如何使用简单的注入器依赖关系使用WPF控件 [英] How to use WPF controls with Simple Injector dependencies

查看:165
本文介绍了如何使用简单的注入器依赖关系使用WPF控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在需要将资源注入到GUI控件中的场景中使用依赖注入。因为这可能是错误的地方,我有一些理由在这里做,而不是在视图模型(例如,我需要窗口句柄等)。



构造函数参数注射似乎是首选方式。因为大多数人知道WPF控件必须有一个无参数的构造函数,否则XAML不起作用,对于当前的场景,我喜欢保留我的XAML,因为它包含一些名称注册和绑定。



所以:如何在WPF + XAML方案中使用构造函数DI(如果可能,在简单注入器的情况下)?



标记扩展是否存在,或者可以让XAML解析器进行容器感知并接受具有参数的构造函数作为控件?



方案示例:

 < Grid> 
< gg:WhateverResourceNeedingViewer ItemSource = {Binding Items} />
< / Grid>

And:

 code> public class WhateverResourceNeedingViewer:ItemsControl 
{
public WhateverResourceNeedingViewer(Dep1 d,DepResource d2)
{
...
}

}


解决方案

不仅使用 SOLID 设计原则构建您的视图模型,而且要做到这一点你的意见也。用户控件的使用可以帮助您。



如果技术上可行,您建议的方法的缺点是,这种设计将违反 SRP OCP



SRP,因为您的用户控件需要的所有依赖项必须注入消费窗口/视图,而此视图可能不需要(所有)这些依赖关系。



和OCP,因为每个您添加或删除用户控件的依赖关系,您还需要从消费窗口/视图中添加或删除它。



通过用户控件,您可以组合视图,就像组成其他类(如服务,命令和查询处理程序等)一样。当涉及依赖注入时,组合应用程序的位置是< a href =http://blog.ploeh.dk/2011/07/28/CompositionRoot/ =nofollow>组成根



ContentControls in WPF是关于从应用程序中的其他内容中构建您的视图。



一个MVVM工具,如 Caliburn Micro 通常使用内容控件来使用自己的viewmodel来注入用户控件视图(读取:xaml而不使用代码)。实际上,当使用MVVM时,您将在usercontrols类的应用程序中构建所有视图,作为最佳实践。



这可能是这样的:

  public interface IViewModel< T> {} 

public class MainViewModel:IViewModel< Someclass>
{
public MainViewModel(IViewModel< SomeOtherClass> userControlViewModel)
{
this.UserControlViewModel = userControlViewModel;
}

public IViewModel< SomeOtherClass> UserControlViewModel {get;私人集合}
}

public class UserControlViewModel:IViewModel< SomeOtherClass>
{
私人只读ISomeService someDependency;

public UserControlViewModel(ISomeService someDependency)
{
this.someDependency = someDependency;
}
}

和MainView的XAML:

  // MainView 
< UserControl x:Class =WpfUserControlTest.MainView
xmlns =http:// schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x =http://schemas.microsoft.com/winfx/2006/xaml>
< Grid>
< ContentControl Name =UserControlViewModel/>
< / Grid>
< / UserControl>

// UserControl查看
< UserControl x:Class =WpfUserControlTest.UserControlView
xmlns =http://schemas.microsoft.com/winfx/2006/xaml / presentation
xmlns:x =http://schemas.microsoft.com/winfx/2006/xaml>
< Grid>
< TextBlock Text =SomeInformation/>
< / Grid>
< / UserControl>

结果将是 MainView 显示在窗口中,该窗口的 DataContext 设置为 MainViewModel 。 contentControl将被填入 UserControlView ,其 DataContext 设置为 UserControlViewModel 类。这是自动发生的,因为MVVM工具将使用通过配置进行视图模型绑定到相应的视图。 p>

如果您不使用MVVM工具,但直接将依赖关系注入到窗口类后面的代码中,那么您只需遵循相同的模式即可。在您的视图中使用ContentControl,就像上面的例子一样,在窗口的构造函数中注入 UserControl (包含一些包含参数的构造函数)。然后将ContentControl的内容属性设置为您的UserControl注入的实例。



