【问题标题】:Prism InteractionRequest + MahApps.MetroPrism InteractionRequest + MahApps.Metro
【发布时间】:2015-05-03 20:23:25
【问题描述】:

我想使用 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 元素:]
  • ConfirmationDialog 是一个UserControl,它显示对话框的内容。但是这个对话框包含在Window 中,它可能是由 Prism 自动创建的

标签: wpf prism mahapps.metro


【解决方案1】:

您必须做两件事,创建新的 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 版本。

【讨论】:

  • 看起来很有希望。谢谢
  • 这已经很好了,但是 Krzysztof suggests a solution 不需要创建自己的弹出窗口。定义一个自定义的 PopupWindowAction 就足够了。我用过,效果很好!
【解决方案2】:

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

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

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

        }


    }
}

【讨论】:

    【解决方案3】:

    我遇到了同样的问题,使用这些 cmets 我可以得到解决方案。
    我使用 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) 将 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>
    

    【讨论】:

      【解决方案4】:

      现在你不需要做任何自定义的东西,也不需要使用 InteractionRequests。

      您可以查看 MahApps.Metro.Demo.Samples(在 github 上)并检查 MVVM 的所有预配置对话框(在本例中为“Dialogs>Show InputDialog via VM”)。

      这很简单,您需要: 1) 注册 DialogCoordinator @你的引导程序(以 Autofac 为例:)

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

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-01-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-09-29
          • 1970-01-01
          相关资源
          最近更新 更多