使用MVVM将WPF中的DataGrid绑定到子导航属性(EF)1:1

时间:2012-11-20 19:49:34

标签: c# entity-framework wpfdatagrid one-to-one

使用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中,但这似乎没有任何帮助。

感谢。

2 个答案:

答案 0 :(得分:1)

为什么要为单个实体使用数据网格?我绝对不会在你的模型中使用ObservableCollection属性来覆盖它。

如果您想要显示所有entity1的所有entity2。您可以将datagrid的ItemsSource绑定到entity1的集合,并深入到entity2的属性。

另一个选择是构建一个自定义表单来呈现entity2数据。

尝试1

<击> 您绝对可以从Entity1深入了解Entity2中的属性。 试试这个:

    <击>
  1. 使用Entity1的实例填充ObservableCollection 你想要使用。
  2. 将DataGrid上的ItemsSource设置为 那ObservableCollection
  3. 将AutoGenerateColumns设置为false 你的DataGrid
  4. 将您想要的列添加到datagrid设置绑定路径为Entity2.PropertyName
  5. 您可能必须为每个Entity1临时创建Entity2实例才能使其生效。
  6. 尝试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以及相应的实体类型。