INotifyPropertyChanged绑定没有像预期的那样更新

问题描述:

所以这里是我打我的头的问题:我有一个自定义的用户控件,显示了绑定到我的ViewModel的两个依赖项属性。在我的ViewModel中,我有一个类的实例,它拥有多个属性,这些属性表示与用户控件相关的值以及控制操作的项目。这里有一些示例代码可以直观地解释它,所以这里是我的控件的一个简单示例,它是一个Slider,它与一个允许用户锁定滑块的复选框组合在一起。INotifyPropertyChanged绑定没有像预期的那样更新

<custom:SliderControl IsLocked="{Binding Path=CustomClass.IsLocked, Mode=TwoWay}" SliderValue="{Binding Path=CustomClass.Value, Mode=TwoWay}" /> 

IsLocked和SliderValue是有效操作中包含的定制控制的复选框和滑块依赖属性。除了与我定义的类绑定之外,所有控制函数都按预期工作。如果我创建单个属性,如在一个int属性和一个布尔属性中,绑定按预期工作。不过,我有五个滑块,我的实际代码中的每个滑块都有五个与它们配合的属性。我试图通过创建一个类来将这些属性保留在可重用对象中,从而将我的25个属性缩小为5个类实例,从而消除代码重复。

我的CustomClass继承ObservableObject并分别具有一个名为IsLocked和SliderValue的bool属性和int属性。因为在这里更直观教具是什么样子:

public class CustomClass : ObservableObject 
    { 
     public const string SliderValuePropertyName = "SliderValue"; 
     private int _sliderValue= 0; 
     public int SliderValue 
     { 
      get 
      { 
       return _sliderValue; 
      } 

      set 
      { 
       if (_sliderValue== value) 
       { 
        return; 
       } 


       _sliderValue= value; 
       RaisePropertyChanged(SliderValuePropertyName); 
      } 
     } 

    public const string IsCheckedPropertyName = "IsChecked"; 
    private bool _isChecked = false; 
    public bool IsChecked 
    { 
     get 
     { 
      return _isChecked; 
     } 

     set 
     { 
      if (_isChecked == value) 
      { 
       return; 
      } 
      _isChecked = value; 
      RaisePropertyChanged(IsCheckedPropertyName); 
     } 
    } 

视图模型属性很相似,看起来像这样,在创建类的实例的时候视图模型加载:

public const string SliderOnePropertyName = "SliderOne"; 
    private CustomClass _sliderOne; 
    public CustomClass SliderOne 
    { 
     get 
     { 
      return _sliderOne; 
     } 

     set 
     { 
      if (_sliderOne== value) 
      { 
       return; 
      } 

      _sliderOne= value; 
      RaisePropertyChanged(SliderOnePropertyName); 
     } 
    } 

为什么不会更新绑定到类中的属性的依赖项属性是否正确更新?是因为你无法自己正确地更新类实例属性,而是必须在发生更改时更新整个类实例?还是我需要进一步在这个ViewModel属性中自定义setter?因为它现在正在改变滑块值或复选框,所以在调试时绝不会碰到绑定属性,也不会出错。

编辑:我也包围了边界的控件,并将边界UIElement的DataContext设置为该类的,然后应用更简单的路径绑定到基础的自定义控件。但是这对我的问题没有任何影响。

我是一位本土编程的程序员,所以在将代码放在一起时,我经常会错过这些事情,我猜这就是这种情况,除非我所尝试的不会工作。

任何帮助将不胜感激。

编辑:所以我一直在使用自定义事件,会让我知道什么时候自定义控件的具体属性发生变化,然后让我的ViewModel中更新现有类的事件。这可以工作,但仍然会产生代码复制,因为现在我必须有10个事件,每个控件2个事件,一个用于检查滑块的值何时更改,另一个用于检测复选框IsChecked值是否更改。此代码重复存在,因为您无法路由多个命令参数(如正在操作滑块的简单字符串标识符以及要在代码中使用的值)。这种限制意味着我不能仅仅使用2个事件来区分哪个控件在定义的方法中正在发生变化,因为将物理控件暴露给ViewModel会破坏MVVM模式。使用一个类作为用户控件的数据上下文使它成为我不关心哪个控件被操作,因为它们都有自己的类实例。使用事件这个解开MVVM模式,因为现在我需要知道用户操纵五个控件中的哪一个。

在属性绑定中使用类不是很难。我不得不错过一些补救措施。

+0

您是否检查过输出窗口的绑定错误? – s1mm0t

+0

是的,在输出窗口中根本没有错误,调试完全没有返回任何问题。我相信这在XAML中使用绑定时很常见,如果绑定无效,它从不报告问题,如果属性可以使用默认值进行初始化。 – Paolis

+0

视图的'DataContext'设置为? – ChrisF

这里是一个完整的例子:

public partial class MainPage : UserControl 
{ 
    public MainPage() 
    { 
     InitializeComponent(); 
     this.DataContext = new ViewModel(); 
    } 
} 


public class ViewModel 
{ 
    public SliderValues slv { get; private set; } 

    public ViewModel() 
    { 
     slv = new SliderValues(); 
    } 
} 

public class SliderValues : INotifyPropertyChanged 
{ 
    bool _isLocked = false; 

    public bool IsLocked 
    { 
     get { return _isLocked; } 
     set 
     { 
      _isLocked = value; 
      OnPropertyChanged("IsLocked"); 
     } 

    } 
    int _theValue = 5; 

    public int TheValue 
    { 
     get { return _theValue; } 
     set 
     { 
      _theValue = value; 
      OnPropertyChanged("TheValue"); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    private void OnPropertyChanged(string prop) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(prop)); 

    } 
} 

现在XAML:

<UserControl x:Class="TestBindings.MainPage" 
    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" 
    mc:Ignorable="d" 
    d:DesignHeight="300" d:DesignWidth="400"> 

    <Grid x:Name="LayoutRoot" Background="White"> 
     <Slider Height="23" HorizontalAlignment="Left" Margin="114,138,0,0" Name="slider1" VerticalAlignment="Top" Width="100" 
       DataContext="{Binding slv}" Value="{Binding TheValue, Mode=TwoWay}"/> 
    </Grid> 
</UserControl> 
+0

这正是我现在所处的位置。我为自己创建的问题是,我在一个单独的文件中定义了类,并且认为我需要为在ViewModel中引发INotifyPropertyChanged的类实例创建一个属性,这使得一切都在类代码中发生,并且忽略我创建的财产。这使得很难执行依赖于知道类属性何时更改的方法。我正在通过使用MVVM Light消息解决此问题。感谢您的代码示例! – Paolis

+0

当任何一个单独的滑块控件被操作时,我都有方法执行的原因是它们之间存在相互依赖关系,并且都与共享最大设置有关,如果达到此最大设置,则会开始从具有最高值的滑块控件中滤除。这创造了一种情况,我需要操纵所有的控件,然后检查所有其他控件,并在最大值被违反时创建奇偶校验。 – Paolis

可能只是一个语法错误。试试这个

{绑定路径= CustomClass.IsLocked,模式=双向}

+0

看起来像它可能是 –

+0

对不起,我输入的例子确实有多个拼写错误,但实际的代码没有。我现在修复了它们。 – Paolis

试试这个... <custom:SliderControl DataContext="{Binding CustomClass}" IsLocked="{Binding IsLocked, Mode=TwoWay}" SliderValue="{Binding Value, Mode=TwoWay}" />