我正在构建我的第一个真正的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查询的各种控件中。因此,我将这些查询的结果抛入ObservableCollection,以捕获基础数据更改:
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));
然后我将各种控件和what-not绑定到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控件来定位元素。有时我会使用Grid,但似乎很难维护:如果要在网格顶部添加新行,则必须触摸网格直接托管的每个控件,以告诉它使用新行。 Uggh。 (微软似乎从未真正获得DRY概念。)
我几乎从不使用VS WPF设计器来添加,修改或定位控件。 VS附带的WPF设计器对于查看表单的外观有点模糊,但即使如此,也不是真的,特别是如果您使用的数据模板不能绑定到可用的数据模板设计时间。如果我需要编辑我的XAML,我会像男人一样手动操作。
我的大部分真实代码都是使用C#而不是XAML。正如我之前提到的elsewhere,完全不同于我还不习惯“思考”它的事实,XAML让我觉得它是一种笨重,丑陋的语言,也恰好伴随着糟糕的设计师和智能感知支持,无法调试。 Uggh。因此,每当我能够清楚地看到如何在C#代码中执行某些操作时,我无法轻易地看到如何在XAML中执行操作,而是在C#中执行此操作,并且没有道歉。关于如何在WPF页面中使用代码隐藏(例如,用于事件处理)这是一个很好的做法,已经有很多文章,但至少到目前为止,这对我来说毫无意义。当我能使用像C#一样漂亮,干净的语言,拥有世界一流的编辑器,近乎完美的时候,我为什么要用一种丑陋,笨重的语言做一些语法,一个令人难以置信的语法,一个令人惊讶的糟糕的编辑器,几乎没有类型的安全性intellisense,无与伦比的安全性?
这就是我所在的地方。有什么建议?我错过了这方面的任何重要部分吗?我应该考虑采取哪些不同的做法?
答案 0 :(得分:19)
您需要实现存储库模式以从EF
中分离WPF问题然后,您可以使用泛型来降低EF到CollectionViewSource处理的复杂性
设计良好的存储库应该降低代码级别并允许替换任何ORM(适当的测试需要)
这方面的一些想法就在这里
答案 1 :(得分:7)
另外,我认为你不需要在这里做一个ToList()。我相信ObservableCollection()接受一个家庭已经存在的IEnumerable。如果您执行ToList,然后将其传递给ObservableCollection,那么我认为您将遍历所有记录两次。
familyOC = new ObservableCollection<Family>(families.ToList());
相反,试试这个,这应该快一点:
familyOC = new ObservableCollection<Family>(families);
答案 2 :(得分:5)
我知道你来自哪里。这个article by Josh Smith帮助我改变(或开始改变)心态,这样你就可以从WPF中获益,而不是把它视为一个奇怪的,阻碍的,难以调试和不友好的框架!
答案 3 :(得分:4)
我的建议是,如果可能的话,使用Expression Blend来设计你的界面,而不是使用Visual Behind,而不是使用Visual Studio设计器,它将为你节省大量的时间。还尝试重新考虑使用C#而不是xaml。如果您使用“WPF Way”,Xaml就不那么难看了。很多时候,当我认为使用后面的代码而不是xaml更容易时,这是因为我做错了方法并且需要重新思考它应该如何最好地使用WPF / xaml。一旦你习惯了,Xaml就很棒了。我还使用了实体框架,但它还不是很好。我更喜欢NHibernate。
答案 4 :(得分:2)
我在我的博客中关注了此链接,并希望提及我在EF中找到的其他内容。有点偏离主题,但不完全。
我注意到在使用.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。
再次,抱歉这有点偏离主题,但我期待你的回复。
答案 5 :(得分:1)
另一个工具可能是BindableLINQ
Bindable LINQ是LINQ的一组扩展,用于添加数据绑定并将传播功能更改为标准LINQ查询