Öncelikle herkese merhaba.
Herşeyin başı merak dedim ve hiç lazım olmadığı halde WPF içerisinde CustomControl yazma işine merak sardım. Bu merak sonucundaki ilk çıktıyı da paylaşmak istedim. İlk denemem sadece sayıların girilebileceği bir DigitTextBox olacak.
Bunun için yaratacağımız sınıfı "Control" sınıfından türetiyoruz. Ayrıca bu kontrolümüzü dizayn edebilmek için "Themes" klasörünün altına "Generic.xaml" dosyasını oluşturup dizayn işlemine başlıyoruz.
Yazacağımız digittextbox için bir adet textbox, iki adet de butona ihtiyacımız var. Bunları görmek istediğimiz şekilde "Generic.xaml" dosyasında tanımlıyoruz.
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DebugControls.DebugDigitTextbox">
<Style TargetType="{x:Type local:DebugDigitTextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:DebugDigitTextBox}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBox x:Name="TemplateTextbox" Grid.Column="0"></TextBox>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Button x:Name="IncrementButton" Grid.Row="0"
Margin="1,1,1,1">
<TextBlock
Text="p"
FontFamily="Wingdings 3"
FontSize="6"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Button>
<Button x:Name="DecrementButton" Grid.Row="1"
Margin="1,1,1,1">
<TextBlock
Text="q"
FontFamily="Wingdings 3"
FontSize="6"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Button>
</Grid>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Daha sonra ilk yapacağımız işlerdne biri Template Apply olduğu anda kontrolümüzdeki textbox ve butonları alıp, gerekli eventleri yakalamak.
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
if (_IncrementButton != null)
{
_IncrementButton.Click -= _IncrementButtonClick;
}
if (_DecrementButton != null)
{
_DecrementButton.Click -= _DecrementButtonClick;
}
if (_TextBox != null)
{
_TextBox.PreviewTextInput -= _TextBoxKeyDown;
_TextBox.TextChanged -= _TextBoxTextChanged;
_TextBox.PreviewKeyDown -= _TextBoxPreviewKeyDown;
}
_TextBox = GetTemplateChild(TextboxName) as TextBox;
_IncrementButton = GetTemplateChild(IncrementButtonName) as Button;
_DecrementButton = GetTemplateChild(DecrementButtonName) as Button;
_IncrementButton.Click += _IncrementButtonClick;
_DecrementButton.Click += _DecrementButtonClick;
_TextBox.PreviewTextInput += _TextBoxKeyDown;
_TextBox.TextChanged += _TextBoxTextChanged;
_TextBox.PreviewKeyDown += _TextBoxPreviewKeyDown;
}
Diğer önemli bir nokta ise kontrolün static constructor ında base sınıftan gelen "DefaultKeyStyle" ı override etmek.
static DebugDigitTextBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(DebugDigitTextBox), new FrameworkPropertyMetadata(typeof(DebugDigitTextBox)));
}
Geriye kalan ise eventleri yakalayıp, gerekli işlemleri yapabilmek...
public class DebugDigitTextBox : Control
{
#region Events
public event RoutedPropertyChangedEventHandler<TimeSpan> ValueChanged
{
add { base.AddHandler(ValueChangedEvent, value); }
remove { base.RemoveHandler(ValueChangedEvent, value); }
}
public static readonly RoutedEvent ValueChangedEvent =
EventManager.RegisterRoutedEvent(
"ValueChanged",
RoutingStrategy.Bubble,
typeof(RoutedPropertyChangedEventHandler<int>),
typeof(DebugDigitTextBox));
#endregion
#region Members
TextBox _TextBox;
Button _IncrementButton;
Button _DecrementButton;
const string TextboxName = "TemplateTextbox";
const string IncrementButtonName = "IncrementButton";
const string DecrementButtonName = "DecrementButton";
#endregion
#region DependencyProperties
public static DependencyProperty ValueProperty = DependencyProperty.Register(
"Value", typeof(int), typeof(DebugDigitTextBox), new PropertyMetadata(0, DebugDigitTextBox.OnValueChanged, null));
#endregion
#region Properties
public int Value
{
get { return Convert.ToInt32(GetValue(ValueProperty)); }
set
{
if (Convert.ToInt32(GetValue(ValueProperty)) == value)
return;
SetValue(ValueProperty, value);
}
}
#endregion
#region Initialization
static DebugDigitTextBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(DebugDigitTextBox), new FrameworkPropertyMetadata(typeof(DebugDigitTextBox)));
}
public DebugDigitTextBox()
{
Value = 0;
Width = 100;
}
#endregion
#region Methods
private static void OnValueChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
DebugDigitTextBox textBox = obj as DebugDigitTextBox;
if (textBox != null)
{
textBox.OnValueChanged((int)e.OldValue, (int)e.NewValue);
}
}
void _IncrementButtonClick(object sender, RoutedEventArgs e)
{
Value++;
}
void _DecrementButtonClick(object sender, RoutedEventArgs e)
{
Value--;
}
void _TextBoxKeyDown(object sender, TextCompositionEventArgs e)
{
if (e.Text.Length == 1)
{
if (e.Text[0] == '-')
{
Value = Value * -1;
e.Handled = true;
return;
}
else if (!char.IsDigit(e.Text[0]))
{
e.Handled = true;
return;
}
}
}
void _TextBoxTextChanged(object sender, TextChangedEventArgs e)
{
if (string.IsNullOrEmpty(_TextBox.Text))
{
Value = 0;
}
else if (_TextBox.Text == "-")
{
Value = 0;
}
else
{
try
{
Value = Convert.ToInt32(_TextBox.Text);
}
catch
{
_TextBox.Text = _TextBox.Text.Remove(_TextBox.SelectionStart - 1, 1);
e.Handled = true;
return;
}
}
if (Value == 0)
{
_TextBox.Text = Value.ToString();
}
}
void _TextBoxPreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Down)
{
Value = Value - 1;
}
else if (e.Key == Key.Up)
{
Value = Value + 1;
}
}
protected virtual void OnValueChanged(int oldValue, int newValue)
{
_TextBox.Text = Value.ToString();
RoutedPropertyChangedEventArgs<int> e = new RoutedPropertyChangedEventArgs<int>(oldValue, newValue);
e.RoutedEvent = ValueChangedEvent;
base.RaiseEvent(e);
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
if (_IncrementButton != null)
{
_IncrementButton.Click -= _IncrementButtonClick;
}
if (_DecrementButton != null)
{
_DecrementButton.Click -= _DecrementButtonClick;
}
if (_TextBox != null)
{
_TextBox.PreviewTextInput -= _TextBoxKeyDown;
_TextBox.TextChanged -= _TextBoxTextChanged;
_TextBox.PreviewKeyDown -= _TextBoxPreviewKeyDown;
}
_TextBox = GetTemplateChild(TextboxName) as TextBox;
_IncrementButton = GetTemplateChild(IncrementButtonName) as Button;
_DecrementButton = GetTemplateChild(DecrementButtonName) as Button;
_IncrementButton.Click += _IncrementButtonClick;
_DecrementButton.Click += _DecrementButtonClick;
_TextBox.PreviewTextInput += _TextBoxKeyDown;
_TextBox.TextChanged += _TextBoxTextChanged;
_TextBox.PreviewKeyDown += _TextBoxPreviewKeyDown;
}
#endregion
}
İyi çalışmalar herkeslere...