首页 文章

WPF Databind控件处于只写模式

提问于
浏览
0

我试图用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;
}

我的viewmodel包含Person的ObservableCollection,以及跟踪所选Person的单个Person .

我将listbox的ItemsSource绑定到ObservableCollection,将SelectedItem绑定到单个Person,名为CurrentPerson . 另外,我已将TextBox绑定到CurrentPerson.Name .

代码工作正常,但每当我更改TextBox的内容时 - 我的列表框也会更改 . 而且无论listbox \ selecteditem上的“OneWay,TwoWay,OneWayToSource”绑定模式的组合如何,我都无法阻止列表框从CurrentPerson更新 .

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

3 回答

  • 1

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

    两个简单的解决方案是

    • TextBox.Text 上的 BindingMode 更改为 Explicit ,因此在您告诉它之前它不会更新Person对象

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

    我个人更喜欢第二个选项,因为我'm not a big fan of bindings that don'吨准确地反映了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;
    

    并且 CanExecute 只会返回true

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

    我不确定我是否正确地遵循了这个问题 . 所以,我们有一个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;
    

    每当我更改文本框中的值时,它都会正确更新名称 . 我尝试为列表更改添加处理程序,但它不会被触发 .

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

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

  • 0

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

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

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

相关问题