【问题标题】:Working with an ObservableCollection based on an Entity Framework one to many property使用基于实体框架一对多属性的 ObservableCollection
【发布时间】:2016-01-09 16:45:19
【问题描述】:

在 MVVM 中使用 WPF。我有一个带有 CurrentItem 属性的 ViewModel。这是一个直接从实体框架中提取的 Item 对象。 Item 有一个 Property 对象的集合。

public virtual ICollection<Property> Properties { get; set; }

在视图中,我需要用户能够在此集合中添加和删除对象。为此,我需要创建一个 ObservableCollection&lt;Property&gt;,我们将其称为 ItemProperties。

有多种方法可以做到这一点。最明显的是在 ViewModel 上添加 ObservableCollection&lt;Property&gt; 属性。然后在构造函数中填充它,如下所示:

ItemProperties = new ObservableCollection<Property>(CurrentItem.Properties);

还可以创建一个位于真实集合顶部的 ObservableCollection 包装器:

public ObservableCollection<Property> ItemProperties
{
    get
    {
        return new ObservableCollection<Property>(CurrentItem.Properties);
    }
    set
    {
        CurrentItem.Properties = value.ToList();
        OnPropertyChanged("ItemProperties");
    }
}

这有它自己的问题。你不能只 Add() 到这个集合,因为它会首先 get,这意味着集合保持不变。因此,您要么必须启动一个新集合,添加到该集合,然后将其值分配给该属性,要么在该属性之外引发 OnPropertyChanged 事件。其中任何一个听起来都像是维护问题。

有没有更有效的方法可以直接访问 EF 属性列表?

【问题讨论】:

  • 如果您希望用户能够添加和删除,您可能不想使用可观察集合。
  • @Chris 如果我想使用双向绑定以便视图响应用户的操作,我的印象是 ObservableCollection 是必要的?快速测试表明情况确实如此。
  • 为了让视图响应,您需要实现可观察集合默认执行的 INotifyPropertyChanged,如果您沿着这条路线走,则需要自定义控件,但它会更适合您的需求

标签: c# wpf entity-framework mvvm


【解决方案1】:

在这一点上,您具有数据层和 Presentation 之间解耦的优势,无需启动集合。

尝试使用LoadedEvent 从服务器加载数据。 示例事件如下

 private ObservableCollection<Property> _itemProperties;

    public ObservableCollection<Property> ItemProperties
    {
        get { return _itemProperties; }
        set
        {
            _itemProperties= value;
           RaisePropertyChanged(() => ItemProperties);
        }
    }

加载的事件

var result= await Task.Run(() => MyBusiness.GetMyData());
//Map to the viewModel if necessary

ItemProperties = result;

加入收藏

var isSuccess = await Task.Run(()=>MyBusiness.Insert(x));
if(isSuccess)
{
   ItemProperties.Add(x);
}

【讨论】:

  • 这实际上是我所做的。我只是对你必须 Add() 到你的 ViewModel 属性而不是原始集合本身这一事实感到不舒服。感觉很脆弱。
【解决方案2】:

如果您可以在 ViewModel 类中访问您的 DbContext,则可以使用 DbSet&lt;TEntity&gt;.Local 属性,它将为您提供一个包含所有 UnchangedModifiedAdded 对象的 ObservableCollection&lt;TEntity&gt;当前由DbContext 跟踪给定的DbSet,但首先您需要过滤以仅将属于您的CurrentItemPropertyItems 加载到内存中。

public class YourViewModel
{
    private context=new YourContext();

    public YourViewModel()  
    {
      context.ItemProperties.Where(ip=>ip.ItemId==CurrentItem.Id).Load();
      ItemProperties=context.ItemProperties.Local;
    }

    private ObservableCollection<Property> _itemProperties;

    public ObservableCollection<Property> ItemProperties
    {
        get { return _itemProperties; }
        set
        {
           _itemProperties= value;
           OnPropertyChanged("ItemProperties");
        }
    }

    public void SaveItemProperties()
    {
      context.SaveChanges();
    }
}

要保存更改,您只需创建一个调用SaveItemProperties 方法的command。此外,最好禁用延迟加载以不加载与您的CurrentItem 相关的ItemProperties 的两倍。

如果您需要了解更多有关其工作原理的信息,可以阅读此article

【讨论】:

    【解决方案3】:

    首先,我不认为为每个 get 创建一个 ObservableCollection 是一个好主意。相反,我会将它缓存在一个字段中。其次,对于缓存的实例,您可能希望订阅 CollectionChanged 事件,在该事件中您的更改将被持久化到底层集合。

    【讨论】:

      【解决方案4】:

      无论哪种方式都很好。但是您需要做的是为 Observable Collection 中存在的事件 CollectionChanged 定义一个处理程序。您的基础实体也必须有一个默认构造函数。因此,当在网格中创建新项目时,将引发该事件。

      _CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e){if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
              {
      
              }
      
              if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add 
              }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-03-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多