2014-06-23 32 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

其他問題,我會說你可能不需要創建一個用戶控件,除非你想部署一個控制庫。請儘量利用相同的數據模板。

其次,因爲您綁定到一個工作在依賴框架上的用戶控件,常規通知可能無法按預期工作。

相關問題