这样看起来像:

  public partial class MainWindow:Window 
{
public MainWindow(YourUserControl userControl)
{
InitializeComponent();
//假设你有一个名为'UserControlViewModel'的内容控件
this.UserControlViewModel.Content = userControl;
}

//其他代码...
}


I'd like to use Dependency Injection in a scenario where I have to inject resources into GUI-controls. As that might be the wrong Place, I have some reasons to do it here and not in a view model (eg. I need Window handles and such).

Constructor parameter injection seems to be the preferred way. As most of you know WPF controls must have a parameter-less constructors, otherwise the XAML does not work and for the current scenario I love to keep my XAML since it contains some name registrations and bindings.

So: How can I use constructor-DI in a WPF+XAML scenario and (if possible in the case of Simple Injector)?

Does a Markup extension exist or can the XAML parser be made Container-Aware and accept parameter-having constructors as controls?

Scheme example:

<Grid>
 <gg:WhateverResourceNeedingViewer ItemSource={Binding Items}/>
</Grid>

And:

public class WhateverResourceNeedingViewer : ItemsControl
{
   public WhateverResourceNeedingViewer(Dep1 d, DepResource d2)
   {
   ...
   }
...
}

解决方案

It is good practice to not only build your viewmodels using the SOLID design principles but to do this in your views also. The usage of usercontrols can help you with this.

Downside of the approach you're suggesting, if technically possible, is that this design will violate SRP and OCP.

SRP because all dependencies your usercontrol needs must be injected in the consuming window/view while this view probably does not need (all of) these dependencies.

And OCP because every you add or delete a dependency from your usercontrol you also need to add or delete this from the consuming window/view.

With usercontrols you're able to compose the view just as you compose your other classes like services, command- and queryhandlers, etc. When it comes to dependency injection the place for composing your application is the composition root

ContentControls in WPF are all about 'composing' your view from other 'content' in your application.

A MVVM tool like Caliburn Micro typically uses contentcontrols to inject a usercontrol view (read: xaml without code behind) with it's own viewmodel. As a matter of fact, when using a MVVM you would build all views in the application from the usercontrols class, as a best practice.

This could look something like this:

public interface IViewModel<T> { }

public class MainViewModel : IViewModel<Someclass>
{
    public MainViewModel(IViewModel<SomeOtherClass> userControlViewModel)
    {
        this.UserControlViewModel = userControlViewModel;
    }

    public IViewModel<SomeOtherClass> UserControlViewModel { get; private set; }
}

public class UserControlViewModel : IViewModel<SomeOtherClass>
{
    private readonly ISomeService someDependency;

    public UserControlViewModel(ISomeService someDependency)
    {
        this.someDependency = someDependency;
    }
}

And the XAML for the MainView:

// MainView
<UserControl x:Class="WpfUserControlTest.MainView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <ContentControl Name="UserControlViewModel" />
    </Grid>
</UserControl>

// UserControl View
<UserControl x:Class="WpfUserControlTest.UserControlView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <TextBlock Text="SomeInformation"/>
    </Grid>
</UserControl>

The result will be that the MainView is displayed in a window where the DataContext of that window is set to the MainViewModel. The contentcontrol will be filled with the UserControlView with its DataContext set to the UserControlViewModel class. This automagically happens because the MVVM tool will bind the viewmodels to corresponding views using Convention over configuration.

If you don't use a MVVM tool but directly inject your dependencies in the code behind of your window class you simply can follow the same pattern. Use a ContentControl in your view, just as the above example and inject the UserControl (with a constructor containing parameters as you wish) in the constructor of the window. Then just set the Content property of the ContentControl to the injected instance of your UserControl.

That would look like:

public partial class MainWindow : Window
{
    public MainWindow(YourUserControl userControl)
    {
        InitializeComponent();
        // assuming you have a contentcontrol named 'UserControlViewModel' 
        this.UserControlViewModel.Content = userControl;
    }

    // other code...
}

这篇关于如何使用简单的注入器依赖关系使用WPF控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