使用MVVM 以1:1将WPF中的DataGrid绑定到子导航属性(EF)
全部,
使用.Net 4和EF 4.4(DB优先)
我有一个ViewModel,它包含对EntityCollection"Entity1"的引用。
此实体与Entity2具有1:1的关系。
我的问题是,虽然我可以绑定到具有1:many或many:many关系的其他实体,但我似乎难以绑定到Entity1.Entity2。我的猜测是,这是因为Entity2不是一个集合,所以WPF不太确定该如何处理它。
因此,除了将ObservableCollection添加到我的Entity1类(它将只包含Entity2的一个实例,是1:1的关系)并绑定到它之外,我想知道是否有更好的方法来实现我的目标,即在DataGrid中显示Entity1.Entity2(而无需重新设计我的DB或创建不必要的集合,最终只包含1个对象)。
我已经尝试过将Entity1.Entity2放入CollectionViewSource中,但这似乎没有任何帮助。
谢谢。
为什么要为单个实体使用数据网格?我绝对不会在您的模型中粘贴ObservableCollection属性来覆盖这一点。
如果要显示所有实体的所有实体。您可以将数据网格的ItemsSource绑定到实体1的集合,并深入到实体2的属性。
另一种选择是构建一个用于呈现实体2数据的自定义表单。
尝试1
您绝对可以从Entity1钻取Entity2中的属性。试试这个:
- 使用Entity1的实例填充ObservableCollection您想要使用的
- 将DataGrid上的ItemsSource设置为ObservableCollection
- 将"自动生成列"设置为false您的DataGrid
- 将所需列添加到数据网格,将绑定路径设置为Entity2.PropertyName
- 您可能需要为每个Entity1临时创建一个Entity2实例,这样才能正常工作
尝试2实体框架将允许从两个表构建单个实体。您可能需要考虑该实现。最大的问题是"如果表2只扩展了表1,我真的在乎表2中是否有没有价值的记录吗?">
尝试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:在创建实体类的T4模板中,将NavigationProperty更改为:
public string NavigationProperty(NavigationProperty navigationProperty)
{
var endType = _typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType());
return string.Format(
CultureInfo.InvariantCulture,
"{0}nn {1} {2} {3}n {{n {4}getn {{n return _{3}; n }}n {5} setn {{n _{3}=value; OnSet{3}();n }}n }}nn {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以及相应的Entity类型。