如何更改 MahApps.Metro 对话框内容模板宽度?

How to change MahApps.Metro dialog content template width?

我想更改 MahApps.Metro 对话框的基本模板(或创建新的对话框类型),因为我想在狭窄的范围内显示它们登录 window。现在消息中几乎所有的第二个词都在新的一行中,但是右侧和左侧有漂亮的大space,我想减少。

我在 BaseMetroDialog.xaml 中发现消息对话框垂直分为三个部分:左侧 25% space,50% 的内容和 25% space 的右侧。我想更改这些数字。

但是我怎样才能用我的新模板更改 BaseMetroWindow 的控件模板呢?

覆盖 metrodialog 样式并将资源合并到 Metro Window

<Style x:Key="newDialogStyle" BasedOn="{StaticResource MetroDialogStyle}"
           TargetType="{x:Type Dialogs:BaseMetroDialog}">
        <!-- ur design of Control Template -->
    </Style>

<Dialogs:CustomDialog Style="{StaticResource newDialogStyle}" Title="Custom Dialog which is awaitable">
        <StackPanel>
            <TextBlock Height="30" Text="This dialog allows arbitrary content. You have to close it yourself by clicking the close button below."
                           TextWrapping="Wrap"
                           Foreground="{DynamicResource AccentColorBrush}" />
            <Button Content="Close Me!"/>
        </StackPanel>
    </Dialogs:CustomDialog>

只需创建您自己的样式来覆盖对话框 Template(并添加 DialogShownStoryboard)。

<Style TargetType="{x:Type Dialog:BaseMetroDialog}"
        x:Key="NewCustomDialogStyle"
        BasedOn="{StaticResource {x:Type Dialog:BaseMetroDialog}}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Dialog:BaseMetroDialog}">
                <ControlTemplate.Resources>
                    <Storyboard x:Key="DialogShownStoryboard">
                        <DoubleAnimation AccelerationRatio=".9"
                                            BeginTime="0:0:0"
                                            Duration="0:0:0.2"
                                            Storyboard.TargetProperty="Opacity"
                                            To="1" />
                    </Storyboard>
                </ControlTemplate.Resources>
                <Grid Background="{TemplateBinding Background}">
                    <Border FocusVisualStyle="{x:Null}"
                            Focusable="False">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="*" />
                                <RowDefinition Height="Auto" />
                            </Grid.RowDefinitions>
                            <ContentPresenter Grid.Row="0"
                                                Content="{TemplateBinding DialogTop}" />
                            <Grid Grid.Row="1">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="10*" />
                                    <ColumnDefinition Width="80*" />
                                    <ColumnDefinition Width="10*" />
                                </Grid.ColumnDefinitions>
                                <!--  Content area  -->
                                <Grid Grid.Column="1"
                                        Margin="0 10 0 0">
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="Auto" />
                                        <RowDefinition Height="*" />
                                    </Grid.RowDefinitions>
                                    <TextBlock Grid.Row="0"
                                                FontSize="{DynamicResource DialogTitleFontSize}"
                                                Foreground="{TemplateBinding Foreground}"
                                                Text="{TemplateBinding Title}"
                                                TextWrapping="Wrap" />
                                    <ContentPresenter Grid.Row="1"
                                                        Content="{TemplateBinding Content}" />
                                </Grid>
                            </Grid>
                            <ContentPresenter Grid.Row="2"
                                                Content="{TemplateBinding DialogBottom}" />
                        </Grid>
                    </Border>
                </Grid>
                <ControlTemplate.Triggers>
                    <EventTrigger RoutedEvent="Loaded">
                        <EventTrigger.Actions>
                            <BeginStoryboard Storyboard="{StaticResource DialogShownStoryboard}" />
                        </EventTrigger.Actions>
                    </EventTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

这里的命名空间是

xmlns:Dialog="clr-namespace:MahApps.Metro.Controls.Dialogs;assembly=MahApps.Metro"

现在使用此自定义样式,例如对于自定义对话框

<Dialog:CustomDialog x:Key="CustomDialogTest"
                        Style="{StaticResource NewCustomDialogStyle}"
                        Title="This dialog allows arbitrary content. It will close in 5 seconds."
                        x:Name="CustomTestDialog">
    <StackPanel>
        <TextBlock Height="30"
                    Text="This dialog allows arbitrary content. You have to close it yourself by clicking the close button below."
                    TextWrapping="Wrap"
                    Foreground="{DynamicResource AccentColorBrush}" />
        <Button Content="Close Me!" />
    </StackPanel>
