我在回答 this问题,在这样做的同时我发现了很多奇怪的行为。因为我是 MVVM 的拥护者,所以我整理了一个解决方案以查看我是否会看到相同的行为。我的解决方案发现,即使我将 TwoWay
绑定(bind)到 Slider.Value
,它也不会在 Slider.Maximum
之后在我的 ViewModel 中更新> 和 Slider.Minimum
改变;即我的 View 模型的 Value
可以在 UpperLimit
和 LowerLimit
之外,同时 Slider.Value
(我的 VM 的 Value
属性绑定(bind)到)在范围内。
在上述问题中,更改 Slider.Maximum
或 Slider.Minimum
似乎始终使 Slider.Value
保持在范围内,有时“将”Slider.Value
恢复到以前设置的值。
Microsoft's Slider Source Code
- 为什么
Slider.Value
会更改/恢复其在链接问题中看到的值,即使当前值在最小/最大范围内? - 为什么 我的 View 模型的
Value
属性绑定(bind)到Slider.Value
与TwoWay
不匹配更改UpperLimit
和LowerLimit
后绑定(bind)?- 请注意,Maximum 和 Minimum 的绑定(bind)会起作用
主窗口.xaml:
<DockPanel>
<Slider Name="MySlider" DockPanel.Dock="Top" AutoToolTipPlacement="BottomRight" Value="{Binding Value, Mode=TwoWay}" Maximum="{Binding UpperLimit}" Minimum="{Binding LowerLimit}"/>
<Button Name="MyButton1" Click="MyButton1_Click" DockPanel.Dock="Top" Content="shrink borders"/>
<Button Name="MyButton2" Click="MyButton2_Click" DockPanel.Dock="Top" VerticalAlignment="Top" Content="grow borders"/>
<Button Name="MyButton3" Click="MyButton3_Click" DockPanel.Dock="Top" VerticalAlignment="Top" Content="Print ItemVM Value"/>
</DockPanel>
MainWindow.xaml.cs:
public partial class MainWindow : Window
{
private readonly ItemViewModel item;
public MainWindow()
{
InitializeComponent();
DataContext = item = new ItemViewModel(new Item(1, 20, 0.5));
}
private void MyButton1_Click(object sender, RoutedEventArgs e)
{
//MySlider.Minimum = 1.6;
//MySlider.Maximum = 8;
item.LowerLimit = 1.6;
item.UpperLimit = 8;
}
private void MyButton2_Click(object sender, RoutedEventArgs e)
{
//MySlider.Minimum = 0.5;
//MySlider.Maximum = 20;
item.LowerLimit = 0.5;
item.UpperLimit = 20;
}
private void MyButton3_Click(object sender, RoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("Item Value: " + item.Value);
System.Diagnostics.Debug.WriteLine("Slider Value: " + MySlider.Value);
}
}
项目/项目 View 模型:
public class ItemViewModel : INotifyPropertyChanged
{
private readonly Item _item;
public event PropertyChangedEventHandler PropertyChanged;
public ItemViewModel(Item item)
{
_item = item;
}
public double UpperLimit
{
get
{
return _item.UpperLimit;
}
set
{
_item.UpperLimit = value;
NotifyPropertyChanged();
}
}
public double LowerLimit
{
get
{
return _item.LowerLimit;
}
set
{
_item.LowerLimit = value;
NotifyPropertyChanged();
}
}
public double Value
{
get
{
return _item.Value;
}
set
{
_item.Value = value;
NotifyPropertyChanged();
}
}
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Item
{
private double _value;
private double _upperLimit;
private double _lowerLimit;
public double Value
{
get
{
return _value;
}
set
{
_value = value;
}
}
public double UpperLimit
{
get
{
return _upperLimit;
}
set
{
_upperLimit = value;
}
}
public double LowerLimit
{
get
{
return _lowerLimit;
}
set
{
_lowerLimit = value;
}
}
public Item(double value, double upperLimit, double lowerLimit)
{
_value = value;
_upperLimit = upperLimit;
_lowerLimit = lowerLimit;
}
}
Steps to reproduce:
Click
MyButton3
Item Value = 1
Slider Value = 1
Move Slider/Thumb all the way to right
Click
MyButton3
Item Value = 20
Slider Value = 20
Click
MyButton1
Click
MyButton3
Item Value = 20
Slider Value = 8
如果在MyButton3_Click
中打断点,执行最后一步,可以看到MySlider.Value = 8
最佳答案
这是由于值强制,可以read more about it here .
一般来说,WPF 控件设计用于松散数据绑定(bind)。添加了它们的获取/设置访问器和事件等以协助从 Winforms 进行转换,但它们添加了一个额外的逻辑层,该逻辑层并不总是过滤到您的绑定(bind)属性。这是将“好的”WPF 代码(数据绑定(bind))与“坏的”代码(直接访问控件)混合使用时可能出现的众多问题示例之一。
编辑:
每当需要确定当前值时,都会调用依赖属性的强制回调处理程序。将其视为修改结果的最后机会;它不会改变绑定(bind)本身,只会改变返回值。如果您在包含值 10 的 View 模型(例如)中有一个整数属性,并且您将文本框绑定(bind)到它,如下所示:
<TextBlock Text="{Binding MyValue}" />
这个值显然会显示为 10。现在假设您创建了一个用户控件,它有一个名为“MyProperty”的整数依赖属性,并且假设强制回调将当前值乘以 2:
<local:MyControl x:Name="myControl" MyProperty="{Binding MyValue}" />
这不会做任何事情。我们将 MyProperty 绑定(bind)到 MyValue 属性,但它只是一个 DP。我们从来没有真正调用过它。现在假设我们添加第二个 TextBox 但这次绑定(bind)到 MyControl.MyProperty:
<TextBlock Text="{Binding Path=MyProperty, ElementName=myControl}" />
第一个控件将继续显示 10(该值仍在我们的 View 模型中),但第二个将显示 20,因为对 MyProperty DP 的强制调用修改了它从自己绑定(bind)到 MyValue 中获得的值。 (有趣的是,双向绑定(bind)也有效,强制回调会导致值在更改时翻倍)。
所有这一切的重要线索是,强制回调仅在需要通过另一个依赖更新自身或通过手动调用 getter 的代码来解析值时调用。显然,您在 Slider 上调用 Value getter 会导致这种情况发生,但仅更改 Minimum 和 Maximum 的值不会。这就像在不调用属性更改通知的情况下更改 View 模型中的属性值...您知道自己做了什么,但没有别的。
进一步阅读:the RangeBase source code (特别是 ConstrainToRange
强制回调)和 the Slider source code (即仅在拖动 slider 或缩略图时调用的 UpdateValue)。
关于c# - slider 值在更改最小值和最大值后不更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32060975/