Prism InteractionRequest + MahApps.Metro

6

我希望使用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窗口,它不是Metro风格的。如何将其更改为MahApps.Metro窗口?
也许,另一种方法是使用MahApps.Metro对话框,但我不知道如何与Prism一起使用。
有什么想法吗?

可能现在您需要创建一个自定义的“confirmation:ConfirmationDialog”元素:] - AgentFire
1
ConfirmationDialog是一个UserControl,它显示对话框的内容。但是这个对话框被包含在一个Window中,这个Window可能是由Prism自动创建的。 - Tomasz
5个回答

5
你需要做两件事情,创建新的 MetroWindow 对话框,然后重写 PopupWindowAction 以使用它们。听起来有些啰嗦,但只需要10分钟:
首先,创建自己的确认和通知窗口,这些窗口从 MetroWindow 继承,就像任何其他的 MetroWindow 一样。你可以从 Prism 源代码中复制原始的确认和通知窗口,然后根据 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,它是prism中的一个扩展。在该类中,您需要重写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;
}

您还需要自己提供“CreateDefaultWindow”的实现,该实现将创建适当窗口的新 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,而不是prism版本。

看起来很有前途。谢谢。 - Tomasz
1
这已经非常好了,但是Krzysztof提出了一个解决方案,不需要创建自己的弹出窗口。定义一个自定义PopupWindowAction就足够了。我已经使用过它,效果非常棒! - Informagic

3

我不确定在prism 5.0中能否实现,但使用新的Prism 6.0 (Github),你可以通过虚方法CreateWindow来创建Metro窗口,只需要继承PopupWindowAction并重写该方法即可。以下是我的代码:

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

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

        }


    }
}

2
现在你不需要做任何定制的东西,也不需要使用InteractionRequests。
你可以查看MahApps.Metro.Demo.Samples(在 github上),并检查所有预配置的MVVM对话框(在这种情况下为“Dialogs>通过VM显示InputDialog”)。
这很简单,你需要: 1)在你的引导程序中注册DialogCoordinator(例如使用Autofac的示例:)
builder.RegisterType<DialogCoordinator>().As<IDialogCoordinator>().SingleInstance();

2)在您的窗口中使用附加属性来向对话框子系统注册您的视图模型。(这需要放置在您想要从其中调用对话框的视图模型的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]
        }
    }
}

现在,如果您需要从ViewModel调用对话框(InputDialog、ProgressDialog、MessageDialog,甚至是自己的CustomDialog),您只需要:
async void MyInputDialog()
{
    await _dialogCoordinator.ShowInputAsync(this, "Dialog Title", "Dialog Message")
                            .ContinueWith(t => Console.WriteLine(t.Result));
}

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,基于默认窗口

例如: 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) 将所有PopupWindowAction的引用更改为MetroPopupWindowAction
例如:

    <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>

0

我猜测PopupWindowAction创建窗口(使用WindowContent的值作为其内容),因此您必须更改其实现或编写自己的代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接