簡體   English   中英

如何為我的bool屬性正確實現INotifyPropertyChanged並綁定到CheckBox.IsChecked?

[英]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”

你真的很親密。 您需要做兩個小的更改並且您的測試工作:

  1. 將Window的DataContext分配給_state變量。
  2. 將字符串“Checked”放入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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM