【问题标题】:Two-way binding issue - PropertyChanged & CanExecuteChanged双向绑定问题 - PropertyChanged & CanExecuteChanged
【发布时间】:2012-03-12 12:53:21
【问题描述】:

我想实现,当文本框的值改变时,我的添加按钮变得可用。

我将文本框与 viewModel 绑定:

<TextBox Name="nameTbx" Text="{Binding Path=NewNode.Name, Mode=TwoWay}" />

我的按钮:

<Button Content="Add" Command="{Binding Path=AddNewNodeProperty}"/>

在后面的 XAML 代码中,我将 DataContext 设置为我的 ViewModel。 ViewModel 看起来像:

/* code*/

private Node _newNode = new Node();
public Node NewNode
{
    get
    {
        return _newNode;
    }
    set
    {
        _newNode = value;
        OnPropertyChanged("NewNode");
    }
}

private AddNode _addNewNodeProperty;
    public AddNode AddNewNodeProperty
    {
        get
        {
            return _addNewNodeProperty;
        }
    }

在构造函数中我初始化 _addNewNodeProperty

this._addNewNodeProperty = new AddNode(this);

这是我的 AddNode 类:

public class AddNode : ICommand
{
    private ServiceMapViewModel viewModel;

    public AddNode(ServiceMapViewModel viewModel)
    {
        this.viewModel = viewModel;
        this.viewModel.PropertyChanged += (s, e) =>
        {
            if (CanExecuteChanged != null)
            {
                CanExecuteChanged(this, new EventArgs());
            }
        };
    }

    public bool CanExecute(object parameter)
    {
        bool b = !string.IsNullOrWhiteSpace(this.viewModel.NewNode.Name);

        return b;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        this.viewModel.AddNewNode();
    }
}

最后是我的 Node 类:

public class Node
{
    public string Name { get; set; }

    public bool? IsChecked { get; set; }

    public Group Group { get; set; }

    public Category Category { get; set; }

    public string Metadata { get; set; }

    public List<string> Children = new List<string>();

    public List<string> Parents = new List<string>();
}

问题是当我更改我的文本框文本时,NewNode 正在为我获取值,但它应该设置。

Tnx 进阶!

编辑 让我补充一点:

I also have a datagrid on the screen and when Selected Item is changed, my Add butom become available.

所选项目:

<DataGrid Name="nodeDataGrid" ItemsSource="{Binding Path=MyServiceMap.Nodes}"
        Background="Silver" Margin="0,34,10,10" IsReadOnly="True" SelectedItem="{Binding Path=SelectedNode}"  >

和虚拟机:

private Node _selectedNode = new Node();
    public Node SelectedNode
    {
        get
        {
            return _selectedNode;
        }
        set
        {
            _selectedNode = value;
            OnPropertyChanged("SelectedNode");
        }
    }

【问题讨论】:

    标签: c# wpf xaml binding mvvm


    【解决方案1】:

    您的 TextBox 绑定到您的 Node 对象的 Name 属性。 Name 属性在更改时不会引发 PropertyChanged 事件。只有整个 NewNode 属性会在更改时引发事件。

    编辑以提供建议

    一种方法是创建一个NodeViewModel 类,正如mtaboy 所建议的,它将实现INotifyPropertyChanged 接口。您将在 ViewModel 上创建您希望向用户公开的任何属性。您可以将 ViewModel 视为位于您的模型(即Node 类)和您的视图(向用户显示的 UI)之间。

    我建议的一个更改是将ICommand 逻辑封装到它自己的类中。我经常使用的一个是 RelayCommand 类,可以在 MSDN 上的 Josh Smith 的 MVVM article 中找到。如果您使用该类,您可以在 ViewModel 类中定义一个属性或一个私有方法,该方法将返回用户是否可以添加。例如,

    private bool CanAddNewNode()
    {
      return !String.IsNullOrWhitespace(Name);
    }
    

    在实例化您的 RelayCommand 时,您可以为引用上述方法的第二个参数传递一个 lambda。

    var saveCommand = new RelayCommand(param => SaveMethod(), param => CanAddNewNode());
    

    您将从 ViewModel 中公开一个 ICommand 属性,该属性将返回 RelayCommand 对象。

    希望这能让你开始。

    【讨论】:

    • 更新了我的答案以提供一些具体建议。
    【解决方案2】:

    你的节点类必须实现

    INotifyPropertyChanged

    public class Node:INotifyPropertyChanged
    {
    
           #region INotifyPropertyChanged Members
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
         string _name ;
          public string Name
          {
              get { return _name; }
    
    
              set
              {
                  _name = value;
                   OnPropertyChanged("Name");
    
              }
          }
    
    
    
    .....
    

    欲了解更多信息,请参阅MVVM Pattern

    【讨论】:

    • 我试过了,但我正在通过 WCF 从 .XML 读取数据,当我实现 INotifyPropertyChanged 时无法从 .XML 获取任何数据...
    • 我知道要实现 mvvm 的 obseverpattern 必须实现 INotifyPropertyChanged,但请参阅这篇文章codeproject.com/Articles/87510/WCF-by-Example-Introduction
    • 字面意思是class Node:INotifyPropertyChanged——这不是继承,这是一个接口实现
    • @sll 你是对的,我错了......但在我上面的评论中我说“你必须暗示 INotifyPropertyChanged”。
    【解决方案3】:

    问题是当我更改我的文本框文本时,NewNode 正在获取 对我来说的价值,但它应该设置。

    我相信您也应该支持Node 类的INotifyPropertyChanged 接口。

    此外,如果您希望在每个角色更新时保持属性同步 - 尝试设置 UpdateSourceTrigger,否则属性将在 LostFocus 事件中更新。

    <TextBox Name="nameTbx" 
             Text="{Binding Path=NewNode.Name, 
                            Mode=TwoWay,
                            UpdateSourceTrigger=PropertyChanged}" />  
    

    【讨论】:

    • 我试过了,但是我正在通过 WCF 从 .XML 读取数据,当我实现 INotifyPropertyChanged 时,我无法从 .XML 获取任何数据。
    • 为什么是could not get any data from .XML when i implement INotifyPropertyChanged.?无论如何,您可以通过使用 NodeUi 类包装器来解决它,用于 Node 模型实体
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-27
    • 2014-01-30
    • 1970-01-01
    • 2020-06-11
    • 1970-01-01
    • 2017-01-20
    • 1970-01-01
    相关资源
    最近更新 更多