我花了一点时间来解决这个问题,但对于像我这样的新手来说,这是我使用 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);
}
}
}