wpf - ¿Cómo cambiar el ancho de la plantilla de contenido del diálogo MahApps.Metro?
xaml modal-dialog (4)
Me gustaría cambiar la plantilla base de los cuadros de diálogo MahApps.Metro (o crear un nuevo tipo de cuadro de diálogo), porque me gustaría mostrarlos en una ventana de inicio de sesión estrecha. En este momento, casi todas las segundas palabras en el mensaje están en una nueva fila, pero hay grandes espacios agradables en el lado derecho e izquierdo, que me gustaría reducir.
En
BaseMetroDialog.xaml
que el diálogo del mensaje está dividido en tres partes verticalmente:
25% de
espacio en el lado izquierdo,
50%
para el contenido y
25% de
espacio en el lado derecho.
Me gustaría cambiar estos números.
Pero, ¿cómo podría cambiar la plantilla de control de
BaseMetroWindow
con mi nueva?
Anule el estilo de metrodialog y combine el recurso con la ventana 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>
Me tomó un tiempo resolver esto, pero para otros novatos como yo, aquí está mi solución completamente documentada para crear cuadros de diálogo personalizados usando mahapps y MVVM. Probablemente hay aspectos que podrían mejorarse, pero esto es lo que funcionó para mí.
Declare su diccionario de recursos de diálogo en App.xaml para que esté disponible globalmente
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>
El diccionario de recursos contiene el código de reemplazo de plantilla para el diálogo personalizado
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 answer from Punker76 --->
</Setter>
</Style>
</ResourceDictionary>
Cree una ventana WPF llamada UserInputDialog y luego reemplace todo el código xaml con customdialog xaml. Estoy usando la sintaxis de Caliburn Micro para unir los botones al modelo de vista de diálogo subyacente (cal: Message.Attach =). En el caso del código de diálogo xaml, necesito especificar manualmente las combinaciones de botones, ya que por alguna razón con Caliburn Micro no es automático como en el modelo de vista principal.
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>
Y el código subyacente para 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;
}
}
}
}
Crear clase de modelo de vista específicamente para el diálogo de entrada del usuario
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);
}
//-----------------
}
}
Cree una clase de ICommand separada para pasar en la función de cierre de diálogo externo a través del constructor del modelo de vista de diálogo
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);
}
}
}
Y finalmente aquí está el código del modelo de vista principal para mostrar el cuadro de diálogo personalizado y procesar la entrada del usuario devuelta:
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);
}
}
}
Se proporciona otra solución en el rastreador de errores : no use la propiedad Contenido, use DialogTop en su lugar. Por ejemplo:
<dialogs:CustomDialog.DialogTop>
<StackPanel>
....
</StackPanel>
</dialogs:CustomDialog.DialogTop>
Coloque su contenido personalizado (por ejemplo, StackPanel) dentro de DialogTop y listo.
Simplemente cree su propio estilo que anule la
Template
diálogo (y agregue
DialogShownStoryboard
también).
<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>
El espacio de nombres aquí es
xmlns:Dialog="clr-namespace:MahApps.Metro.Controls.Dialogs;assembly=MahApps.Metro"
Ahora use este estilo personalizado, por ejemplo, para un diálogo personalizado
<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>
Captura de pantalla de la demostración principal
Actualizar
Con la última versión de MahApps.Metro ahora es posible cambiar, por ejemplo, el estilo de
MessageDialog
nivel mundial.
<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}" />
¡Espero que ayude!