在 C# 代码而不是 XAML 中声明的 WPF 属性

问题描述 投票:0回答:1

由于某些特殊原因,我在 C# 代码中声明了一个绑定,而不是像往常一样在 XAML 中声明它。我面临的问题是,当我仅更改对象的一个属性时,INotifyPropertyChanged 可以正常工作并按预期传播更改,但是当我更改整个对象(引用)时,它无法按预期工作。

您可以在这个示例代码中看到它,其中我设置了一个初始值“111”,效果很好,然后我只将一个属性值更改为“222”并且也按预期工作,但是当我设置一个新对象时,那么它就不起作用了。

我应该在代码中更改什么,以便第三次分配也起作用并且通过绑定将 Text 属性设置为“333”?

    public class MainWindowViewModel : INotifyPropertyChanged
{
    private MySubClass _selectedItem;
    public MySubClass SelectedItem
    {
        get => _selectedItem;
        set
        {
            _selectedItem = value;
            OnPropertyChanged(nameof(SelectedItem));
        }
    }
    private MySubClass _selectedItemBefore;
    public MySubClass SelectedItemBefore
    {
        get => _selectedItemBefore;
        set
        {
            _selectedItemBefore = value;
            OnPropertyChanged(nameof(SelectedItemBefore));
        }
    }
    private MySubClass _selectedItemAfter;
    public MySubClass SelectedItemAfter
    {
        get => _selectedItemAfter;
        set
        {
            _selectedItemAfter = value;
            OnPropertyChanged(nameof(SelectedItemAfter));
        }
    }


    TextBox textBox = new TextBox();
    public MainWindowViewModel()
    {
        SelectedItemBefore = new MySubClass
        {
            FirstProperty = "111"
        };
        SelectedItemAfter = new MySubClass
        {
            FirstProperty = "333"
        };
        SelectedItem = SelectedItemBefore;
        var firstPropertyBinding = new Binding("FirstProperty") { Source = SelectedItem, Mode = BindingMode.TwoWay };
        BindingOperations.SetBinding(textBox, TextBox.TextProperty, firstPropertyBinding);
        Console.WriteLine($"Text here is: {textBox.Text}");
        // It's "111", so OK!!!

        SelectedItem.FirstProperty = "222";
        Console.WriteLine($"Text here is: {textBox.Text}");
        // It's "222", so OK!!!

        SelectedItem = SelectedItemAfter;
        Console.WriteLine($"Text here is: {textBox.Text}");
        // ¡¡¡FAIL!!!: expected "333" but it is "222" yet
        // (here SelectedItem.FirstProperty == "333")
    }
    

    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
    {
        var changed = PropertyChanged;
        if (changed == null)
            return;

        changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion        
}

public class MySubClass : INotifyPropertyChanged
{
    private string _firstProperty;
    public string FirstProperty
    {
        get => _firstProperty;
        set
        {
            _firstProperty = value;
            OnPropertyChanged(nameof(FirstProperty));
        }
    }
    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
    {
        var changed = PropertyChanged;
        if (changed == null)
            return;

        changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion   
}

更新: 我知道 TextBox 永远不应该出现在 ViewModel 中,也不应该出现与 View 相关的任何内容,请不要过多关注这个细节。该代码仅用于学习目的并了解绑定如何工作,但目前我还没有完全理解它。我希望了解如何修改代码以使其显示“333”。

c# wpf xaml binding inotifypropertychanged
1个回答
0
投票

首先我们来看看

Binding
的数据来源:

  • Source
    :直接静态绑定源引用,绑定后不可修改。
    • 您可以通过
      {Reference name}
      在 XAML 中进行设置,以在此 XAML 范围内设置命名元素引用。
  • RelativeSource
    :根据应用绑定的元素和该RelativeSource的模式,根据应用绑定的元素的相对位置获取其他对象作为绑定源。
    • 如果
      RelativeSource
      目标改变将会改变这个绑定源的引用。
  • ElementName
    :设置在当前 XAML 和同一可视化树中定义的使用
    x:Name
    命名元素的名称。
    • 它无法找到不在可视树中的元素,即使它们是在同一个 XAML 文件中定义的(例如在
      Popup
      控件内部和外部)
  • 以上均未设置:绑定源为对象(Control)自带的DataContext属性,DataContext可以在可视化树或文档流中继承。
    • 如果
      DataContext
      改变将会改变这个绑定源的引用。

Setted

Binding.Source
属性将设置对象的静态 引用作为此
Binding
上的绑定源,但看起来你想要一个动态源,所以你不应该使用
Binding.Source

© www.soinside.com 2019 - 2024. All rights reserved.