如何避免耦合 XAML 视图来启动 WPF MVVM 应用程序中的代码?
我真的很喜欢通过 XAML 在视图的 DataContext 上声明 ViewModel 的灵活性,但我很难弄清楚如何将此 ViewModel 与系统的其余部分联系起来。
前任。
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ViewModels">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
这里的问题是,我的 ViewModel 通常会与系统的其他部分共享依赖关系,并且我不确定如何将另一个对象的引用注入到上面声明的 MainViewModel 中。
如果我正在进行手动依赖注入,那么我会在应用程序开始时创建一堆工厂,负责连接所有内容。
如何在 MVVM WPF 应用程序中采用相同的方法?处理我的所有 ViewModel 的最有效方法是什么?
I really like the flexibility of declaring my ViewModel on the DataContext of a View through XAML, but I am having a hard time figuring out how I can tie this ViewModel into the rest of the system.
Ex.
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ViewModels">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
The problem here, is that my ViewModels will often have and share dependencies with other parts of the system, and I am not sure how I can inject a reference of another object into the MainViewModel declared above.
If I were doing a manual sort of Dependency Injection, then I would create a bunch of factories at the start of the application responsible for wiring everything up.
How can I take this same approach in a MVVM WPF application? And what is the most effective way to get a handle on all of my ViewModels?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您可以使用视图模型优先方法,在该方法中实例化视图模型(通过构造函数注入注入任何依赖项),然后实例化视图,并以编程方式将其 DataContext 设置为视图模型实例。
我使用 Caliburn.Micro 框架,它会自动通过约定查看位置和绑定。 中找到它
您可以在 http://caliburnmicro.codeplex.com/ Rob Eisenburg 的原始“构建您自己的 MVVM 框架”演讲 很好地概述了 Caliburn.Micro 的发展历程 - http://live.visitmix.com/MIX10/会话/EX15
You can use a view model first approach, where you instantiate your view models (injecting any dependencies through constructor injection), and then instantiate your view, and set its DataContext to your view model instance programmatically.
I use the Caliburn.Micro framework which does view location and binding through conventions automatically. You can find it at http://caliburnmicro.codeplex.com/
Rob Eisenburg's original Build Your Own MVVM Framework talk gives an excellent overview of what became Caliburn.Micro - http://live.visitmix.com/MIX10/Sessions/EX15
要实现完全解耦,请在主 App 类上的
ResourceDictionary
上设置 ViewModel。有两种方法可以做到这一点,并且在大多数情况下,使用哪种方法并不重要。然而,这也是需要权衡的。方法 1
如果以编程方式完成,则必须确保字典键匹配。这会导致 XAML 中定义的字符串与以编程方式定义的字符串之间的弱耦合。并不理想,但也不是世界末日。这里的优点是能够使用构造函数注入。
业务逻辑并不关心视图是什么,并且应用程序可以以任何方式引导......使用工厂/构建器对象或任何 IOC 容器。 (只要一切都在OnStartUp函数中启动)。
方法 2
使用
Application.Resource
在App.xaml
中定义 ViewModel。使用此方法,所有键名称都将位于 XAML 中,这感觉非常好。唯一的负面结果是 .NET 自动构建 ViewModel,强制提供默认构造函数。有时需要 IOC 容器来构建对象,或者在自定义工厂/构建器中使用构造函数注入。两种方式都是有效的选择,并且通过一些密钥管理,可以使用混合和匹配来满足要求。
To achieve complete decoupling, set ViewModels on the
ResourceDictionary
found on the main App class. There are two ways to do this, and for the most part it doesn't matter which method is used. There are trade-offs however.Method 1
If it is done progamatically, you must ensure Dictionary keys match. This causes a weak coupling between the strings defined in the XAML and those defined programmatically. Not ideal, but not the end of the world either. The advantage here is that ability to use constructor injection.
The Business logic doesn't care what a View is, and the application can be Bootstrapped in any way... using factory/builder object or any IOC container. (As long as it all starts in the OnStartUp function).
Method 2
Define ViewModels in
App.xaml
usingApplication.Resource
. Using this method all key names will be located in XAML, which feels pretty nice. The only negative result is that .NET automatically builds the ViewModels, forcing the to provide default constructors. Sometimes it is desirable for the IOC container to build your objects, or use Constructor Injection in custom factories/builders.Both ways are valid options, and with a little key management, a mix and match can be used to suit requirements.
我喜欢使用在 App.xaml(或其他地方)的资源字典中定义的 DataTemplate,将 ViewModel 映射到视图,如下所示:
这具有在运行时自动将 ViewModel 分配为视图的 DataContext 的效果。在这种情况下,我将在窗口的 ViewModel 或将托管 CustomerView 的其他用户控件中实例化一个名为 myCustomerViewModel 的对象,然后在该窗口的视图中使用 ContentControl ,例如这:
I like to use a DataTemplate, defined in a resource dictionary within App.xaml (or elsewhere), to map a ViewModel to a View like this:
This has the effect of automatically assigning the ViewModel to be the view's DataContext at runtime. In this case I would instantiate an object called,say,
myCustomerViewModel
, in the ViewModel for the window or other user control that would host the CustomerView, and then in the View for that window, use a ContentControl like this:我为整个应用程序创建一个视图模型,并将其作为主窗口的数据上下文,或者(如果我不打算只有一个主窗口)将其粘贴到应用程序的资源字典中。所有启动代码都位于应用程序视图模型的构造函数内部,并且 AVM 将其他视图模型公开为属性,以便可以通过绑定来访问它们。
这是一种生硬的工具,但它具有简单的优点。
I create a view model for the entire application and either make it the data context of my main window or (if I'm not going to have just one main window) stick it in the application's resource dictionary. All of the startup code goes inside of the application view model's constructor, and the AVM exposes other view models as properties so that they can be accessed via binding.
It's kind of a blunt instrument, but it's got the virtue of simplicity.
我猜你有一个依赖项,你想像这样构造函数注入:
其次,据我了解,为了能够在 XAML 中使用 MainViewModel,您需要提供一个默认构造函数,它与注入的依赖项结合起来就是一个“混蛋注入”: “私生子注射”和“穷人注射”之间的真正区别是什么
到目前为止,我还没有找到一种方法来避免“Bastard Injection”并且仍然能够这样做:
或那样:
I guess you have a dependency that you want to constructor inject like this:
Secondly, to my understanding to be able to use your MainViewModel in XAML, you need to provide a default constructor, which in combination with the injected dependency is a "Bastard Injection": What is the real difference between "Bastard Injection" and "Poor Man's Injection"
So far I have not seen a way to avoid "Bastard Injection" and still be able to this:
or that: