[英]How do I correctly implement INotifyPropertyChanged for my bool property and bind to CheckBox.IsChecked?
新手在這里。 我一直在嘗試圍繞數據綁定,並希望嘗試將視圖中的復選框雙向綁定到我稱為“狀態”的單獨類中的布爾值。 關鍵是要確保它們始終保持同步。
所以我在視圖中創建了一個復選框,並將其綁定到State-class中前面提到的布爾屬性,並伴有一個按鈕,該按鈕繞過復選框並直接切換布爾屬性(恰當地標記為'Ninja!')。 關鍵在於測試復選框的數據綁定在屬性更改時的反應。 但是,我不能最好地弄清楚當屬性更改時應該如何調用OnPropertyChanged方法。
這是我到目前為止所擁有的:
<CheckBox x:Name="checkBox" Content="CheckBox" HorizontalAlignment="Left" Margin="232,109,0,0" VerticalAlignment="Top" IsChecked="{Binding Checked, Mode=TwoWay}"/>
<Button x:Name="button" Content="Ninja!" HorizontalAlignment="Left" Margin="228,182,0,0" VerticalAlignment="Top" Width="75" Click="button_Click"/>
以及我所做的“州”類的代碼:
namespace TestTwoWayBinding
{
class State : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool _checked;
public bool Checked {
get
{
return _checked;
}
set
{
_checked = value;
OnPropertyChanged(Checked);
}
}
public void Toggle()
{
if (!Checked)
{
Checked = true;
}
else
{
Checked = false;
}
}
public State(bool c)
{
this.Checked = c;
}
protected virtual void OnPropertyChanged(string propertyName)
{
if(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(Checked));
}
}
}
}
以及用於初始化和處理事件的視圖的代碼隱藏:
namespace TestTwoWayBinding
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private State _state;
public MainWindow()
{
InitializeComponent();
_state = new State((bool)checkBox.IsChecked);
}
private void button_Click(object sender, RoutedEventArgs e)
{
_state.Toggle();
}
}
}
從我收集的內容來看,OnPropertyChanged需要一個String propertyName,但我不知道這會帶來什么。 當我輸入屬性的名稱(Checked)時,那自然是指一個布爾值,而不是一個字符串。 我得不到什么? 還有什么我做錯了,因為當我通過按鈕更改它時,復選框沒有注冊屬性更改?
建議你傳遞字符串文字"Checked"
的兩個答案將起作用,但恕我直言並不是最好的方法。 相反,我更喜歡在實現[CallerMemberName]
OnPropertyChanged()
方法時使用[CallerMemberName]
。 (我不知道第三個答案是什么......它似乎與這個問題沒什么關系,我猜它只是從其他地方復制/粘貼)。
這是我如何編寫State
類的示例:
class State : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool _checked;
public bool Checked
{
get { return _checked; }
set { _checked = value; OnPropertyChanged(); }
}
public void Toggle()
{
Checked = !Checked;
}
public State(bool c)
{
this.Checked = c;
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
這里的關鍵是用[CallerMemberName]
標記的參數將自動用來自調用者的正確值填充,只是不傳遞任何值。 默認值為null
,因此編譯器將允許調用者不傳遞值。
請注意,我還簡化了Toggle()
方法。 沒有必要使用if
語句將一個bool
值轉換為另一個bool
值; 這就是布爾運算符的用途。
我還更改了OnPropertyChanged()
方法,以便它是線程安全的,即如果某些代碼在將事件字段與null
比較的時間與實際引發事件的時間之間取消訂閱PropertyChanged
事件中的最后一個處理程序,則不會崩潰。 通常,這不是問題,因為這些屬性幾乎總是只從一個線程訪問,但它很容易防止並且是一個很好的習慣。
請注意,在C#6中,您可以選擇只編寫PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
對於方法體。 並非所有人都在100%的時間內使用新的編譯器,所以我只是提到它作為您的可選選擇。
當然,您還需要正確設置DataContext
,如其他答案之一所示:
public MainWindow()
{
InitializeComponent();
_state = new State((bool)checkBox.IsChecked);
this.DataContext = _state;
}
雖然,就個人而言,我不確定我是否會對構造函數感到煩惱。 你似乎沒有其他代碼可以設置checkBox.IsChecked
,所以在我看來你總是會得到默認值。 此外,如果沒有參數化構造函數,則無法在XAML中創建視圖模型類; 在將來,您可能更喜歡像這樣配置DataContext
。 例如:
<Window.DataContext>
<l:State Checked="True"/>
</Window.DataContext>
並在窗口的構造函數中:
public MainWindow()
{
InitializeComponent();
_state = (State)this.DataContext;
}
另請參閱相關問答自動INotifyPropertyChanged 。 那里的問題確實存在一些不同的東西 - 他們想要實現界面而不必在屬性設置器中明確地寫任何東西 - 但無論好壞,他們得到的答案更多地是關於你的場景,這只是一個簡化的問題屬性setter實現而不是完全自動化。
我不得不承認,我原以為會有另外一個問題,將你的標記重復。 我確實找到了很多相關的問題。 但是沒有什么能直接關注“如何實現和使用實現INotifyPropertyChanged
的視圖模型?”,這正是您的問題所在。
附錄 :
我做了一些搜索,雖然這些看起來都沒有被認為是完全重復的,但它們都有很好的信息來幫助解決有關實現INotifyPropertyChanged
的問題:
使用屬性... INotifyPropertyChanged
模型和視圖模型的INotifyPropertyChanged
BindableBase與INotifyChanged
如何在MVVM(WPF)中編寫“ViewModelBase”
你真的很親密。 您需要做兩個小的更改並且您的測試工作:
DataContext
分配給_state變量。 OnPropertyChanged
並將propertyName
傳遞給OnPropertyChanged
方法中的PropertyChangedEventArgs
。 所以你的MainWindow ctor變成:
public MainWindow()
{
InitializeComponent();
_state = new State((bool)checkBox.IsChecked);
this.DataContext = _state;
}
和State類文件看起來像:
class State : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool _checked;
public bool Checked
{
get
{
return _checked;
}
set
{
_checked = value;
OnPropertyChanged("Checked");
}
}
public void Toggle()
{
if (!Checked)
{
Checked = true;
}
else
{
Checked = false;
}
}
public State(bool c)
{
this.Checked = c;
}
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
作為一名新手,我建議您了解有關Model-View-ViewModel MVVM設計模式的更多信息。 它是WPF的常見模式,有助於鼓勵關注點分離(保持業務邏輯不受用戶界面邏輯影響)
OnPropertyChanged
方法期望Checked
屬性的名稱作為參數 - 目前,您傳遞其值!
這意味着,將Checked
屬性聲明更改為:
public bool Checked {
get
{
return _checked;
}
set
{
_checked = value;
OnPropertyChanged("Checked");
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.