代码之家  ›  专栏  ›  技术社区  ›  Ken Smith

将实体框架与WPF数据绑定一起使用的最佳实践[关闭]

  •  52
  • Ken Smith  · 技术社区  · 16 年前

    我正在构建我的第一个真正的WPF应用程序(也就是说,第一个被我以外的人使用的应用程序),我仍然在用WPF来做事情的最佳方法。这是一个相当简单的数据访问应用程序,它使用的是全新的实体框架,但是我还没有找到很多在线指南来找到将这两种技术(WPF和EF)结合使用的最佳方法。所以我想我应该抛开如何接近它,看看是否有人有更好的建议。

    • 我将在SQL Server 2008中使用实体框架。EF给我的印象是,它比需要的要复杂得多,而且还不成熟,但是Linq to SQL显然已经死了,所以我不妨使用MS所关注的技术。

    • 这是一个简单的应用程序,所以我还没有看到适合在它周围构建一个单独的数据层。当我想要获取数据时,我使用相当简单的linq-to-entity查询,通常是直接从我的代码后面查询,例如:

      var families = from family in entities.Family.Include("Person")
                 orderby family.PrimaryLastName, family.Tag
                 select family;
      
    • linq to entity查询返回一个iorderedqueryable结果,它不会自动反映基础数据中的更改,例如,如果我通过代码向实体数据模型添加一个新记录,则该新记录的存在不会自动反映在引用linq查询的各个控件中。因此,我将这些查询的结果放入一个可观察的集合中,以捕获基础数据更改:

      familyOC = new ObservableCollection<Family>(families.ToList());
      
    • 然后,我将ObservableCollection映射到CollectionViewSource,这样我就可以在不必返回数据库的情况下进行筛选、排序等操作。

      familyCVS.Source = familyOC;
      familyCVS.View.Filter = new Predicate<object>(ApplyFamilyFilter);
      familyCVS.View.SortDescriptions.Add(new System.ComponentModel.SortDescription("PrimaryLastName", System.ComponentModel.ListSortDirection.Ascending));
      familyCVS.View.SortDescriptions.Add(new System.ComponentModel.SortDescription("Tag", System.ComponentModel.ListSortDirection.Ascending));
      
    • 然后,我将各种控件以及不属于该CollectionViewSource的内容绑定到:

      <ListBox DockPanel.Dock="Bottom" Margin="5,5,5,5" 
          Name="familyList" 
          ItemsSource="{Binding Source={StaticResource familyCVS}, Path=., Mode=TwoWay}" 
          IsSynchronizedWithCurrentItem="True" 
          ItemTemplate="{StaticResource familyTemplate}" 
          SelectionChanged="familyList_SelectionChanged" />
      
    • 当我需要添加或删除记录/对象时,我会从实体数据模型和ObservableCollection中手动添加或删除:

      private void DeletePerson(Person person)
      {
          entities.DeleteObject(person);
          entities.SaveChanges();
          personOC.Remove(person);
      }
      
    • 我通常使用stackpanel和dockpanel控件来定位元素。有时我会使用网格,但似乎很难维护:如果要在网格顶部添加新行,必须触摸网格直接承载的每个控件,告诉它使用新行。塔克(微软似乎从未真正获得过干燥的概念。)

    • 我几乎从不使用vs wpf设计器来添加、修改或定位控件。与VS一起提供的WPF设计器对查看表单的外观有一定的帮助,但即使这样,也不是真的,特别是当您使用的数据模板没有绑定到设计时可用的数据时。如果我需要编辑我的XAML,我会像个男人一样,手动进行。

    • 我的大部分代码都是用C而不是XAML编写的。如我所说 elsewhere 除了我还不习惯在其中“思考”之外,XAML给我的印象是一种笨拙、丑陋的语言,它恰巧也伴随着糟糕的设计和智能感知支持,而且无法调试。塔克因此,每当我能清楚地看到如何在后面的C代码中做一些我不容易看到如何在XAML中做的事情时,我就用C代码来做,而不必道歉。关于如何在WPF页面中几乎从不使用代码隐藏(比如,用于事件处理)是一个很好的实践,已经有很多人写过了,但至少到目前为止,这对我来说毫无意义。如果我能使用一种漂亮、干净的语言,比如C,它有世界级的编辑器、近乎完美的智能感知和无与伦比的类型安全性,为什么我要用一种丑陋、笨拙的语言、糟糕的语法、糟糕得出奇的编辑器和几乎没有类型安全性来做一些事情呢?

    所以我就在这里。有什么建议吗?我是不是错过了什么?我真的应该考虑做什么不同的事情吗?

    6 回复  |  直到 11 年前
        1
  •  19
  •   user73993    16 年前

    您需要实现一个存储库模式来将WPF关注点与EF分离。

    然后,您可以使用泛型来降低EF到CollectionViewSource处理的复杂性。

    一个设计良好的存储库应该减少代码级别,并能够替换任何ORM(体面的测试需要)。

    这里有一些想法

    http://blog.nicktown.info/2008/12/10/using-a-collectionviewsource-to-display-a-sorted-entitycollection.aspx

        2
  •  7
  •   NotDan    16 年前

    另外,我认为您不需要在这里执行tolist()。我相信ObservableCollection()采用的IEnumerable家族已经是。如果你做了一个tolist,然后把它传递给observablecollection,那么我认为你将循环遍历所有记录两次。

    familyOC = new ObservableCollection<Family>(families.ToList());
    

    相反,试试这个,应该快一点:

    familyOC = new ObservableCollection<Family>(families);
    
        3
  •  5
  •   amaca    16 年前

    我知道你从哪里来。这个 article by Josh Smith 帮助我改变(或开始改变)心态,这样你就可以从WPF中获得一些好处,而不是把它看作一个奇怪的、阻塞的、难以调试的、不友好的框架!

        4
  •  4
  •   NotDan    16 年前

    我的建议是,如果可能的话,使用ExpressionBlend来设计界面,而不是使用代码隐藏,也不是使用Visual Studio设计器,这样可以节省大量时间。同时尝试使用C而不是XAML重新思考。如果你用“wpf”的方式来做,xaml就不那么难看了。通常,当我认为使用代码隐藏而不是XAML更容易时,这是因为我做代码隐藏的方式不对,需要重新考虑如何最好地使用WPF/XAML。一旦你习惯了,XAML就很棒了。我还使用了实体框架,这还不算太好。我更喜欢NHibernate。

        5
  •  2
  •   Nicholas Romanidis    15 年前

    我从我的博客上跟踪了这个链接,想提及我在英孚身上发现的其他东西。有点离题,但不完全是。

    在使用.include时,我注意到了一些有关ef的疯狂性能问题。MS在他们的网站上的一篇文章中解释了原因,因此我实际上已经开始将我的大部分代码转换为使用.load方法。

    因为这是一项乏味的任务,因为我找不到其他方法来完成它…我创建了自己的方法“includebyroundtrip”。它所做的是获取一个对象路径并确保加载整个路径。最终结果与使用include时相同,但是在后台,我只是调用对象图中所有属性的load。

    如果存在这样的机制,它将类似于执行order.load(“customer.address”)之类的操作。不管怎样,在我的博客上看看,告诉我你的发现。我想知道其他人是否注意到使用include的速度较慢,以及您是否有其他方法来攻击这种情况。

    有关我的解决方案的更多信息,请访问: http://blog.nicktown.info/2009/07/27/method-to-load-an-entire-object-graph-using-adonet-entity-framework.aspx .

    再次抱歉,这有点离题,但我期待您的回复。

        6
  •  1
  •   TFD    16 年前

    另一个工具可能是 BindableLINQ

    可绑定的LINQ是对LINQ的一组扩展,用于向标准LINQ查询添加数据绑定和更改传播功能。