如何使listview在wpf中自我更新?

如何使listview在wpf中自我更新?,wpf,data-binding,listview,Wpf,Data Binding,Listview,我意识到这是一个很长的问题,但我在这里看到的只有发布我的代码,为了清晰起见,我尽量保持代码的简洁。当然,这么做违反了很多最佳实践,这个例子已经足够长了 我制作了一个非常简单的wpf应用程序 在屏幕左侧显示人员列表(格式:姓名和年龄介于()之间) 在屏幕右侧显示所选人员的所有属性 在右侧,您可以编辑属性并在msgbox中查看整个选择 在下面的示例中,我编辑了Bar的年龄。但是,在列表中,年龄不会更新。如果我询问基础集合,它似乎仍已更新。。 我怎样才能让名单知道 除了屏幕截图,下面是代码和XAM

我意识到这是一个很长的问题,但我在这里看到的只有发布我的代码,为了清晰起见,我尽量保持代码的简洁。当然,这么做违反了很多最佳实践,这个例子已经足够长了

我制作了一个非常简单的wpf应用程序

  • 在屏幕左侧显示人员列表(格式:姓名和年龄介于()之间)
  • 在屏幕右侧显示所选人员的所有属性
  • 在右侧,您可以编辑属性并在msgbox中查看整个选择
在下面的示例中,我编辑了Bar的年龄。但是,在列表中,年龄不会更新。如果我询问基础集合,它似乎仍已更新。。 我怎样才能让名单知道

除了屏幕截图,下面是代码和XAML

注意:如果图像未显示,请尝试在新选项卡或窗口中打开它





仅仅有一个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();
            }
        }
    }
}