How to use different Data Types in a Custom Control
Mesh Ka
345
Reputation points
I have a Custom NumericUpDown control in my WPF C# .NET 8 application that is working nicely, But now i want to update it so that it can use different Numbers DataTypes like int and decimal so that i can re-use my custom NumericUpDown control instead of creating two different custom Controls just because of DataTypes.
I am really confused how to do that, Help.
Here is the Generic.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:local="clr-namespace:NumericUpDownControl">
<Style TargetType="{x:Type local:NumericUpDown}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:NumericUpDown}">
<Grid FlowDirection="LeftToRight" HorizontalAlignment="Stretch" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox x:Name="NUDTextBox"
Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Value}"
materialDesign:HintAssist.Hint="Height"
materialDesign:HintAssist.FontFamily="Century Gothic"
materialDesign:HintAssist.IsFloating="False"
Margin="0 -5 10 0"
FontSize="20"
Grid.Column="0"
HorizontalContentAlignment="Right"/>
<StackPanel Grid.Column="1" Orientation="Vertical">
<RepeatButton x:Name="NUDButtonUP"
Background="Transparent"
BorderThickness="0"
Height="15"
Width="15"
VerticalAlignment="Top">
<RepeatButton.Template>
<ControlTemplate TargetType="RepeatButton">
<materialDesign:PackIcon Kind="Triangle"
Height="10"
Width="10"
Margin="0,3,0,0"
Foreground="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Foreground}"/>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Blue" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Foreground" Value="Red" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Gray" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</RepeatButton.Template>
<RepeatButton.Style>
<Style TargetType="RepeatButton">
<Setter Property="Foreground" Value="Lime" />
</Style>
</RepeatButton.Style>
</RepeatButton>
<RepeatButton x:Name="NUDButtonDown"
Background="Transparent"
BorderThickness="0"
Height="15"
Width="15"
VerticalAlignment="Top">
<RepeatButton.Template>
<ControlTemplate TargetType="RepeatButton">
<materialDesign:PackIcon Kind="TriangleDown"
Height="10"
Width="10"
Margin="0,0,0,0"
Foreground="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Foreground}" />
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Blue" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Foreground" Value="Red" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Gray" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</RepeatButton.Template>
<RepeatButton.Style>
<Style TargetType="RepeatButton">
<Setter Property="Foreground" Value="Lime" />
</Style>
</RepeatButton.Style>
</RepeatButton>
</StackPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
And Here is the NumericUpDown.cs:
using System;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
namespace NumericUpDownControl
{
public class NumericUpDown : Control
{
private TextBox NUDTextBox;
private RepeatButton NUDButtonUP;
private RepeatButton NUDButtonDown;
static NumericUpDown()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(NumericUpDown), new FrameworkPropertyMetadata(typeof(NumericUpDown)));
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(double), typeof(NumericUpDown), new FrameworkPropertyMetadata(1.0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public double Value
{
get { return (double)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
NUDTextBox = GetTemplateChild("NUDTextBox") as TextBox;
NUDButtonUP = GetTemplateChild("NUDButtonUP") as RepeatButton;
NUDButtonDown = GetTemplateChild("NUDButtonDown") as RepeatButton;
if (NUDTextBox != null)
{
NUDTextBox.PreviewKeyDown += NUDTextBox_PreviewKeyDown;
NUDTextBox.PreviewKeyUp += NUDTextBox_PreviewKeyUp;
NUDTextBox.TextChanged += NUDTextBox_TextChanged;
}
if (NUDButtonUP != null)
{
NUDButtonUP.Click += NUDButtonUP_Click;
}
if (NUDButtonDown != null)
{
NUDButtonDown.Click += NUDButtonDown_Click;
}
}
private void NUDButtonUP_Click(object sender, RoutedEventArgs e)
{
double number;
if (NUDTextBox.Text != "") number = Convert.ToDouble(NUDTextBox.Text);
else number = 0;
if (number < MaxValue)
NUDTextBox.Text = Convert.ToString(number + IncrementValue);
else
NUDButtonUP.IsEnabled = false;
ValidateValue();
}
private void NUDButtonDown_Click(object sender, RoutedEventArgs e)
{
double number;
if (NUDTextBox.Text != "") number = Convert.ToDouble(NUDTextBox.Text);
else number = 0;
if (number > MinValue)
NUDTextBox.Text = Convert.ToString(number - IncrementValue);
else
NUDButtonUP.IsEnabled = false;
ValidateValue();
}
private void NUDTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Up)
{
NUDButtonUP.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(NUDButtonUP, new object[] { true });
}
if (e.Key == Key.Down)
{
NUDButtonDown.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(NUDButtonDown, new object[] { true });
}
}
private void NUDTextBox_PreviewKeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Up)
typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(NUDButtonUP, new object[] { false });
if (e.Key == Key.Down)
typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(NUDButtonDown, new object[] { false });
}
private void NUDTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
ValidateValue();
NUDTextBox.SelectionStart = NUDTextBox.Text.Length;
}
private void ValidateValue()
{
double number = 0;
if (NUDTextBox.Text != "")
if (!double.TryParse(NUDTextBox.Text, out number)) NUDTextBox.Text = MinValue.ToString();
if (number >= MaxValue)
{
NUDTextBox.Text = MaxValue.ToString();
NUDButtonUP.IsEnabled = false; // disable UP button
}
else
{
NUDButtonUP.IsEnabled = true; // enable UP button
}
if (number <= MinValue)
{
NUDTextBox.Text = MinValue.ToString();
NUDButtonDown.IsEnabled = false; // disable DOWN button
}
else
{
NUDButtonDown.IsEnabled = true; // enable DOWN button
}
}
public double MinValue { get; set; } = 1.0;
public double MaxValue { get; set; } = 3.0;
public double IncrementValue { get; set; } = 0.1;
}
}
and this is an example of how i wanted to use it:
<Window x:Class="NumericUpDownControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:NumericUpDownControl"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<StackPanel>
<local:NumericUpDown
Value="1.3"
MinValue="1.0"
MaxValue="3.0"
IncrementValue="0.1"
/>
<local:NumericUpDown
Value="2"
MinValue="1"
MaxValue="10"
IncrementValue="1"
/>
</StackPanel>
</Grid>
</Window>
Sign in to answer