</Dialog:CustomDialog>

主要演示的屏幕截图

更新

使用最新版本的 MahApps.Metro 现在可以更改,例如MessageDialog 全局样式。

<Style TargetType="{x:Type Dialog:MessageDialog}"
       x:Key="NewCustomMessageDialogStyle"
       BasedOn="{StaticResource {x:Type Dialog:BaseMetroDialog}}">
  <Setter Property="Template">
    <!-- the custom template for e.g. MessageDialog -->
  </Setter>
</Style>

<Style TargetType="{x:Type Dialog:MessageDialog}" BasedOn="{StaticResource NewCustomMessageDialogStyle}" />

希望对您有所帮助!

我花了一点时间来解决这个问题,但对于像我这样的新手,这里是我使用 mahapps 和 MVVM 创建自定义对话框的完整记录解决方案。 可能有一些方面可以改进,但这对我有用。

在 App.xaml 中声明您的对话框资源字典,以便它在全球范围内可用

App.xaml

  <Application x:Class="MyAppName.App"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:MyAppName"
            xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
            xmlns:Dialog="clr-namespace:MahApps.Metro.Controls.Dialogs;assembly=MahApps.Metro"            

            >
     <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
               <ResourceDictionary>
               <ResourceDictionary  Source="DialogResource.xaml" />             
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
     </Application.Resources>
  </Application>

资源字典包含自定义对话框的模板替换代码

DialogResource.xaml

  <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                  xmlns:local="clr-namespace:MyAppName.MyResources"
                  xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
                  xmlns:Dialog="clr-namespace:MahApps.Metro.Controls.Dialogs;assembly=MahApps.Metro"                    

                  >

     <!== Override default template for Mahapps custom dialog -->

     <Style TargetType="{x:Type Dialog:BaseMetroDialog}"
        x:Key="NewCustomDialogStyle"
        BasedOn="{StaticResource {x:Type Dialog:BaseMetroDialog}}">
        <Setter Property="Template">
            <!-- Custom template xaml code goes here -- see above Whosebug answer from Punker76 --->
        </Setter>
     </Style>

  </ResourceDictionary>

创建一个名为 UserInputDialog 的 WPF window 然后用 customdialog xaml 替换 all xaml 代码。 我使用 Caliburn Micro 语法将按钮绑定到底层对话框视图模型 (cal:Message.Attach=)。 在对话框 xaml 代码的情况下,我需要手动指定按钮绑定,因为 Caliburn Micro 的某些原因它不像在主视图模型中那样自动指定。

UserInputDialog.xaml

  <Dialog:CustomDialog  
                    x:Name="MyUserInputDialog"
                    x:Class="MyAppName.UserInputDialog"
                    Style="{StaticResource NewCustomDialogStyle}"
                    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:Dialog="clr-namespace:MahApps.Metro.Controls.Dialogs;assembly=MahApps.Metro"
                    xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
                    xmlns:cal="http://www.caliburnproject.org"
                    xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"

                    >

     <!--      , diag:PresentationTraceSources.TraceLevel=High        -->

     <StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center"  >

        <Label HorizontalAlignment="Center" Margin="10" Content="{Binding MessageText}" /> 

        <TextBox    x:Name="tbInput" 
                   Width="200"
                   Margin="10"
                   Content="{Binding UserInput}"
                   HorizontalAlignment="Center"
                   KeyDown="tbInput_KeyDown"                  
                   />

        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="10,20" >

            <Button x:Name="butOK"
               Content="OK"
               Width="80"
               Margin="10,0"                
               HorizontalAlignment="Center"
               cal:Message.Attach="butOK"                
               />

            <Button x:Name="butCancel"
               Content="Cancel"             
               Width="80"
               Margin="10,0"
               HorizontalAlignment="Center"
               cal:Message.Attach="butCancel"    
               />



        </StackPanel>
     </StackPanel>

  </Dialog:CustomDialog>    

以及 UserInputDialog 的代码隐藏:

