使用MVVM将WPF中的DataGrid绑定到子导航属性(EF)1:1
所有
使用.Net 4和EF 4.4(数据库优先)
我有一个ViewModel,它包含对EntityCollection“Entity1”的引用。
此实体与Entity2的关系为1:1。
我的问题是,虽然我可以绑定到具有1:many或many:many关系的其他实体,但我似乎无法绑定到Entity1.Entity2。我猜这是因为Entity2不是一个集合,因此WPF不太清楚如何处理它。
所以,除了向我的Entity1类添加一个ObservableCollection(它只包含1个Entity2实例,是一个1:1的关系)并绑定到它之外,我想知道是否有更好的方法可以实现我的目标在DataGrid中显示Entity1.Entity2(不重新设计我的数据库或创建最终只包含1个对象的不必要的集合)。
我已经尝试将Entity1.Entity2放在CollectionViewSource中,但这似乎没有任何帮助。
感谢。
答案 0 :(得分:1)
为什么要为单个实体使用数据网格?我绝对不会在你的模型中使用ObservableCollection属性来覆盖它。
如果您想要显示所有entity1的所有entity2。您可以将datagrid的ItemsSource绑定到entity1的集合,并深入到entity2的属性。
另一个选择是构建一个自定义表单来呈现entity2数据。
尝试1
<击> 您绝对可以从Entity1深入了解Entity2中的属性。 试试这个:
尝试2 实体框架将允许从两个表构造单个实体。您可能想要考虑该实现。最大的问题是“如果Table2只扩展Table1,我是否真的关心Table2中是否有无价值的记录?”
尝试3 我认为您应该在您的域中引入新模型,而不是直接使用Entity1和Entity2。拥有一个可以包装Entity1和Entity2属性的类可能是最好的选择。然后,当您准备好更新数据库时,可以确定是否具有Entity2的实例。
遵循WPF应用程序框架,您可能会遇到以下情况:
//In your application layer
public class RecordsViewModel
{
public ObservableCollection<Record> Records {get;set;}
}
//In your domain layer
public class Record
{
//Properties from Entity1
//Properties from Entity2
}
//In your Data Access Layer
public class Repository
{
public IEnumerable<Record> GetRecords()
{
return db.Entity1.Include("Entity2")
.Select(e =>
new Record()
{
//object initialization
});
}
public void Update(IEnumerable<Record> records)
{
var recordIds = records.Select(r => r.Id);
var entities = db.Entity1.Include("Entity2").Where(e => recordIds.Contains(e.Id));
foreach(var record in records)
{
var entity = entities.SingleOrDefault(e => e.Id == record.Id);
if (entity == null)
{
entity = new Entity1();
db.Entity1.Add(entity);
}
//update properties on Entity1
//check if Entity2 should exist
//If so, create/update entity2
//If not, decide if you should delete entity2 or simply set Entity1.Entity2 to null
}
}
}
答案 1 :(得分:0)
ATTEMPT 1: 在创建实体类的T4模板中,将NavigationProperty更改为:
public string NavigationProperty(NavigationProperty navigationProperty)
{
var endType = _typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType());
return string.Format(
CultureInfo.InvariantCulture,
"{0}\n\n {1} {2} {3}\n {{\n {4}get\n {{\n return _{3}; \n }}\n {5} set\n {{\n _{3}=value; OnSet{3}();\n }}\n }}\n\n {6}",
string.Format(CultureInfo.InvariantCulture, "{0} _{1};",_typeMapper.GetTypeName(navigationProperty.TypeUsage), _code.Escape(navigationProperty)),
AccessibilityAndVirtual(Accessibility.ForProperty(navigationProperty)),
navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType,
_code.Escape(navigationProperty),
_code.SpaceAfter(Accessibility.ForGetter(navigationProperty)),
_code.SpaceAfter(Accessibility.ForSetter(navigationProperty)),
string.Format(CultureInfo.InvariantCulture, "partial void OnSet{0}();", _code.Escape(navigationProperty)));
}
然后添加部分Entity1类:
Partial Class Entity1:EntityBase
{
public SpecificObservableCollection<Entity2> Entity2_Observable
{
get;
set;
}
partial void OnSetEntity2()
{
Misc_Observable.Add(Entity2);
}
public class SpecificObservableCollection<T> : ObservableCollection<T>
{
public Action<T> SetValue { get; set; }
protected override void InsertItem(int index, T item)
{
if (item != null)
{
base.InsertItem(index, item);
}
}
protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
base.OnCollectionChanged(e);
if (this.Count>0)
SetValue(this[0]);
}
}
protected override void DoStuffOnAdd()
{
Entity2_Observable = new SpecificObservableCollection<Entity2>();
Entity2_Observable.SetValue = a => _Entity2 = a;
}
}
然后在EntityBase中:
public abstract class EntityBase
{
EntityBase()
{
DoStuffOnAdd();
}
protected virtual void DoStuffOnAdd() { }
}
对于IValueConverter(为了避免以1:1的关系添加太多记录)
public class CanAddValueConverter : IValueConverter
{
private Type _T;
private DataGrid _dg;
public void SetValues(DataGrid dg, Type T)
{
_T = T;
_dg = dg;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
System.Collections.IEnumerable dgIS = value as System.Collections.IEnumerable;
if (_dg != null && dgIS == _dg.ItemsSource)
{
if (_dg.Items.Count > 0)
return _dg.Items.Count <= System.Convert.ToInt32(parameter) && _dg.Items[_dg.Items.Count - 1].GetType() != _T;
else
return true;
}
else
return false;
}
}
然后在CodeBehind中,将DataGrid分配给IValueConverter以及相应的实体类型。