【问题标题】:How to change MahApps.Metro dialog content template width?如何更改 MahApps.Metro 对话框内容模板宽度?
【发布时间】:2015-08-25 10:18:09
【问题描述】:

我想更改 MahApps.Metro 对话框的基本模板(或创建新的对话框类型),因为我想在狭窄的登录窗口中显示它们。现在消息中几乎所有的第二个单词都在一个新的行中,但是左右两边都有很好的大空间,我想减少它。

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

但是我如何将BaseMetroWindow 的控制模板更改为我的新模板?

【问题讨论】:

    标签: wpf xaml modal-dialog controltemplate mahapps.metro


    【解决方案1】:

    只需创建您自己的样式来覆盖对话框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}" />
    

    希望有帮助!

    【讨论】:

    • 谢谢你,它有效!顺便说一句,您认为是否可以将这种样式也应用于由 ShowMessageAsync() 函数显示的消息对话框?
    • @user3126075 是的,当然。我已经更新了我的答案。
    • 再次感谢!你帮了我很多。我已经用我添加的一些依赖属性重新编译了 mahapps 库,以防能够从代码中设置这些列宽 :) 但这是更好的解决方案。
    • 如果任何其他菜鸟来到这里并且无法理解您从复制粘贴此代码时遇到的错误,我提出了一个附加问题。如果您知道自己在做什么,它并不能解释太多,但它帮助了我。它位于here
    【解决方案2】:

    我花了一点时间来解决这个问题,但对于像我这样的新手来说,这是我使用 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 StackOverflow answer from Punker76 --->
            </Setter>
         </Style>
    
      </ResourceDictionary>
    

    创建一个名为 UserInputDialog 的 WPF 窗口,然后将 all xaml 代码替换为 customdialog 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;
            }
    
         }
    
    
      }
      }
    

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

    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 类,通过对话框视图模型构造函数传入外部对话框关闭函数

    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);
    
            }
        }
    
      }
    

    【讨论】:

    • 嘿,CustomDialog 不包含 InitializeComponent();了。你知道一些方法吗?
    【解决方案3】:

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

    【讨论】:

    • 嗨!感谢您的回答,我试图让它像这样但无法让它工作。我用一些代码更新了我的答案。这就是我放入 MetroWindow.Resources 的内容,但什么也没发生,它的侧面仍然有那些大边框。
    • 你能不能这样改行定义>
    • 我认为这不是行定义的问题,因为列太宽了。问题是 CustomDialog 仍然使用它的原始模板。顺便说一句,我用一张显示我的问题的图片更新了我的问题。
    • 我已经更改了我的代码,您现在可以尝试一下。您使用的是 dll 还是 mahapps 源?
    • 嗨!不幸的是,如果我这样做,它会引发 xaml 异常。顺便说一句,我正在使用 mahapps 的 dll。
    【解决方案4】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-05
      • 1970-01-01
      • 2012-02-08
      • 2015-07-07
      • 2018-08-21
      相关资源
      最近更新 更多