仅写模式下的WPF数据绑定控件

本文关键字:WPF 数据绑定 控件 模式 | 更新日期: 2023-09-27 18:24:12

我试图对WPF绑定进行一些修改,所以我创建了一个简单的项目。这是代码:

public class Person : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public int Age {
        get { return age; }
        set {
            age = value;
            FirePropertyChanged("Age");
        }
    }
    public string Name
    {
        get { return name; }
        set
        {
            name = value;
            FirePropertyChanged("Name");
        }
    }
    private void FirePropertyChanged(string v)
    {
        if(PropertyChanged !=null)
            PropertyChanged(this, new PropertyChangedEventArgs(v));
    }
    private int age;
    private string name;
}

我的视图模型包含人员的ObservableCollection,以及跟踪所选人员的单个人员。

我已经将listbox的ItemsSource绑定到ObservableCollection,将SelectedItem绑定到一个名为CurrentPerson的Person。此外,我已将TextBox绑定到CurrentPerson.Name.

代码运行良好,但每当我更改TextBox的内容时,我的列表框也会更改。无论listbox''selectedeem上的"单向、双向、单向到源"绑定模式的组合如何,我都无法阻止listbox从CurrentPerson更新。

如何防止这种行为?我只想使用VM的ICommand接口从CurrentPerson更新列表框。

仅写模式下的WPF数据绑定控件

ListBox.ItemsSourceTextBox.Text中都使用的Person对象只有一个副本,因此从一个位置自然更新该对象也会反映另一个位置的变化。

两个简单的解决方案是

  • TextBox.Text上的BindingMode更改为Explicit,这样在您将Person对象告知之前,它不会更新它

  • TextBox.Text使用单独的字符串属性,并在命令执行时将其复制到SelectedPerson.Name

就我个人而言,我更喜欢第二个选项,因为我不太喜欢不能准确反映UI组件后面的数据对象的绑定,而且它允许用户在不重置TextBox值的情况下更改SelectedItem


对于第二个选项的示例,您的ViewModel可能如下所示:

public class MyViewModel()
{
    ObservableCollection<Person> People { get; set; }
    Person SelectedPerson { get; set; }
    string NewPersonName { get; set; }
    ICommand UpdatePersonName { get; }
}

其中UpdatePersonName命令将执行

SelectedPerson.Name = NewPersonName;

并且CCD_ 11只有在

SelectedPerson != null 
&& !NewPersonName.IsNullOrWhiteSpace() 
&& NewPersonName != SelectedPerson.Name

我不确定我是否正确地回答了这个问题。因此,我们有一个类Person作为

public class Person : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public int Age
        {
            get { return age; }
            set
            {
                age = value;
                FirePropertyChanged("Age");
            }
        }
        public string Name
        {
            get { return name; }
            set
            {
                name = value;
                FirePropertyChanged("Name");
            }
        }
        private void FirePropertyChanged(string v)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(v));
        }
        private int age;
        private string name;
    }

我们有一个视图模型

public class ViewModel : INotifyPropertyChanged
    {
        public ObservableCollection<Person> List { get; set; }
        Person currentPerson;
        public Person CurrentPerson {
            get { return currentPerson; }
            set { currentPerson = value;
            FirePropertyChanged("CurrentPerson");
            }
        }
        private void FirePropertyChanged(string v)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(v));
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }

xaml是

<ListBox ItemsSource="{Binding List}" SelectedItem="{Binding CurrentPerson}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBox Text="{Binding Name}" Width="100" />
        </DataTemplate>
    </ListBox.ItemTemplate>       
</ListBox>

我通过将视图模型绑定到视图

    ViewModel vm = new ViewModel();
    vm.List = new ObservableCollection<Person>();
    foreach (var i in Enumerable.Range(1,10))
    {
        vm.List.Add(new Person() { Name = "Test" + i.ToString(), Age= i });
    }
    vm.CurrentPerson = null;
    this.DataContext = vm;

每当我更改文本框中的值时,它都会正确地更新名称。我试图为列表changed添加一个处理程序,但它并没有被触发。

vm.List.CollectionChanged += List_CollectionChanged;
void List_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            MessageBox.Show(e.Action.ToString());
        }

如果它和你的问题陈述不一样,你能评论一下吗?

如果您想控制保存/更新的时间和内容,显然需要一个ViewModel来编辑您的Person模型。

在列表框中选择人员时,必须将人员的id(避免传递对象本身)传递给绑定到要编辑的属性的PersonEditViewModel,将人员数据加载到PersonEditViewModel中,然后进行编辑。一旦您点击"保存"按钮,它应该提交更改并更新数据库或用于持久性的任何东西。

使用事件/消息来回传递值/事件,或者使用导航方法(如Prism中的INavigationAware接口)。