【问题标题】:WPF DataGrid not updating UI when its ItemsSource is updated in codeWPF DataGrid 在代码中更新其 ItemsSource 时不更新 UI
【发布时间】:2018-06-28 21:20:22
【问题描述】:

当 WPF DataGrid 在其 ObservableCollection 的项目中更改代码时,我应该怎么做?

<DataGrid HorizontalAlignment="Left" Height="100" Margin="54,25,0,0" VerticalAlignment="Top" Width="264" 
    IsSynchronizedWithCurrentItem="True" AutoGenerateColumns="False" 
    ItemsSource="{Binding DataSource}" SelectedItem="{Binding SelectedPerson}">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding FirstName}" />
        <DataGridTextColumn Binding="{Binding LastName}" />
    </DataGrid.Columns>
</DataGrid>

我在代码中更新SelectedPerson.FirstName 并执行DataSource 的setter。当前DataSource.FirstName 已更新,但DataGrid 不显示更改。如果我单击列标题,DataGrid 会刷新并显示更改的数据。当我使用 MVVM 并且我没有对 DataGrid 的引用时,如何让它迅速刷新?

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class VM : Notifier
{
    private ObservableCollection<Person> dataSource;
    public ObservableCollection<Person> DataSource
    {
        get { return dataSource; }
        set
        {
            dataSource = value;
            OnPropertyChanged("DataSource");
        }
    }

    private Person selectedPerson;
    public Person SelectedPerson
    {
        get { return selectedPerson; }
        set
        {
            selectedPerson = value;
            OnPropertyChanged("SelectedPerson");
        }
    }

    private string string1;
    public string String1
    {
        get { return string1; }
        set
        {
            string1 = value;
            OnPropertyChanged(String1);
        }
    }

    public VM()
    {
        String1 = "abc";

        DataSource = new ObservableCollection<Person>();
        DataSource.Add(new Person { FirstName = "Alpha", LastName = "Apple" });
        DataSource.Add(new Person { FirstName = "Beta", LastName = "Banana" });
        DataSource.Add(new Person { FirstName = "Charlie", LastName = "Cucumber" });
    }

    public ICommand SetSelectedCommand => new RelayCommandBase(SetSelected);
    private void SetSelected(object parameter = null)
    {
        SelectedPerson.FirstName = String1;
        SelectedPerson = SelectedPerson;    // force setter to run
        DataSource = DataSource;            // force ObservableCollection setter to run
    }
}

【问题讨论】:

    标签: wpf mvvm datagrid


    【解决方案1】:

    Person 类应该实现INotifyPropertyChanged 接口:

    public class Person : INotifyPropertyChanged
    {
        private string _firstName;
        public string FirstName
        {
            get { return _firstName; }
            set
            {
                _firstName = value;
                NotifyPropertyChanged();
            }
        }
    
        private string _lastName;
        public string LastName
        {
            get { return _lastName; }
            set
            {
                _lastName = value;
                NotifyPropertyChanged();
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    

    【讨论】:

    • 那行得通。谢谢。当 EntityFramework 生成 Person 类时,我应该如何实现?
    • 如果您有其他问题,请提出其他问题。但是要么不绑定到生成的实体类——创建你自己的类——要么修改它们:stackoverflow.com/questions/11010718/…
    【解决方案2】:

    您的更改没有得到反映,因为正在更新的项目(人)不会引发更改通知来更新 UI。为此,您需要更新 Person 类以在类 Person 中实现接口 INotifyPropertyChanged,与在视图模型中实现的方式相同,这应该可以工作。

    public class Person:Notifier
    {
        private string _firstName;
        public string FirstName
        {
            get { return _firstName; }
            set
            {
                _firstName = value;
                OnPropertyChanged(nameof(this.FirstName));
            }
        }
    
        private string _lastName;
        public string LastName
        {
            get { return _lastName; }
            set
            {
                _lastName = value;
                OnPropertyChanged(nameof(this.LastName));
            }
        }
    }
    

    还有一件事。 如果在您的 .NET Framework 版本中支持,您可以使用 C# nameof 以字符串形式获取属性名称,而不是对名称进行硬编码。这有助于您重构/重命名属性。

    【讨论】:

    • 谢谢@JCB。你能告诉我实体框架生成 Person 类的情况吗?
    • 不幸的是,没有直接的方法来实现它。正确的方法是在你的模型和视图模型之间创建一个映射。因此,您需要为 Person 创建一个 ViewModel,例如 PersonViewModel 并在创建时将 DTO Person 传递给它,以便每当更新人员 ViewModel 的属性时,它也会在 setter 中更新 DTO 属性。这在这里有所解释:stackoverflow.com/a/14870073/2147335stackoverflow.com/a/14870145/2147335
    • 我编写了一个简单的表单来将 EF 生成的 POCO 标量实体属性更改为通知属性,从现在开始我将使用它来更改我的 T4 生成的类。
    猜你喜欢
    • 2012-06-22
    • 2010-11-09
    • 1970-01-01
    • 2014-08-17
    • 2011-10-26
    • 2011-11-22
    • 2016-02-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多