我试图用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更新列表框。
答案 0 :(得分:1)
只有Person
对象的副本在ListBox.ItemsSource
和TextBox.Text
中使用,因此从一个位置自然更新该对象将反映另一个位置的变化好。
两个简单的解决方案是
将BindingMode
上的TextBox.Text
更改为Explicit
,因此在您将其告知
为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
只会在
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
接口)。