WPF Databind控件处于只写模式

时间:2015-11-24 15:50:16

标签: c# wpf mvvm data-binding listbox

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

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

代码工作正常,但每当我更改TextBox的内容时 - 我的列表框也会发生变化。而且无论是什么组合的" OneWay,TwoWay,OneWayToSource" listbox \ selecteditem上的绑定模式我无法阻止列表框从CurrentPerson更新。

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

3 个答案:

答案 0 :(得分:1)

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

两个简单的解决方案是

  • BindingMode上的TextBox.Text更改为Explicit,因此在您将其告知

  • 之前,它不会更新Person对象
  • TextBox.Text使用单独的字符串属性,并在命令执行时将其复制到SelectedPerson.Name

我个人更喜欢第二个选项,因为我不是那些不能准确反映UI组件背后的数据对象的绑定的忠实粉丝,并且它允许用户更改SelectedItem而不重置TextBox值。

有关第二个选项的示例,您的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

答案 1 :(得分:0)

我不确定我是否正确地遵循了这个问题。 所以,我们有一个类人物

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

如果它与您的问题陈述不同,您能否发表评论?

答案 2 :(得分:0)

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

在列表框中选择某个人时,您必须将该人的ID(避免将该对象本身传递)传递给绑定到应编辑的属性的PersonEditViewModel,将人员数据加载到{ {1}}然后编辑。点击“保存”按钮后,它应该提交更改并更新数据库或用于持久性的任何内容。

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