使用依赖注入

时间:2015-05-21 11:55:28

标签: c# wpf mvvm unity-container prism

我创建了一个“弹出窗口”窗口,根据Prism文档使用PopupWindowAction显示该窗口。视图加载得很好,但ViewModel不是。我能找到的所有示例都只是在视图后面的代码中创建了一个简单的ViewModel。我的ViewModel需要由unity构造,以便可以注入依赖项,但是由于视图是在xaml中声明的,所以这是被绕过的:

<prism:InteractionRequestTrigger SourceObject="{Binding CustomViewRequest, Mode=OneWay}">
    <prism:PopupWindowAction>
        <prism:PopupWindowAction.WindowContent>
            <views:CustomView />
        </prism:PopupWindowAction.WindowContent>
    </prism:PopupWindowAction>
</prism:InteractionRequestTrigger>

我有一个部分解决方法,即在PopupWindowAction.WindowContent中嵌入一个ContentControl(带有一个区域)。这是有效的,当我将视图加载到区域时,ViewModel是为我创建的。但是,每次出现窗口时,它都与所有显示中的总桌面空间大小相同。

我在想我可以实现一些代码来设置弹出窗口的起始位置和尺寸,但我无法访问Window,因为这是在PopupWindowAction中为我创建的。我不想限制底层ContentControl或View的大小,否则用户将无法调整窗口大小。另外,这只是一种解决方法!

那么如何让PopupWindowAction使用依赖注入加载ViewModel?或者,如果这不是直截了当的,如何访问Window维度并将它们绑定到与ContentControl中的视图关联的viewmodel?

1 个答案:

答案 0 :(得分:2)

我遇到了同样的需求,并且能够使用自定义派生的PopupWindowAction,以允许它的WindowContent组合。根据Prism doc Unity doesn't support the TryResolve extension method,但如果您对Unity更熟悉,可能有另一种方法可以在Unity中使用TryResolve部分。

所以我定义了一个添加WindowContentType依赖项属性的ComposablePopupWindowAction。然后我重写了Invoke方法,使用服务定位器获取WindowContentType的实例(如果已定义)。

// a popupWindowAction that allows the DI to compose its view
public class ComposablePopupWindowAction : PopupWindowAction
{
    public static readonly DependencyProperty WindowContentTypeProperty =
        DependencyProperty.Register(
            "WindowContentType",
            typeof(Type),
            typeof(ComposablePopupWindowAction),
            new PropertyMetadata(null),
            v => {
                Type type = v as Type;
                Type frameworkElementType = typeof(FrameworkElement);
                // either this is not specified, or if it is then it needs to be a FrameworkElement
                return (v == null) || type.IsSubclassOf(frameworkElementType) || (type == frameworkElementType);
            }
        );

    public Type WindowContentType
    {
        get { return (Type)GetValue(WindowContentTypeProperty); }
        set { SetValue(WindowContentTypeProperty, value); }
    }

    protected override void Invoke(object parameter)
    {
        ConfigureWindowContent();

        base.Invoke(parameter);
    }

    protected void ConfigureWindowContent()
    {
        // configure the windowContent if not specified, but a type was
        if ((this.WindowContentType != null) && (this.WindowContent == null))
        {
            // this doesn't appear to be supported in Unity so might need slightly different logic here?
            var view = ServiceLocator.Current.TryResolve(this.WindowContentType);
            // if can't get thedesired type then base will use the notification
            if ((view != null) && (view.GetType() == this.WindowContentType))
            {
                this.WindowContent = view as FrameworkElement;
            }
        }
    }
}

然后正常执行interactionRequestTrigger,并指定WindowContentType属性的视图类型:

<prism:InteractionRequestTrigger SourceObject="{Binding ConfigurationPopupRequest, Mode=OneWay}">
  <inf:ComposablePopupWindowAction IsModal="True" CenterOverAssociatedObject="True" WindowContentType="{x:Type analysis:ConfigurationPopupView}" />
</prism:InteractionRequestTrigger>