为什么INotifyPropertyChanged不更新代码后面的局部变量

本文关键字:局部变量 代码 INotifyPropertyChanged 更新 为什么 | 更新日期: 2023-09-27 18:17:27

我有两个类,Node和Connection。Node的名称和编号作为属性,Connection的字面意思是关于两个节点之间的连接信息。我使用这两个类作为observable collection声明静态。NodeNubmer和NodeName属性的CollectionPropertyChangedEventHandler在Node类中实现,因此当UI中任何节点的信息通过数据绑定发生变化时,UI和节点信息后面的代码都会发生变化。但是,Connection中的节点信息不会发生变化,例如在UI中更改了节点名称。下面是部分代码。如何更新节点信息连接时,它的变化在节点?

public Class Node: INotifyPropertyChanged
{
   private int _nodeNumber;
   private string _nodeName;
   public int NodeNumber
   {
        get
        {
            return _nodeNumber;
        }
        set
        {
            _nodeNumber = value;
            OnPropertyChanged("NodeNumber");
        }
   }
   public string NodeName
   {
        get
        {
            return _nodeName;
        }
        set
        {
            _nodeName = value;
            OnPropertyChanged("NodeName");
        }
   }
   public event PropertyChangedEventHandler PropertyChanged;
   // constructor
   public Node(int nodeNumber, string nodeName)
   {
       _nodeNumber = nodeNumber;
       _nodeName = nodeName;
   }
   public void OnPropertyChanged(string propertyName)
   {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));   
        }
   }
}
public Class Connection: INotifyPropertyChanged
{
   private int _sourceNumber;
   private int _destNamber;
   private string _sourceName;
   private string _destName;
   public int SourceNumber
   {
        get
        {
            return _sourceNumber;
        }
        set
        {
            _sourceNumber = value;
            OnPropertyChanged("SourceNumber");
        }
   }

   public int DestNumber
   {
        get
        {
            return _destNumber;
        }
        set
        {
            _destNumber = value;
            OnPropertyChanged("DestNumber");
        }
   }
   public string SourceName
   {
        get
        {
            return _sourceName;
        }
        set
        {
            _sourceName = value;
            OnPropertyChanged("SourceName");
        }
   }
   public string DestName
   {
        get
        {
            return _destName;
        }
        set
        {
            _destName = value;
            OnPropertyChanged("DestName");
        }
   }
   public event PropertyChangedEventHandler PropertyChanged;
   // constructor
   public Connection(int sourceNumber, int destNumber)
   {
       _sourceNumber = sourceNumber;
       _destNumber = destNumber;
       // I guess this code is the reason why SourceName/DestName isn't changed when its node's name changed in UI, but I don't know how to fix this code.
       // NodeInfo is ObservableCollection of Node
       SourceName = NodeInfo.Collection[sourceNumber-1].NodeName;
       DestName = NodeInfo.Collection[destNumber-1].NodeName;
   }
   public void OnPropertyChanged(string propertyName)
   {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));   
        }
   }
}

为什么INotifyPropertyChanged不更新代码后面的局部变量

我完全同意@mike z的观点。我认为如果你的连接类看起来像这样(BaseVM是一个实现INotifyPropertyChanged接口的类,为了简单起见,这里省略了),你的生活会容易得多:

public class Connection :  BaseVM
{
    public Connection(string name, Node a, Node b)
    {
        this.Name = name;
        this.NodeA = a;
        this.NodeB = b;
    }
    string _name;
    public string Name
    {
        get { return _name; }
        set
        {
            if (_name == value) return;
            _name = value;
            Notify( "Name" );
        }
    }
    Node _nodeA;
    public Node NodeA
    {
        get { return _nodeA; }
        set
        {
            if (_nodeA == value) return;
            _nodeA = value;
            Notify( "NodeA" );
        }
    }

    Node _nodeB;
    public Node NodeB
    {
        get { return _nodeB; }
        set
        {
            if (_nodeB == value) return;
            _nodeB = value;
            Notify( "NodeB" );
        }
    }

那么您可以在XAML中使用{Binding NodeA.Name}(假设Connection作为您的数据上下文)。

如果你真的想在Connection类的中绑定数据,你可以手工完成。你的绑定目标需要是依赖属性,你的类需要派生自DependencyObject:
    public string AName
    {
        get { return (string)GetValue (ANameProperty); }
        set { SetValue (ANameProperty, value); }
    }
    public static readonly DependencyProperty ANameProperty =
        DependencyProperty.Register ("AName", typeof (string), typeof (Connection), new PropertyMetadata (""));

然后你必须手动设置绑定:

    public Connection(string name, Node a, Node b)
    {
        // ...
        this.AName = a.Name;
        // to keep these updated, there needs to be a binding between the two
        var binding = new Binding ("Name");
        binding.Source = this.NodeA;
        BindingOperations.SetBinding (this, ANameProperty, binding);
    }

但正如@mike z所建议的,前者可能更符合你的要求。我有一个完整的例子:

  • XAML小提琴
  • CS小提琴