2014-06-23 35 views
1

我做了一个小项目来了解一下MVVM。这是一个计算器,可以计算何时可以下班回家。PropertyChangedEventHandler都是null时间,但绑定只能工作一次,为什么?

我做了一个UserControl与两个文本框和一个简单的标签“TimePicker”。这个Usercontrol有一个ViewModel(主窗口甚至有一个),它管理一个Timepicker的时间。它有三个属性:一个称为TimeValue的int,它只是小时和分钟的值,并且两个整数称为HoursMinutes。我的两个文本框绑定到它们并显示它们。通过文本框设置一个值也重置时间,设置时间(通过属性)重置小时和分钟,两个文本框在设置此值后更新。

这个作品退出罚款。现在我想添加名为ReadOnly的第二个属性。 TimePicker需要ReadOnly来显示时间。这是没有意义的手动设置这个时间,所以我想有可能设置两个文本框IsReadOnly属性。

ReadOnly现在是UserControl的第二个属性。因为我很懒,所以我想通过UserControl直接绑定属性和两个文本框,并且只将IsReadOnly -Property绑定到UserControl。

这是我的想法的代码(用户控件):

public partial class TimeBox : UserControl, INotifyPropertyChanged 
{ 
    private SingleTimeViewModel viewModel; 

    //... other Properties 

    public static DependencyProperty ReadOnlyProperty = DependencyProperty.Register("ReadOnly", typeof(Boolean), typeof(TimeBox), new PropertyMetadata(false)); 

    // Schnittstellen-Ereignis 
    public event PropertyChangedEventHandler PropertyChanged; 
    protected internal void OnPropertyChanged(string propertyname) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyname)); 
    } 

    public TimeBox() 
    { 
     InitializeComponent(); 
     viewModel = new SingleTimeViewModel(SingleTime.CreateSingleTime()); 
     this.DataContext = viewModel; 
    } 

    //... Code of other Properties 

    private bool _ReadOnly; 
    public bool ReadOnly 
    { 
     get 
     { 
      return _ReadOnly; 
     } 
     set 
     { 
      if (_ReadOnly == value) 
       return; 
      _ReadOnly = value; 
      OnPropertyChanged("ReadOnly"); 
     } 
    } 

    //... Other Methods 
} 

这是通过XAML绑定到两个文本框(绑定Text导致视图模型,IsReadOnly应绑定到时间盒):

<UserControl x:Name="TimeBoxControl" x:Class="TimeCalculator.TimeBox" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     ... > 
    <WrapPanel Grid.Column="7" HorizontalAlignment="Stretch" Margin="0,0,0,0" Grid.Row="1" VerticalAlignment="Center" > 
     <TextBox x:Name="txtBxHours" ... Text="{Binding Hours}" ... IsReadOnly="{Binding ReadOnly, ElementName=TimeBoxControl}" /> 
     <Label x:Name="lblSeparator" ... /> 
     <TextBox x:Name="txtBxMinutes" ... Text="{Binding Minutes}" ... IsReadOnly="{Binding ReadOnly, ElementName=TimeBoxControl}" /> 
    </WrapPanel> 
</UserControl> 

我在InitializeComponent之后在我的项目的主窗口的构造函数中只读取了这些值。所以我用下面几行:

this.TmBxMayGo.ReadOnly = true; 
this.TmBxMustGo.ReadOnly = true; 
this.TmBxTimeUntilMayGo.ReadOnly = true; 
this.TmBxTimeUntilMustGo.ReadOnly = true; 
this.TmBxCurrentOvertime.ReadOnly = true; 

这不起作用,一些调试后我发现它并没有因为PropertyChangedEventHandler PropertyChanged总是null。 我搜索了很多以找到解决这个问题的方法,但是我没有做出任何常见的错误(例如忘记: INotifyPropertyChanged,在字符串中的错误名称或其他)。

我终于放弃了,并通过ViewModel。但后来我意识到,PropertyChangedEventHandler PropertyChanged也是null当我通过ViewModel设置,但文本框是ReadOnly后调用。

现在这两个问题,我有:

  1. 是否有意义作出自己的视图模型为单用户控件?
  2. 这是为什么呢? PropertyChangednull两次,但只能工作一次?
+0

我想知道为什么你需要INotifyPropertyChanged派生自UserControl的类。您可以充分利用依赖属性来获得更好的控制和灵活性。 – pushpraj

+0

在分配_ReadOnly之前,请选中“if(_Enabled == value)”。是通过设计还是你必须检查“if(_ReadOnly == value)”? :) –

+2

删除所有。你不应该在'DependencyObject'中实现'INotifyPropertyChanged'。这个想法是通过将所有的属性放在一个单独的,名为“ViewModel”的POCO类中来实际“分离”UI和行为。 –

回答

0
  1. 是的,是有意义的有单并且standlone逻辑分隔UI单一视图模型。它将主视图模型的责任分开。所以把你的所有属性放在ViewModel中。

  2. 当该对象设置为视图的DataContext时,WPF仅将处理程序附加到INotifyPropertyChanged对象的PropertyChanged事件,这就是为什么您的PropertyChanged在设置用户控件的DataContext之前为null的原因。而且你的文本框仍然是禁用的,因为在初始化绑定的时候,这些属性的getter被调用,并且用你给出的默认值更新UI。

+0

但我第一次使用InitializeComponent(),然后在两种情况下设置属性.. – Strohi

0

做提到一个更简洁的方法是这样的

public bool ReadOnly 
    { 
     get { return (bool)GetValue(ReadOnlyProperty); } 
     set { SetValue(ReadOnlyProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for ReadOnly. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty ReadOnlyProperty = 
     DependencyProperty.Register("ReadOnly", typeof(bool), typeof(TimeBox), new PropertyMetadata(false, null, CoerceReadOnly)); 

    private static object CoerceReadOnly(DependencyObject d, object baseValue) 
    { 
     if ((d as TimeBox)._Enabled == baseValue) 
      return DependencyProperty.UnsetValue; 
     return baseValue; 
    } 

这里我使用强制值回调来检查条件,所以通过返回DependencyProperty.UnsetValue否则将取消属性更改它会继续

更多信息强迫上这里 http://msdn.microsoft.com/en-us/library/ms745795(v=vs.110).aspx#Advanced

其他问题,我会说你可能不需要创建一个用户控件,除非你想部署一个控制库。请尽量利用相同的数据模板。

其次,因为您绑定到一个工作在依赖框架上的用户控件,常规通知可能无法按预期工作。

相关问题