有没有办法在不通知 ItemsSource 集合的情况下使用 ObservableCollection 和 MVVM 刷新 WPF DataGrid?

Posted

技术标签:

【中文标题】有没有办法在不通知 ItemsSource 集合的情况下使用 ObservableCollection 和 MVVM 刷新 WPF DataGrid?【英文标题】:Is there a way to refresh WPF DataGrid using ObservableCollection and MVVM without informing ItemsSource collection? 【发布时间】:2015-09-25 14:52:47 【问题描述】:

这是我的第一个问题,所以我会尽力而为。

我正在尝试使用 ObservableCollection 和 MVVM 来“刷新”一个简单的 WPF DataGrid 控件,正如网络上的众多教程所解释的那样。

在上下文中,这些是我的模型类:

(PersonViewModel.cs)

public class PersonViewModel : INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    private int _id;
    private int _idAddress;
    private string _name;
    private int _age;
    private string _address;

    public int Id
    
        get  return this._id; 
        set
        
            if (value != this._id)
            
                this._id = value;
                OnPropertyChanged();
            
        
    
    public int IdAddress
    
        get  return this._idAddress; 
        set
        
            if (value != this._idAddress)
            
                this._idAddress = value;
                OnPropertyChanged();
            
        
    
    public string Name
    
        get  return this._name; 
        set
        
            if (value != this._name)
            
                this._name = value;
                OnPropertyChanged();
            
        
    
    public int Age
    
        get  return this._age; 
        set
        
            if (value != this._age)
            
                this._age = value;
                OnPropertyChanged();
            
        
    
    public string Address
    
        get  return this._address; 
        set
        
            if (value != this._address)
            
                this._address = value;
                OnPropertyChanged();
            
        
    

    private void OnPropertyChanged([CallerMemberName]String caller = null)
    
        var handler = PropertyChanged;
        if (handler != null)
        
            handler(this, new PropertyChangedEventArgs(caller));
        
    

(AddressViewModel.cs)

public class AddressViewModel : INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    private int _id;
    private string _street;
    private int _number;

    public int Id
    
        get  return this._id; 
        set
        
            if (value != this._id)
            
                this._id = value;
                OnPropertyChanged();
            
        
    
    public string Street
    
        get  return this._street; 
        set
        
            if (value != this._street)
            
                this._street = value;
                OnPropertyChanged();
            
        
    
    public int Number
    
        get  return this._number; 
        set
        
            if (value != this._number)
            
                this._number = value;
                OnPropertyChanged();
            
        
    

    private void OnPropertyChanged([CallerMemberName]String caller = null)
    
        var handler = PropertyChanged;
        if (handler != null)
        
            handler(this, new PropertyChangedEventArgs(caller));
        
    

