如何使listview在wpf中自我更新?
我意识到这是一个很长的问题,但我在这里看到的只有发布我的代码,为了清晰起见,我尽量保持代码的简洁。当然,这么做违反了很多最佳实践,这个例子已经足够长了 我制作了一个非常简单的wpf应用程序如何使listview在wpf中自我更新?,wpf,data-binding,listview,Wpf,Data Binding,Listview,我意识到这是一个很长的问题,但我在这里看到的只有发布我的代码,为了清晰起见,我尽量保持代码的简洁。当然,这么做违反了很多最佳实践,这个例子已经足够长了 我制作了一个非常简单的wpf应用程序 在屏幕左侧显示人员列表(格式:姓名和年龄介于()之间) 在屏幕右侧显示所选人员的所有属性 在右侧,您可以编辑属性并在msgbox中查看整个选择 在下面的示例中,我编辑了Bar的年龄。但是,在列表中,年龄不会更新。如果我询问基础集合,它似乎仍已更新。。 我怎样才能让名单知道 除了屏幕截图,下面是代码和XAM
- 在屏幕左侧显示人员列表(格式:姓名和年龄介于()之间)
- 在屏幕右侧显示所选人员的所有属性
- 在右侧,您可以编辑属性并在msgbox中查看整个选择
仅仅有一个ObservableCollection是不够的,如果您想更新特定属性的绑定,那么您的Person类型必须实现 编辑 我刚刚注意到,您的左侧列表框没有更新,因为您没有为Person对象设置DataTemplate。您现在拥有的是一个ToString()实现,它向UI报告后不会更新 你需要这样的东西:
<DataTemplate DataType="{x:Type local:Person}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="("/>
<TextBlock Text="{Binding Age}"/>
<TextBlock Text=")"/>
</StackPanel>
</DataTemplate>
示例:
public class Person : DependencyObject
{
public static readonly DependencyProperty NameProperty = DependencyProperty.Register(
"Name",
typeof(string),
typeof(Person)
);
public static readonly DependencyProperty AgeProperty = DependencyProperty.Register(
"Age",
typeof(int),
typeof(Person)
);
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
public int Age
{
get { return (int)GetValue(AgeProperty ); }
set { SetValue(AgeProperty , value); }
}
public override string ToString()
{
return String.Format("{0} ({1})",Name,Age);
}
}
首先,在集合级别,您的
ListView
的ItemsSource
应该是observedcollection
ObservableCollection<Person> Persons = new ObservableCollection<Person>();
已定义,必须在属性的setter中显式调用。
需要注意的一点是,您不需要硬编码属性名,CallerMemberName
属性可用于自动获取调用方的名称
public class DemoCustomer : INotifyPropertyChanged
{
// These fields hold the values for the public properties.
private Guid idValue = Guid.NewGuid();
private string customerNameValue = String.Empty;
private string phoneNumberValue = String.Empty;
public event PropertyChangedEventHandler PropertyChanged;
// This method is called by the Set accessor of each property.
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
// The constructor is private to enforce the factory pattern.
private DemoCustomer()
{
customerNameValue = "Customer";
phoneNumberValue = "(312)555-0100";
}
// This is the public factory method.
public static DemoCustomer CreateNewCustomer()
{
return new DemoCustomer();
}
// This property represents an ID, suitable
// for use as a primary key in a database.
public Guid ID
{
get
{
return this.idValue;
}
}
public string CustomerName
{
get
{
return this.customerNameValue;
}
set
{
if (value != this.customerNameValue)
{
this.customerNameValue = value;
NotifyPropertyChanged();
}
}
}
public string PhoneNumber
{
get
{
return this.phoneNumberValue;
}
set
{
if (value != this.phoneNumberValue)
{
this.phoneNumberValue = value;
NotifyPropertyChanged();
}
}
}
}
或者继承自DependencyObjectNo,这还不够,绑定到的值必须是DependencyProperty(在DependencyObject上),或者所属类型必须实现INotifyPropertyChanged(正确)。是的,基础很容易被忽略。编辑了我的答案。是的,这是正确实现接口的:)我想我把它改为DependencyObject,因为你也可以在XAML中使用它,就像你想要那样。注意,在这种情况下,从DependencyObject继承确实是不必要的开销。
<DataTemplate DataType="{x:Type local:Person}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="("/>
<TextBlock Text="{Binding Age}"/>
<TextBlock Text=")"/>
</StackPanel>
</DataTemplate>
public class Person : DependencyObject
{
public static readonly DependencyProperty NameProperty = DependencyProperty.Register(
"Name",
typeof(string),
typeof(Person)
);
public static readonly DependencyProperty AgeProperty = DependencyProperty.Register(
"Age",
typeof(int),
typeof(Person)
);
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
public int Age
{
get { return (int)GetValue(AgeProperty ); }
set { SetValue(AgeProperty , value); }
}
public override string ToString()
{
return String.Format("{0} ({1})",Name,Age);
}
}
ObservableCollection<Person> Persons = new ObservableCollection<Person>();
public event PropertyChangedEventHandler PropertyChanged;
public class DemoCustomer : INotifyPropertyChanged
{
// These fields hold the values for the public properties.
private Guid idValue = Guid.NewGuid();
private string customerNameValue = String.Empty;
private string phoneNumberValue = String.Empty;
public event PropertyChangedEventHandler PropertyChanged;
// This method is called by the Set accessor of each property.
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
// The constructor is private to enforce the factory pattern.
private DemoCustomer()
{
customerNameValue = "Customer";
phoneNumberValue = "(312)555-0100";
}
// This is the public factory method.
public static DemoCustomer CreateNewCustomer()
{
return new DemoCustomer();
}
// This property represents an ID, suitable
// for use as a primary key in a database.
public Guid ID
{
get
{
return this.idValue;
}
}
public string CustomerName
{
get
{
return this.customerNameValue;
}
set
{
if (value != this.customerNameValue)
{
this.customerNameValue = value;
NotifyPropertyChanged();
}
}
}
public string PhoneNumber
{
get
{
return this.phoneNumberValue;
}
set
{
if (value != this.phoneNumberValue)
{
this.phoneNumberValue = value;
NotifyPropertyChanged();
}
}
}
}