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

时间:2014-08-11 23:29:50

标签: c# data-binding code-behind inotifypropertychanged local-variables

我有两个类,Node和Connection。 Node的名称和编号作为属性,Connection实际上是关于两个节点之间的连接信息。我使用这两个类作为OservableCollection声明为static。 NodeNubmer和NodeName属性的CollectionPropertyChangedEventHandler在Node类中实现,因此当通过数据绑定在UI中更改任何节点的信息时,将更改后面的UI和节点信息代码。但是,Connection中的节点信息不会更改,例如在UI中更改节点名称时。这是代码的一部分。如何在Node中更改节点中的节点信息?

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));   
        }

   }
}

1 个答案:

答案 0 :(得分:1)

我完全同意@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类中使用数据绑定you can do it manually。您的绑定目标需要为dependency properties,并且您的类需要派生自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所暗示的那样,前者可能更像你正在寻找的东西。我在这里有一个功能齐全的例子: