Prism InteractionRequest + MahApps.Metro

时间:2015-05-03 20:23:25

标签: wpf prism mahapps.metro

我想使用WPF Prism + MahApps.Metro创建一个弹出窗口或对话框,其中包含选择确认(确定,取消)

我创建了自定义互动:

<i:Interaction.Triggers>
    <interactionRequest:InteractionRequestTrigger SourceObject="{Binding DeleteConfirmationRequest, Mode=OneWay}">
        <interactionRequest:PopupWindowAction>
            <interactionRequest:PopupWindowAction.WindowContent>
                <confirmation:ConfirmationDialog/>
            </interactionRequest:PopupWindowAction.WindowContent>
        </interactionRequest:PopupWindowAction>
    </interactionRequest:InteractionRequestTrigger>
</i:Interaction.Triggers>

但是这将创建一个默认的WPF窗口,它不是城域风格的。如何将其更改为MahApps.Metro窗口?

也许,另一种方法是使用MahApps.Metro Dialogs,但我不知道如何在Prism中使用它。

有什么想法吗?

5 个答案:

答案 0 :(得分:5)

您必须做两件事,创建新的 MetroWindow 对话框,然后覆盖 PopupWindowAction 以使用它们。这听起来很长,但只需要10分钟:

首先,创建自己的确认和通知窗口,继承自 MetroWindow ,就像任何其他 MetroWindow 一样。您可以从棱镜源复制原始的确认和通知窗口,并根据mahapps quick start的建议进行更改。 因此,确认窗口将类似于:

<Controls:MetroWindow x:Class="MyApp.DefaultPopupWindows.DefaultConfirmationWindow"
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
           xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
           MinWidth="300" MinHeight="150"
           Title="{Binding Title}" 
           BorderBrush="{DynamicResource AccentColorBrush}"                      
           BorderThickness="1">

    <Grid x:Name="LayoutRoot" Margin="5">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <ContentControl HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="0" Content="{Binding Content}"/>

        <StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right">
            <Button x:Name="OkButton" Content="OK" Width="75" Height="25" HorizontalAlignment="Right" Margin="0,10,0,0" Click="OkButton_Click" />
            <Button x:Name="CancelButton" Content="Cancel" Width="75" Height="25" HorizontalAlignment="Right" Margin="20,10,0,0" Click="CancelButton_Click" />
        </StackPanel>

    </Grid>
</Controls:MetroWindow>

背后的相关代码:

using MahApps.Metro.Controls;
using Microsoft.Practices.Prism.Interactivity.InteractionRequest;
using System.Windows;

namespace MyApp.DefaultPopupWindows
{
    /// <summary>
    /// Interaction logic for ConfirmationChildWindow.xaml
    /// </summary>
    public partial class DefaultConfirmationWindow : MetroWindow
    {
        /// <summary>
        /// Creates a new instance of ConfirmationChildWindow.
        /// </summary>
        public DefaultConfirmationWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Sets or gets the <see cref="IConfirmation"/> shown by this window./>
        /// </summary>
        public IConfirmation Confirmation
        {
            get
            {
                return this.DataContext as IConfirmation;
            }
            set
            {
                this.DataContext = value;
            }
        }

        private void OkButton_Click(object sender, RoutedEventArgs e)
        {
            this.Confirmation.Confirmed = true;
            this.Close();
        }

        private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
            this.Confirmation.Confirmed = false;
            this.Close();
        }
    }
}

接下来,您将创建自己的 PopupWindowAction ,扩展棱镜中的那个。在该类中,您将覆盖GetWindow函数:

protected override Window GetWindow(INotification notification)
{
    MetroWindow wrapperWindow;

    if (this.WindowContent != null)
    {
        wrapperWindow = new MetroWindow();

        // If the WindowContent does not have its own DataContext, it will inherit this one.
        wrapperWindow.DataContext = notification;
        wrapperWindow.Title = notification.Title;

        this.PrepareContentForWindow(notification, wrapperWindow);
    }
    else
    {
        wrapperWindow = this.CreateDefaultWindow(notification);
    }

    return wrapperWindow;
}

您还必须为&#34; CreateDefaultWindow&#34;提供您自己的实施。这将创建相应窗口的新 MetroWindow 版本:

protected new MetroWindow CreateDefaultWindow(INotification notification)
{
    MetroWindow window = null;

    if (notification is IConfirmation)
    {
        window = new DefaultPopupWindows.DefaultConfirmationWindow() { Confirmation = (IConfirmation)notification };
    }
    else
    {
        window = new DefaultPopupWindows.DefaultNotificationWindow() { Notification = notification };
    }

    return window;
}

最后,在您自己的视图/窗口中的 InteractionRequest 中,指定这个新的 PopupWindowAction ,而不是棱镜版本。

答案 1 :(得分:3)

我不知道你是否可以在prism 5.0中使用它,但是使用新的Prism 6.0(Github)你有一个虚拟方法CreateWindow,你可以子类化PopupWindowAction并覆盖它创建Metro窗口。我正在使用以下代码:

namespace KPP.Vision.Infrastructure.Interactions
{
    public class MetroPopupWindowAction:PopupWindowAction
    {

        protected override Window CreateWindow()
        {
            return new MetroPopupWindowView();

        }


    }
}

答案 2 :(得分:2)

我遇到了同样的问题,我可以通过这些评论得到解决方案 我使用Prism 6

1)首先重写PopupWindowAction

/// <summary>
        ///     it creates a new metro window instead of a window
        /// </summary>
        /// <returns></returns>
        protected override Window CreateWindow()
        {
            return new MetroPopupWindow();
        }

        /// <summary>
        /// Creates a window with the notification type
        /// </summary>
        /// <param name="notification"></param>
        /// <returns></returns>
        private new Window CreateDefaultWindow(INotification notification)
        {
            Window window = null;

            if (notification is IConfirmation)
            {
                window = new MetroConfirmationWindow {Confirmation = (IConfirmation) notification};
            }
            else
            {
                window = new MetroNotificationWindow {Notification = notification};
            }

            return window;
        }

        /// <summary>
        ///     Returns the window to display as part of the trigger action.
        /// </summary>
        /// <param name="notification">The notification to be set as a DataContext in the window.</param>
        /// <returns></returns>
        protected override Window GetWindow(INotification notification)
        {
            Window wrapperWindow;

            if (WindowContent != null)
            {
                wrapperWindow = CreateWindow();

                if (wrapperWindow == null)
                    throw new NullReferenceException("CreateWindow cannot return null");

                // If the WindowContent does not have its own DataContext, it will inherit this one.
                wrapperWindow.DataContext = notification;
                wrapperWindow.Title = notification.Title;

                PrepareContentForWindow(notification, wrapperWindow);
            }
            else
            {
                wrapperWindow = CreateDefaultWindow(notification);
            }

            // If the user provided a Style for a Window we set it as the window's style.
            if (WindowStyle != null)
                wrapperWindow.Style = WindowStyle;

            return wrapperWindow;
        }

2)创建MetroWindow,MetroNotificationWindow和MetroConfirmationWindow based in the default windows

实施例: 的 MetroPopupWindow.xaml

<controls:MetroWindow x:Class="MetroPopupWindow"
                      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"                          
                      xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"
                      mc:Ignorable="d"
                      Title="MetroPopupWindow" TitleCaps="False" SizeToContent="WidthAndHeight">
    <Grid>
        <ContentControl HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="0"
                        Content="{Binding Content}" />
    </Grid>
</controls:MetroWindow>

MetroNotificationWindow.xaml

<controls:MetroWindow x:Class="MetroNotificationWindow"
                      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"                          
                      xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"                          
                      Title="Web Studio" TitleCaps="False" SizeToContent="WidthAndHeight">
    <Grid x:Name="LayoutRoot" Margin="5">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <ContentControl HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="0"
                        Content="{Binding Content}" />
        <Button x:Name="OKButton" Content="{lex:Loc Ok}" Width="75" Height="25" HorizontalAlignment="Right"
                Margin="0,10,0,0" Grid.Row="1" Click="OKButton_Click" IsDefault="True" />

    </Grid>
</controls:MetroWindow>

3)更改MetroPopupWindowAction的PopupWindowAction的所有引用 例如:

    <i:Interaction.Triggers>
    <!-- Trigger listening for the "Raised" event on the source object (of type IInteractionRequest) -->
    <interactionRequest:InteractionRequestTrigger
        SourceObject="{Binding SaveChangesConfirmationRequest, Mode=OneWay}">
        <!-- That window will be show as a modal dialog and centered over this window -->
        <windowAction:MetroPopupWindowAction IsModal="True" CenterOverAssociatedObject="True" />
    </interactionRequest:InteractionRequestTrigger>
</i:Interaction.Triggers>

答案 3 :(得分:2)

现在您不需要做任何自定义内容,也不需要使用InteractionRequests。

您可以查看MahApps.Metro.Demo.Samples(在github上)并检查MVVM的所有预配置对话框(在这种情况下,“对话框&gt;通过VM显示InputDialog”)。

这很简单,你需要: 1)注册DialogCoordinator @你的引导程序(使用Autofac的例子:)

builder.RegisterType<DialogCoordinator>().As<IDialogCoordinator>().SingleInstance();

2)使用Window中的附加属性,使用对话框子系统注册视图模型。 (这需要放在要从中调用对话框的ViewModel的View.xaml中:

<UserControl x:Class="MyNamespace.Views.MyView"
             xmlns:dialogs="clr-namespace:MahApps.Metro.Controls.Dialogs;assembly=MahApps.Metro"
             dialogs:DialogParticipation.Register="{Binding}"
             .../>

3)@您的ViewModel,确保您对DialogCoordinator接口有一个只读引用,用于依赖注入:

namespace MyNamespace
{
    class MyViewModel : BindableBase
    {
        readonly IDialogCoordinator _dialogCoordinator;

        public MyViewModel (IDialogCoordinator dcFromDependencyInjection)
        {
            _dialogCoordinator = dcFromDependencyInjection;
            [rest of your constructor code here]
        }
    }
}

4)现在,只要您需要从ViewModel调用对话框(InputDialog,ProgressDialog,MessageDialog甚至自己的CustomDialog),您只需要:

async void MyInputDialog()
{
    await _dialogCoordinator.ShowInputAsync(this, "Dialog Title", "Dialog Message")
                            .ContinueWith(t => Console.WriteLine(t.Result));
}

答案 4 :(得分:0)

我猜PopupWindowAction创建了一个窗口(其值为WindowContent),因此您必须更改其实现或编写自己的实现。