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

C# 使用MVVM以1:1将WPF中的DataGrid绑定到子导航属性(EF),c#,entity-framework,wpfdatagrid,one-to-one,C#,Entity Framework,Wpfdatagrid,One To One,使用MVVM以1:1将WPF中的DataGrid绑定到子导航属性(EF) 全部, 使用.NET4和EF4.4(数据库优先) 我有一个ViewModel,其中包含对EntityCollection“Entity1”的引用 此实体与Entity2的关系为1:1 我的问题是,虽然我可以绑定到具有1:many或many:many关系的其他实体,但绑定到Entity1.Entity2时似乎有问题。我猜这是因为Entity2不是一个集合,所以WPF不太确定如何处理它 因此,除了向我的Entity1类(只包含

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

全部,

使用.NET4和EF4.4(数据库优先)

我有一个ViewModel,其中包含对EntityCollection“Entity1”的引用

此实体与Entity2的关系为1:1

我的问题是,虽然我可以绑定到具有1:many或many:many关系的其他实体,但绑定到Entity1.Entity2时似乎有问题。我猜这是因为Entity2不是一个集合,所以WPF不太确定如何处理它

因此,除了向我的Entity1类(只包含一个Entity2实例,为1:1关系)添加ObservableCollection并绑定到该类之外,我想知道是否有更好的方法来实现我的目标,即在数据网格中显示Entity1.Entity2(无需重新设计my DB或创建最终只包含1个对象的不必要集合)

我已经尝试将Entity1.Entity2放在CollectionViewSource中,但这似乎没有任何帮助


谢谢。

为什么要对单个实体使用datagrid?我绝对不会在模型中使用ObservableCollection属性来涵盖这一点

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

另一个选项是构建一个自定义表单来表示entity2数据

尝试1

您完全可以从Entity1钻取Entity2中的属性。 试试这个:

  • 用Entity1的实例填充ObservableCollection 你想用的
  • 将DataGrid上的ItemsSource设置为 那可观测的集合
  • 在上将AutoGenerateColumns设置为false 你的数据网格
  • 将所需的列添加到datagrid,并将绑定路径设置为Entity2.PropertyName
  • 您可能需要为每个Entity1临时创建一个Entity2实例,这样才能工作。
  • 尝试2 实体框架将允许一个实体从两个表中构建。您可能需要考虑这个实现。最大的问题是:“如果表2只扩展表1,我是否真的在乎是否有无价值的记录?”

    尝试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
            }
        }
    }
    
    //在应用程序层中
    公共类记录viewmodel
    {
    公共可观察收集记录{get;set;}
    }
    //在您的域层中
    公开课记录
    {
    //来自Entity1的属性
    //来自Entity2的属性
    }
    //在数据访问层中
    公共类存储库
    {
    公共IEnumerable GetRecords()
    {
    返回db.Entity1.Include(“Entity2”)
    .选择(e=>
    新纪录()
    { 
    //对象初始化
    });
    }
    公共作废更新(IEnumerable记录)
    {
    var recordIds=records.Select(r=>r.Id);
    var entities=db.Entity1.Include(“Entity2”)。其中(e=>recordIds.Contains(e.Id));
    foreach(记录中的var记录)
    {
    var entity=entities.SingleOrDefault(e=>e.Id==record.Id);
    if(实体==null)
    {
    实体=新实体1();
    db.Entity1.Add(实体);
    }
    //更新Entity1上的属性
    //检查Entity2是否应该存在
    //如果是,请创建/更新entity2
    //如果不是,请决定是删除entity2还是将Entity1.entity2设置为null
    }
    }
    }
    
    尝试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)));
    }
    
    对于IValueConverter(为了避免在1:1关系中添加过多记录)

    公共类CanadValueConverter:IValueConverter
    {
    私有类型;;
    私有数据网格;
    公共无效设置值(数据网格dg,T型)
    {
    _T=T;
    _dg=dg;
    }
    公共对象转换(对象值、类型targetType、对象参数、CultureInfo区域性)
    {
    System.Collections.IEnumerable dgIS=值为System.Collections.IEnumerable;
    如果(_dg!=null&&dgIS==_dg.ItemsSource)
    {
    如果(_dg.Items.Count>0)
    
    return _dg.Items.Count我有理由对单个实体使用DataGrid。现在,我的问题是,如果我在ItemsSource中引用Entity1,并对ItemsSource中的每一列使用Entity2.Property,这会对Entity1.Entity2为null有任何影响吗?在我看来,我必须检查Entity1.Entity2!=null,然后分配Entity2在我可以编辑之前,但问题是我希望Entity1.Entity2在大多数情况下都是空的,修改T4模板(我已经做过)似乎更容易(尽管有点讨厌)并使ObservableCollection与Entity2I am保持同步。我希望能够允许最终用户在不单击任何按钮的情况下添加行(DataGrid.AllowUserToAddress=True)如果可能的话。但是,我有一个IValueConverter,它可以防止最终用户添加太多行。更重要的是,我倾向于将我的对象放在集合中并绑定到集合。因此,用户使用的多个Entity1可能有也可能没有Entity2?正确。Entity1:Entity2是1:0或1:1关系。这不是我的ViewModel包含对Entity1(和Entity1.Entity2)的引用所做的吗?看起来像
    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;
        }
    }
    
    public abstract class EntityBase
    {
        EntityBase()
        {
            DoStuffOnAdd();
        }
        protected virtual void DoStuffOnAdd() { }
    }
    
    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;
       }
    }