0

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

全部,

使用 .Net 4 和 EF 4.4(数据库优先)

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

该实体与 Entity2 具有 1:1 的关系。

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

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

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

谢谢。

4

2 回答 2

1

为什么要为单个实体使用数据网格?我绝对不会在您的模型中粘贴 ObservableCollection 属性来涵盖这一点。

如果您想显示所有 entity1 的所有 entity2。您可以将数据网格的 ItemsSource 绑定到 entity1 的集合并深入了解 entity2 的属性。

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

尝试 1

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

  1. 使用您要使用的 Entity1 的实例填充 ObservableCollection。
  2. 将 DataGrid 上的 ItemsSource 设置为 ObservableCollection
  3. 在 DataGrid 上将 AutoGenerateColumns 设置为 false
  4. 将所需的列添加到数据网格中,将绑定路径设置为 Entity2.PropertyName
  5. 您可能必须为每个 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
        }
    }
}
于 2012-11-20T19:53:48.450 回答
0

尝试 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 以及相应的实体类型。

于 2012-11-20T21:08:21.640 回答