2015-08-17 105 views
3

我回答了this问题,并且在执行此操作时发现了很多奇怪的行为。由于我是亲MVVM,我把一个解决方案放在一起,看看我是否会看到相同的行为。我的解决方案揭示的是,尽管我绑定了TwoWaySlider.Value,但在Slider.MaximumSlider.Minimum更改后,它并未在我的ViewModel中更新;即我的视图模型的Value可以在UpperLimitLowerLimit之外,同时Slider.Value(我的VM的Value属性被绑定到)在范围之内。更改后滑块值不会更新最小值和最大值

在上述的问题,改变Slider.MaximumSlider.Minimum似乎始终保持在范围Slider.Value,有时“恢复” Slider.Value将它用于设置为以前的值。

Microsoft's Slider Source Code

  1. 为什么确实Slider.Value变化/作为链接的问题看到即使当前值的最小/最大范围内恢复它的价值呢?
  2. 为什么没有我的视图模型的Value财产,势必Slider.Value与之匹配的TwoWay改变UpperLimitLowerLimit后绑定?
    • 注意,绑定最大&最低工作

MainWindow.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); 
    } 
} 

项目/ ItemViewModel:

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; 
    } 
} 

重现步骤:

  1. 点击MyButton3

    • 项目值= 1

    • 滑块值= 1

  2. 移动滑块/拇指全部向右

  3. 点击MyButton3

    • 项目的方式值= 20

    • 滑块值= 20

  4. 按此MyButton1

  5. 按此MyButton3

    • 项值= 20

    • 滑块值= 8

如果你把MyButton3_Click一个破发点,并执行最后一步,你可以看到,​​

回答

1

这是因为看重胁迫,你可以read more about it here

一般来说,WPF控件的设计与松散的数据绑定一起使用。他们的get/set访问器和事件等被添加来帮助从Winforms转换,但他们添加了一个额外的逻辑层,并不总是通过你的绑定属性过滤。这是将“良好”的WPF代码(数据绑定)与“不良”(直接访问控件)混合时可能出现的许多问题示例之一。

编辑:

为一个依赖属性胁迫回调处理程序被调用时的电流值需要被确定。把它看作是修改结果的最后机会;它不会更改绑定本身,只会返回正在返回的值。如果您有包含值10视图模型(说)整数属性,并可以在文本框绑定到它是这样的:

<TextBlock Text="{Binding MyValue}" /> 

该值将明显显示为10.现在让我们假设你创建一个用户与所谓的“myProperty的”整数依赖属性控制,让我们说,强迫回调乘无论电流值是2:

<local:MyControl x:Name="myControl" MyProperty="{Binding MyValue}" /> 

这将做两手空空。我们将MyProperty绑定到MyValue属性,但它只是一个DP。我们从来没有真正调用它。现在,让我们说,我们第二个文本框,但这次绑定添加到MyControl.MyProperty:

<TextBlock Text="{Binding Path=MyProperty, ElementName=myControl}" /> 

的第一控制将继续显示10(这是价值仍然在我们的视图模型),但第二个将显示20,因为MyProperty DP的强制调用修改了它自己绑定到MyValue的值。 (有趣的是,执行双向绑定也可以,强制回调会导致值在每次更改时都会加倍)。

所有这一切的重要线索是,只有当值需要通过另一个依赖项更新自身或手动调用getter来解决时,才会调用强制回调。很显然,你在Slider上调用Value getter会导致这种情况发生,但只是改变Minimum和Maximum的值不会。这就像在您的视图模型中更改属性的值而无需调用属性更改通知......您知道自己做了什么但没有其他事情。

进一步阅读:the RangeBase source code(特别是ConstrainToRange胁迫回调)和the Slider source code(即UpdateValue当滑块或缩略图拖到其仅调用)。

+0

我能够将它分解为大部分,但我无法确定故障的位置。它是否显而易见,如何改变代码隐藏和绑定中的值的行为有所不同;这不是我。我也质疑这个事实,如果强迫泡沫或隧道下来。当我试图找出SelectionStart/End是否在值和Max/Min之前被强制执行时,我的思维过程转向了意大利面条,当时我无法逐步浏览代码。我将不得不阅读胁迫。如果你对如何理解逻辑或发生的事情有了更多的了解,那么我就是耳朵。谢谢! – Kcvin

+0

相应编辑。 :) –

+0

@MarkFeldman我已经查看了WPF源代码,并将Minimum设置为明确调用最大值和最大值的强制回调。我是否理解你的帖子? –

相关问题