仅写模式下的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更新列表框。
ListBox.ItemsSource
和TextBox.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
接口)。