Я пытаюсь создать пользовательский просто Числовой Up Down, используя свойства зависимости для практики.
Но у меня какое-то нежелательное поведение.
Мой код:
XAML:
<Grid Height="22">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<TextBox
x:Name="PART_TextboxEditable"
HorizontalContentAlignment="Right"
VerticalContentAlignment="Center"
Text="{Binding Value, ElementName=parent, Mode=TwoWay}"
IsEnabled="{Binding IsEditable, ElementName=parent}"
PreviewTextInput="TextBox_PreviewTextInput"
FontWeight="Normal">
</TextBox>
</Grid>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<RepeatButton
Click="IncressValueClick"
FontSize="8"
Background="#FFF6F6F6"
BorderThickness="0 1 1 1">
<RepeatButton.Content>
<Path
HorizontalAlignment="Center"
VerticalAlignment="Center"
Fill="Black"
Data="M4,0 L0,4 L8,4 z"/>
</RepeatButton.Content>
</RepeatButton>
<RepeatButton
Click="DecressValueClick"
Grid.Row="1"
FontSize="8"
BorderThickness="0 0 1 1"
Background="#FFF6F6F6">
<RepeatButton.Content>
<Path
HorizontalAlignment="Center"
VerticalAlignment="Center"
Fill="Black"
Data="M0,0 L8,0 L4,4 z"/>
</RepeatButton.Content>
</RepeatButton>
</Grid>
</Grid>
Код сзади:
/// <summary>
/// Interação lógica para IntegerUpDown.xam
/// </summary>
public partial class IntegerUpDown : UserControl
{
public int Value
{
get { return (int)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public int Minimum
{
get { return (int)GetValue(MinimumProperty); }
set { SetValue(MinimumProperty, value); }
}
public int? Maximum
{
get { return (int?)GetValue(MaximumProperty); }
set { SetValue(MaximumProperty, value); }
}
public int Increment
{
get { return (int)GetValue(IncrementProperty); }
set { SetValue(IncrementProperty, value); }
}
public static readonly DependencyProperty IncrementProperty =
DependencyProperty.Register(
"Increment",
typeof(int),
typeof(IntegerUpDown),
new PropertyMetadata(1));
public static readonly DependencyProperty MaximumProperty =
DependencyProperty.Register(
"Maximum",
typeof(int?),
typeof(IntegerUpDown),
new PropertyMetadata(null, new PropertyChangedCallback(MaximumPropertyChangedCallback)));
public static readonly DependencyProperty MinimumProperty =
DependencyProperty.Register(
"Minimum",
typeof(int),
typeof(IntegerUpDown),
new PropertyMetadata(0, new PropertyChangedCallback(MinimumPropertyChangedCallback)));
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(
"Value",
typeof(int),
typeof(IntegerUpDown),
new FrameworkPropertyMetadata(0,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
new PropertyChangedCallback(ValuePropertyChangedCalllback),
new CoerceValueCallback(ValuePropertyCoerceValueCallback)));
public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent(
"ValueChanged",
RoutingStrategy.Bubble,
typeof(RoutedPropertyChangedEventHandler<int>), typeof(IntegerUpDown));
private static void ValuePropertyChangedCalllback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
BindingExpression be = (d as IntegerUpDown).GetBindingExpression(ValueProperty);
if (be != null)
be.UpdateSource();
(d as IntegerUpDown).RaiseEvent(new RoutedPropertyChangedEventArgs<int>((int)e.OldValue, (int)e.NewValue, ValueChangedEvent));
}
private static void MinimumPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs baseValue)
{
var value = (int)baseValue.NewValue;
var obj = d as IntegerUpDown;
obj.SetCurrentValue(ValueProperty, (int)Math.Max(obj.Value, value));
}
private static void MaximumPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs baseValue)
{
var value = (int?)baseValue.NewValue;
var obj = d as IntegerUpDown;
obj.SetCurrentValue(ValueProperty, Math.Min(obj.Value, value ?? obj.Value));
}
private static object ValuePropertyCoerceValueCallback(DependencyObject d, object baseValue)
{
var value = (int)baseValue;
var obj = d as IntegerUpDown;
obj.CoerceValue(MaximumProperty);
obj.CoerceValue(MinimumProperty);
int newValue = Math.Max(obj.Minimum, Math.Min(value, obj.Maximum ?? value));
return newValue;
}
public IntegerUpDown()
{
InitializeComponent();
}
private void IncressValueClick(object sender, RoutedEventArgs e)
{
IncressValue();
}
private void DecressValueClick(object sender, RoutedEventArgs e)
{
DecressValue();
}
private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
var textBox = sender as TextBox;
var fullText = textBox.Text.Insert(textBox.SelectionStart, e.Text);
e.Handled = !int.TryParse(fullText, out _);
}
private void NumericUpDownPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
IntegerUpDown control = (IntegerUpDown)sender;
e.Handled = control.Focus() || e.Handled;
}
private void Parent_MouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Delta > 0)
IncressValue();
else
DecressValue();
}
private void IncressValue()
{
Value += Increment;
}
private void DecressValue()
{
Value -= Increment;
}
private void Parent_PreviewKeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.Up:
IncressValue();
break;
case Key.Down:
DecressValue();
break;
default:
return;
}
}
Это очень простой код, но он не работает, как ожидалось.Я знаю, что делаю что-то не так, но не могу распознать проблему здесь.
Проблема:
Я использую этот XAML для проверки:
<local:IntegerUpDown Value="{Binding Value}"
Maximum="15"
Minimum="10"
Increment="2"></local:IntegerUpDown>
<TextBlock
Foreground="White"
Text="{Binding Value}" Grid.Row="1"></TextBlock>
Как вы можете видеть ниже, я вручную установил значение '15151515' в TextBox
и мой CoerceValue
называется, мой newValue
, возвращенный на CoerceValue
, равен '15', потому что Maximum
значение установлено на 15. Мои textbox
показывают правильное значение (15), но мое значение от ViewModel
имеетневерное значение.
[
Если я нажму UP и мое значение будет 15:
[
У меня всегда будет Maximum
что-токак Maximum
+ Increment
и Minimum
- Increment
.Я имею в виду, когда значение достигает Minimum
, я могу щелкнуть еще раз и иметь Minimum
- Increment
(на примере 8) на ViewModel
, но на TextBox
он показывает MinimumValue
(наПример 10).
Что не так с моим кодом?