这是数据库模型的表示(无法上传图片

地址

身份证 街道 编号

身份证 身份证地址 名称 年龄 Address ---> 此属性连接 Street 和 Number of Address 实体。

所以,如您所见,这是一个非常简单的示例。只是一个概念验证。问题是,每当我尝试向数据库添加新实体时(通过 Entity Framework 6 和 LINQ),我都必须不可避免地将该 ViewModel 实体添加到 DataGrid 的数据上下文中。

这是目前工作的代码:

public static Person CreatePerson(PersonViewModel personVM)

    var person = new Person
    
        IdAddress = personVM.IdAddress,
        Name = personVM.Name,
        Age = personVM.Age
    ;

    try
    
        using (var context = new OCDemoContext())
        
            context.Database.Connection.Open();
            context.Person.Add(person);
            context.SaveChanges();
            context.Database.Connection.Close();
        
    
    catch
    
        throw;
    

    return person;

如您所见,此处需要在 DataGrid 中显示一列,该列连接 Address 数据库实体的两个属性:Street 和 Number,并将该值赋予 PersonViewModel 类的 Address 属性以在 DataGrid 中显示为一列。

在插入数据库后将实体添加到 DataGrid itemssource 集合的代码:

        // Add to the database
        PersonsGateway.CreatePerson(personVM);

        // Update view on DataGrid's itemssource collection
        ViewModel model = this.xGrid.DataContext as ViewModel;

        model.Persons.Insert(0, personVM);

XAML 为:

<Window x:Class="OCDemo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525" xmlns:local="clr-namespace:OCDemo">
<Window.Resources>
    <local:ViewModel x:Key="xViewModel" />
</Window.Resources>
<Grid x:Name="xGrid" DataContext="StaticResource xViewModel">
    <DataGrid x:Name="xDataGrid" Grid.Row="0" ItemsSource="Binding Persons" AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="Binding Path=Name" Header="Name"/>
            <DataGridTextColumn Binding="Binding Path=Age" Header="Age"/>
            <DataGridTextColumn Binding="Binding Path=Address" Header="Address"/>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

还有 ViewModel.cs

public class ViewModel

    public ObservableCollection<PersonViewModel> Persons  get; set; 

    public ViewModel()
    
        this.Persons = PersonsGateway.RetrievePersons();
    

T4 .tt 文件更新为MSDN - Updating code generation for data binding 解释。

那么,在 ObservableCollection 场景中,是否可以只依赖于将实体添加到数据库而不总是将实体添加到 itemssource 集合?

【问题讨论】:

【参考方案1】:

将您的视图模型更改为以下

public class ViewModel

    public ObservableCollection<PersonViewModel> Persons  get; private set; 

    public ViewModel()
    
        Persons = new ObservableCollection<PersonViewModel>();
        Persons.AddRange(PersonsGateway.RetrievePersons().ToList());
    

重要的是创建一次可观察集合而不是重新创建它,依赖于更改通知,所以创建它然后使用标准方法来管理它。

【讨论】:

我按照你的建议做了。没有变化。我的目标是直接通过 EF 方法将 PersonViewModel 的新实例添加到数据库中,并且该操作会更新 UI 上的 ViewModel。这可能吗?干杯。【参考方案2】:

好的,我应该建议不要使用这段代码

    PersonsGateway.CreatePerson(personVM);

    ViewModel model = this.xGrid.DataContext as ViewModel;

    model.Persons.Insert(0, personVM);

你应该这样做

PersonsGateway.CreatePerson(personVM);

ViewModel model = this.xGrid.DataContext as ViewModel;

model.Persons.Add(personVM);

【讨论】:

事实上,我想做的是不要使用ViewModel model = this.xGrid.DataContext as ViewModel; model.Persons.Add(personVM);ViewModel model = this.xGrid.DataContext as ViewModel; model.Persons.Insert(0, personVM);,只使用PersonsGateway.CreatePerson(personVM);...或者我必须完全 1.- 插入实体数据库,然后 2.- 更新模型?干杯菲尔 PersonsGateway 是您的 EF 适配器,它与 ObservableCollection 断开连接。您应该有对 Persons 集合所在的父 VM 的引用,因此一旦您知道您已经成功创建了该人,只需添加它,或者完全刷新视图(重建,但是为什么有一个 ObservableCollection) 对不起,我应该彻底阅读您最初的问题,您真正要问的是,您能否让 ObservableCollection 像以前的 DataSet 一样工作,您基本上将数据适配器绑定到它。我不认为你能做到这一点 您通常在这里做的是调用您的服务/存储库,它会返回一个构造的 Person VM,然后您将其添加到您的 ObservableCollection 没错。那是我试图做的。仅依靠网关更新。我必须更好地理解 ObservableCollection 的概念和应用。无论如何,谢谢菲尔:)

以上是关于有没有办法在不通知 ItemsSource 集合的情况下使用 ObservableCollection 和 MVVM 刷新 WPF DataGrid?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在不发送推送通知的情况下调用 saveCurrentTurnWithMatchData?

有没有办法在不轮询 REST API 的情况下通知 Google AI Platform 训练作业的状态变化?

有没有办法通过不删除和添加 ItemsSource 来更新 ListBox 的项目? [关闭]

有没有办法打开推送通知中收到的 url 而无需在 ios 10 中打开应用程序?

如何在不唤醒 Android 屏幕的情况下发送通知

重新绑定ItemsSource先设置ItemsSource = null;的原因