Uzun bir aradan sonra tekrar merhaba,
Bu makalemiz, başlıktan da anlaşılacağı üzere, WPF'te bir TextBox kontrolünün içindeki yazının tamamının nasıl seçileceği üzerine.
Uzun zamandır WPF ile uğraşanların muhtemelen karşılaştıkları bir problemdir bu. WPF içinde, dahili olarak, TextBox için otomatik metin seçimi mevcut değil. Bunun için birkaç yol kullanmak mümkün.
Bunlardan biri, her TextBox kontrolüne SelectionStart ve SelectionLength değeri vermek şeklinde gerçekleştirilebilir:
<TextBox SelectionStart="0" SelectionLength="1000" />
Burada SelectionLength için verilen değer, toplam karakter sayısından büyük olabilir. Bu, herhangi bir problem oluşturmayacaktır. Ancak bu kullanım şeklinde, SelectionStart ve SelectionLength ifadelerini, her TextBox kontrolü için tek tek yazmamız gereklidir. Bu ise toplu olarak kontrolü oldukça zorlaştıran bir yol olacaktır.
Toplu olarak bu işlemi yapmak için, property'leri Style içinde oluşturmak daha doğru bir yol olmakla beraber, SelectionStart ve SelectionLength property'lerinin her ikisi de DependencyObject türünde olmadıkları için, Style içinde yazılamazlar.
Bu sebeplerle, bu usûlde kullanım pek doğru bir tercih olmayacaktır.
Diğer bir kullanım şekli olarak, App.xaml.cs içinde EventManager.RegisterClassHandler methodunu kullanarak RoutedEvent'leri yakalama yolu tercih edilebilir. Ancak bu da her projede bu kodu tek tek yapıştırmayı gerektireceği için pek kullanışlı bir yol olarak görünmüyor. Yine de nasıl olacağına bakmak isterseniz şu adreslerden faydalanabilirsiniz:
https://www.intertech.com/Blog/how-to-select-all-text-in-a-wpf-textbox-on-focus/
http://stackoverflow.com/a/2553297/2374053
http://madprops.org/blog/wpf-textbox-selectall-on-focus/
Diğer bir yol da AttachedProperty kullanmaktır ki, bu makalede göstermek istediğim de buydu zaten.
Evvela, temel olarak aldığım kodları sizlere sunmalıyım:
http://stackoverflow.com/a/2674291/2374053
Karşınıza çıkan kodlar, tatbik edildiği her TextBox kontrolünde gerçekleşen her bir focus event'inde, TextBox içindeki bütün yazıyı tamamen seçecektir. Bu ise kısmen iş görmekle beraber, yine de eksik kalmaktadır.
İşte bu kısımda kendi kodlarımı geliştirme ihtiyacı hissettim ve size de bunu sunuyorum.
Buradaki mantık, üsttekinden farklı olarak, dört ayrı senaryo üzerine kurulu. Bunlar:
- Yazıyı sadece ilk focus event'i gerçekleştiğinde tamamen seçmek ve daha sonraki focus işlemlerinde, yazının son seçilen kısmını aynen bırakmak
- Yazıyı sadece ilk focus event'i gerçekleştiğinde tamamen seçmek ve sonrakilerde asla seçmemek,
- Yazıyı her focus event'i gerçekleştiğinde tamamen seçmek,
- Yazıyı her focus event'i gerçekleştiğinde hiç seçmemek (var olan seçimi kaldırmak)
şeklinde ifade edilebilir.
Şimdi dilerseniz kodlara bir göz gezdirin.
namespace WPF.AttachedProperties
{
public enum SelectAllMode
{
/// /// On first focus, it selects all then leave off textbox and doesn't check again
/// OnFirstFocusThenLeaveOff = 0,
/// /// On first focus, it selects all then never selects
/// OnFirstFocusThenNever = 1,
/// /// Selects all on every focus
/// OnEveryFocus = 2,
/// /// Never selects text (WPF's default attitude)
/// Never = 4
}
public partial class TextBox : DependencyObject
{
public static readonly DependencyProperty SelectAllModeProperty = DependencyProperty.RegisterAttached(
"SelectAllMode",
typeof(SelectAllMode?),
typeof(TextBox),
new PropertyMetadata(SelectAllModePropertyChanged));
private static void SelectAllModePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is System.Windows.Controls.TextBox)
{
var textBox = d as System.Windows.Controls.TextBox;
if (e.NewValue != null)
{
textBox.GotKeyboardFocus += OnKeyboardFocusSelectText;
textBox.PreviewMouseLeftButtonDown += OnMouseLeftButtonDown;
}
else
{
textBox.GotKeyboardFocus -= OnKeyboardFocusSelectText;
textBox.PreviewMouseLeftButtonDown -= OnMouseLeftButtonDown;
}
}
}
private static void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var dependencyObject = GetParentFromVisualTree(e.OriginalSource);
if (dependencyObject == null)
return;
var textBox = (System.Windows.Controls.TextBox) dependencyObject;
if (!textBox.IsKeyboardFocusWithin)
{
textBox.Focus();
e.Handled = true;
}
}
private static DependencyObject GetParentFromVisualTree(object source)
{
DependencyObject parent = source as UIElement;
while (parent != null && !(parent is System.Windows.Controls.TextBox))
{
parent = VisualTreeHelper.GetParent(parent);
}
return parent;
}
private static void OnKeyboardFocusSelectText(object sender, KeyboardFocusChangedEventArgs e)
{
var textBox = e.OriginalSource as System.Windows.Controls.TextBox;
if (textBox == null) return;
var selectAllMode = GetSelectAllMode(textBox);
if (selectAllMode == SelectAllMode.Never)
{
textBox.SelectionStart = 0;
textBox.SelectionLength = 0;
}
else
textBox.SelectAll();
if (selectAllMode == SelectAllMode.OnFirstFocusThenNever)
SetSelectAllMode(textBox, SelectAllMode.Never);
else if (selectAllMode == SelectAllMode.OnFirstFocusThenLeaveOff)
SetSelectAllMode(textBox, null);
}
[AttachedPropertyBrowsableForChildren(IncludeDescendants = false)]
[AttachedPropertyBrowsableForType(typeof(System.Windows.Controls.TextBox))]
public static SelectAllMode? GetSelectAllMode(DependencyObject @object)
{
return (SelectAllMode) @object.GetValue(SelectAllModeProperty);
}
public static void SetSelectAllMode(DependencyObject @object, SelectAllMode? value)
{
@object.SetValue(SelectAllModeProperty, value);
}
}
}
Oluşturduğumuz bu attachedproperty'yi kullanmak için yapmanız gereken, şöyle bir kod yazmaktan ibarettir.
<!-- İlk focus event'inde bütün yazıyı seçer ve sonrasında yazının son seçilen kısmını aynen bırakır -->
<TextBox attprop:TextBox.SelectAllMode="OnFirstFocusThenLeaveOff" />
<!-- İlk focus event'inde bütün yazıyı seçer ve sonrakilerde asla seçili olmamasını sağlar -->
<TextBox attprop:TextBox.SelectAllMode="OnFirstFocusThenNever" />
<!-- Her focus event'i çalıştığında yazının tamamını seçer -->
<TextBox attprop:TextBox.SelectAllMode="OnEveryFocus" />
<!-- Her focus event'i çalıştığında yazının seçili olmamasını sağlar ve cursor'ü satırın başına alır -->
<TextBox attprop:TextBox.SelectAllMode="Never" />
Böyle bir kullanım ise, daha evvel bahsettiğim gibi, toplu olarak değişiklik yapmayı zor hâle getirir. Bunun için tercih edilebilecek bir yol ise Style kullanımıdır:
<Style TargetType="{x:Type TextBox}">
<Setter Property="attprop:TextBox.SelectAllMode" Value="OnFirstFocusThenLeaveOff" />
</Style>
İsterseniz, bu style'a Key değeri vererek sadece belirli yerlerde kullanmayı tercih edebilirsiniz. Ancak buradaki gibi kullanırsanız, yazdığınız style kodu bütün TextBox'lara tatbik edilecektir.
Buradakiler haricinde başka kullanım şekilleri de elbette mevcuttur. Biraz araştırma yaparak ortaya birşeyler çıkarmak mümkün.
Ayrıca, aynı sayfada diğer kullanıcılara ait diğer kullanım şekillerine de göz atabilir ve daha farklı yollar geliştirebilirsiniz.
...
WPF hakkındaki ilk yazım olan bu makale de buraya kadar. Yakın zamanda yeni makaleler sunabilmek dileğiyle, hoşçakalın...