UserInputDialog.xaml.cs

  using MahApps.Metro.Controls.Dialogs;
  using System;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Input;

  namespace MyAppName
  {
     public partial class UserInputDialog : CustomDialog
     {
        public UserInputDialog()
        {
            InitializeComponent();

            MinWidth = 300;
            MinHeight = 300;

            Loaded += Dialog_Loaded;
        }

     private void Dialog_Loaded(Object sender, RoutedEventArgs e)
     {
        tbInput.Focus();
     }


     private void tbInput_KeyDown(object sender, KeyEventArgs e)
     {
        //Not strictly MVVM but prefer the simplicity of using code-behind for this
        switch (e.Key)
        {

            case Key.Enter:
               if(this.DataContext != null) (dynamic)this.DataContext.butOK();
               break;

            case Key.Escape:
               if(this.DataContext != null) (dynamic)this.DataContext.butCancel();
               break;
        }

     }


  }
  }

专门为用户输入对话框创建视图模型class

UserInputViewModel.cs

  using System;
  using System.Windows.Input;
  using Caliburn.Micro;
  using MyAppName.Models;
  using System.Security;

  namespace MyAppName.ViewModels
  {
     public class UserInputViewModel : PropertyChangedBase
     {

        private readonly ICommand _closeCommand;

        public string MessageText { get; set; }  // Message displayed to user

        public string UserInput { get; set; }   // User input returned

        public bool Cancel { get; set; }  // Flagged true if user clicks cancel button

        //Constructor
        public UserInputViewModel(Action<UserInputViewModel> closeHandler)
        {
            Cancel = false;
            _closeCommand = new SimpleCommand { ExecuteDelegate = o => closeHandler(this) };
        }

        public void butCancel()
        {
            Cancel = true;
            _closeCommand.Execute(this);
        }

        public void butOK()
        {
            Cancel = false;
            _closeCommand.Execute(this);
        }

        //-----------------
     }
  }

创建一个单独的 ICommand class 通过对话框视图模型构造函数传入外部对话框关闭函数

SimpleCommand.cs

  using System;
  using System.Windows.Input;

  namespace MyAppName.Models
  {
     public class SimpleCommand : ICommand
     {
        public Predicate<object> CanExecuteDelegate { get; set; }
        public Action<object> ExecuteDelegate { get; set; }

        public bool CanExecute(object parameter)
        {
            if (CanExecuteDelegate != null)
               return CanExecuteDelegate(parameter);
            return true; // if there is no can execute default to true
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public void Execute(object parameter)
        {
            if (ExecuteDelegate != null)
               ExecuteDelegate(parameter);
        }
     }
  }

最后是显示自定义对话框和处理返回的用户输入的主视图模型代码:-

MainViewModel.cs

  using MahApps.Metro.Controls.Dialogs;
  namespace MyAppName.ViewModels
  {
     /// <summary>
     /// The ViewModel for the application's main window.
     /// </summary>
     public class MainViewModel : PropertyChangedBase
     {


        private readonly IDialogCoordinator _dialogCoordinator;

        //Constructor
        public MainViewModel(IDialogCoordinator dialogCoordinator)
        {
            // Dialog coordinator provided by Mahapps framework 
            // Either passed into MainViewModel constructor to conform to MVVM:-

            _dialogCoordinator = dialogCoordinator;

            // or just initialise directly here
            // _dialogCoordinator = new DialogCoordinator();
        }



        public async void GetUserInput()
        {

            var custom_dialog = new UserInputDialog();

            custom_dialog.Height = 300;
            custom_dialog.Width = 400;

            var dialog_vm = new UserInputViewModel(async instance =>
            {
               await _dialogCoordinator.HideMetroDialogAsync(this, custom_dialog);
               //instance --> dialog ViewModel
               if (!(instance.Cancel || String.IsNullOrEmpty(instance.UserInput)) ProcessUserInput(instance.UserInput);
            });

            dialog_vm.MessageText = "Please type in your first name";

            custom_dialog.DataContext = dialog_vm;

            await _dialogCoordinator.ShowMetroDialogAsync(this, custom_dialog);

        }

        public ProcessUserInput(string input_message){
               Console.WriteLine("Users firstname is " + input_message);

        }
    }

  }

bug tracker 上提供了另一种解决方案:不要使用内容 属性,而是使用 DialogTop。例如:

<dialogs:CustomDialog.DialogTop>
    <StackPanel>
        ....
    </StackPanel>
</dialogs:CustomDialog.DialogTop>

将您的自定义内容(例如 StackPanel)放入 DialogTop 中,您就完成了。