wpf 使用基于实体框架一对多属性的 ObservableCollection
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33077159/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Working with an ObservableCollection based on an Entity Framework one to many property
提问by Bob Tway
Working with WPF in MVVM. I have a ViewModel with a CurrentItem property. This is an Item object which is pulled directly from Entity Framework. Item has a collection of Property objects.
在 MVVM 中使用 WPF。我有一个带有 CurrentItem 属性的 ViewModel。这是一个直接从实体框架中提取的 Item 对象。Item 有一组 Property 对象。
public virtual ICollection<Property> Properties { get; set; }
In the View, I need users to be able to add and remove objects from this collection. To do that, I need to create an ObservableCollection<Property>, which we'll call ItemProperties.
在视图中,我需要用户能够从该集合中添加和删除对象。为此,我需要创建一个ObservableCollection<Property>,我们将其称为 ItemProperties。
There are various ways to do this. The most obvious is to add a ObservableCollection<Property>property on the ViewModel. Then populate this in the constructor, like so:
有多种方法可以做到这一点。最明显的就是ObservableCollection<Property>在ViewModel上添加一个属性。然后在构造函数中填充它,如下所示:
ItemProperties = new ObservableCollection<Property>(CurrentItem.Properties);
It's also possible to create an ObservableCollection wrapper that sits over the top of the real collection:
也可以创建一个位于真实集合顶部的 ObservableCollection 包装器:
public ObservableCollection<Property> ItemProperties
{
get
{
return new ObservableCollection<Property>(CurrentItem.Properties);
}
set
{
CurrentItem.Properties = value.ToList();
OnPropertyChanged("ItemProperties");
}
}
Which has its own problems. You can't just Add()to this collection, since it'll getfirst, meaning the collection remains unchanged. So you'd either have to spin up a new collection, add to that, and then assign its value to the property or raise the OnPropertyChangedevent outside the property. Either of which also sounds like a maintenance issue.
这有其自身的问题。你不能只Add()到这个集合,因为它会get首先,这意味着集合保持不变。因此,您要么必须启动一个新集合,添加到该集合中,然后将其值分配给该属性,要么OnPropertyChanged在该属性之外引发该事件。其中任何一个听起来也像是维护问题。
Is there a more effective way of doing this, which allows you to access the EF property list directly?
是否有更有效的方法可以让您直接访问 EF 属性列表?
采纳答案by Eldho
On this you have advantage of decoupling between data layer and Presentation , No need to spin up the collection.
在这一点上,您可以在数据层和 Presentation 之间解耦,无需启动集合。
Try a LoadedEventto load data from the server.
Sample event is below
尝试LoadedEvent从服务器加载数据。示例事件如下
private ObservableCollection<Property> _itemProperties;
public ObservableCollection<Property> ItemProperties
{
get { return _itemProperties; }
set
{
_itemProperties= value;
RaisePropertyChanged(() => ItemProperties);
}
}
The loaded event
加载的事件
var result= await Task.Run(() => MyBusiness.GetMyData());
//Map to the viewModel if necessary
ItemProperties = result;
Add to the collection
添加到集合
var isSuccess = await Task.Run(()=>MyBusiness.Insert(x));
if(isSuccess)
{
ItemProperties.Add(x);
}
回答by octavioccl
If you have access to your DbContextin your ViewModel class, you can use DbSet<TEntity>.Localproperty which it will give you an ObservableCollection<TEntity>that contains all Unchanged, Modifiedand Addedobjects that are currently tracked by the DbContextfor the given DbSet, but first you need to filter to load into memory only the PropertyItemsthat belong to your CurrentItem.
如果您有权访问您DbContext的 ViewModel 类,则可以使用DbSet<TEntity>.Local它的属性,该属性将为您提供一个ObservableCollection<TEntity>包含所有Unchanged,Modified以及Added当前由DbContext给定跟踪的对象DbSet,但首先您需要过滤以仅加载到内存PropertyItems中属于你的CurrentItem。
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();
}
}
To save the changes the only you need to do is create, for example, a commandthat calls the SaveItemPropertiesmethod. Also, it could be a good idea disable lazy loading to not load twice the ItemPropertiesrelated to your CurrentItem.
例如,要保存更改,您只需创建一个调用该方法的命令SaveItemProperties。此外,禁用延迟加载以不加载ItemProperties与您的CurrentItem.
If you need to understand more about how this works you can read this article.
如果您需要了解有关其工作原理的更多信息,可以阅读本文。
回答by Primary Key
First of all, I don't think creating an ObservableCollection for every get is a good idea. Instead I would cache it in a field. Second, for the cached instance, you will probably want to subscribe to CollectionChanged event in which you will changes will be persisted to the underlying collection.
首先,我不认为为每个 get 创建一个 ObservableCollection 是一个好主意。相反,我会将它缓存在一个字段中。其次,对于缓存实例,您可能希望订阅 CollectionChanged 事件,在该事件中您的更改将持久化到基础集合。
回答by Franck Ngako
either way is good. But what you need to do is to define an handler to the event CollectionChanged present in the Observable Collection. Your underlying entity must have a default constructor too. So when the new item will be created in the grid, that event will be raised.
无论哪种方式都很好。但是您需要做的是为 Observable 集合中存在的事件 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
}

