Как изменить ширину шаблона содержимого диалога MahApps.Metro?

Я хотел бы изменить базовый шаблон диалоговых окон MahApps.Metro (или создать новый тип диалогового окна), поскольку я хотел бы отображать их в узком окне входа в систему. Сейчас почти все вторые слова в сообщении находятся в новой строке, но есть хорошие большие пробелы справа и слева, которые я хотел бы уменьшить.

Слишком широкий отступ по бокам

Я обнаружил в BaseMetroDialog.xaml, что диалоговое окно сообщения разделено на три части по вертикали: 25% пространство слева, 50% для содержимого и 25%< /strong> пробел справа. Я хотел бы изменить эти цифры.

Но как я могу изменить шаблон управления BaseMetroWindow на мой новый?


person user2042930    schedule 10.06.2015    source источник


Ответы (4)


Просто создайте свой собственный стиль, который переопределяет диалоговое окно 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}" />

введите здесь описание изображения

Надеюсь, это поможет!

person punker76    schedule 12.06.2015
comment
А, спасибо, работает! Кстати, как вы думаете, можно ли применить этот стиль и к диалогам сообщений, которые показывает функция ShowMessageAsync()? - person user2042930; 12.06.2015
comment
@ user3126075 да, конечно. я обновил свой ответ. - person punker76; 12.06.2015
comment
Спасибо еще раз! Вы мне очень помогли. Я уже перекомпилировал библиотеки mahapps с некоторыми свойствами зависимостей, которые я добавил на случай, если можно будет установить ширину этих столбцов из кода :) Но это гораздо лучшее решение. - person user2042930; 12.06.2015
comment
На случай, если сюда попадут другие новички и у них возникнут проблемы с пониманием ошибок, возникающих при копировании этого кода, я задал дополнительный вопрос к этому. Это мало что объясняет, если вы знаете, что делаете, но мне это помогло. Он находится здесь - person trueCamelType; 23.10.2015

Мне потребовалось некоторое время, чтобы разобраться с этим, но для таких же новичков, как я, вот мое полностью документированное решение для создания настраиваемых диалоговых окон с использованием 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>

Создайте окно WPF с именем UserInputDialog, затем замените весь код xaml на customdialog xaml. Я использую синтаксис Caliburn Micro для привязки кнопок к модели представления диалогового окна (cal:Message.Attach=). В случае диалогового кода xaml мне нужно вручную указать привязки кнопок, так как по какой-то причине с Caliburn Micro это не происходит автоматически, как в модели основного представления.

Усеринпутдиалог.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:

Усеринпутдиалог.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;
        }

     }


  }
  }

Создайте класс модели представления специально для диалогового окна ввода пользователя

Усеринпутвиевмодел.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);

        }
    }

  }
person Hugh    schedule 30.07.2016
comment
Эй, CustomDialog не содержит InitializeComponent(); больше. Вы знаете какой-нибудь обходной путь? - person TechCrap; 09.05.2017

Переопределить стиль метродиалога и объединить ресурс с окном Metro.

<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>
person ReeganLourduraj    schedule 10.06.2015
comment
Привет! Спасибо за ваш ответ, я пытался сделать это так, но не смог заставить его работать. Я обновил свой ответ некоторым кодом. Это то, что я поместил в MetroWindow.Resources, но ничего не произошло, у него все еще есть эти большие рамки по бокам. - person user2042930; 10.06.2015
comment
Не могли бы вы изменить вот так: Grid.RowDefinitions› ‹RowDefinition Height=10 /› ‹RowDefinition Height=* /› ‹RowDefinition Height=Auto /› ‹/Grid.RowDefinitions› - person ReeganLourduraj; 10.06.2015
comment
Я думаю, что проблема не в определениях строк, так как столбцы слишком широкие. Проблема в том, что CustomDialog все еще использует свой оригинальный шаблон. Кстати, я обновил свой вопрос изображением, показывающим мою проблему. - person user2042930; 10.06.2015
comment
Я изменил свой код, не могли бы вы попробовать сейчас. Используете ли вы библиотеки DLL или источник mahapps? - person ReeganLourduraj; 10.06.2015
comment
Привет! К сожалению, он выдает исключение xaml, если я делаю это так. Кстати, я использую dll mahapps. - person user2042930; 11.06.2015
comment
правильно ли вы ссылаетесь на стили из dll? то есть пространство имен dll - person ReeganLourduraj; 11.06.2015
comment
Я думаю, что пространства имен указаны хорошо, так как появляется диалоговое окно. - person user2042930; 11.06.2015

Другое решение представлено в системе отслеживания ошибок: не используйте свойство Content, используйте вместо этого DialogTop. Например:

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

Поместите свой собственный контент (например, StackPanel) внутрь DialogTop, и все готово.

person Mikhail Tumashenko    schedule 20.09.2016