如何在WPF中基于SlimWindow编写带XAML的通用对话框?
解决方案
核心方案:用UserControl做通用对话框容器,搭配你的SlimWindow实现复用
既然没法继承带XAML的Window,那就把对话框的通用布局(标题栏、按钮栏、内容区)做成一个UserControl,让每个继承自SlimWindow的对话框直接嵌入这个控件,既满足XAML+代码隐藏的需求,又能批量复用逻辑。
1. 先做通用的DialogWindowControl用户控件
这个控件把标题、内容、确定/取消按钮的布局和基础逻辑都封装好,后续所有对话框直接用它就行。
XAML模板(DialogWindowControl.xaml)
<UserControl x:Class="YourNamespace.DialogWindowControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"> <DockPanel> <!-- 标题栏:用DevExpress主题动态资源,切换主题自动变色 --> <Border DockPanel.Dock="Top" Padding="10,5" Background="{DynamicResource {dxgt:GridRowThemeKey ResourceKey=BorderFocusedBrush}}"> <TextBlock x:Name="TitleTextBlock" Text="{Binding Title, RelativeSource={RelativeSource AncestorType=UserControl}}" FontSize="16" FontWeight="Bold"/> </Border> <!-- 自定义内容区:直接承载子类传入的内容 --> <ContentPresenter x:Name="MainContentArea" Content="{Binding Content, RelativeSource={RelativeSource AncestorType=UserControl}}"/> <!-- 按钮栏 --> <StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" HorizontalAlignment="Right" Margin="10" Spacing="8"> <Button x:Name="CancelButton" Content="取消" Click="CancelButton_Click"/> <Button x:Name="OkButton" Content="确定" Click="OkButton_Click"/> </StackPanel> </DockPanel> </UserControl>
代码隐藏(DialogWindowControl.xaml.cs)
public partial class DialogWindowControl : UserControl { // 标题依赖属性,供子类绑定或直接赋值 public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(DialogWindowControl)); public string Title { get => (string)GetValue(TitleProperty); set => SetValue(TitleProperty, value); } // 自定义事件:确定/取消按钮点击,让子类写自己的逻辑 public event RoutedEventHandler OkClicked; public event RoutedEventHandler CancelClicked; public DialogWindowControl() { InitializeComponent(); } private void OkButton_Click(object sender, RoutedEventArgs e) { // 先触发子类的自定义逻辑,再默认关闭窗口 OkClicked?.Invoke(this, e); Window.GetWindow(this)?.Close(); } private void CancelButton_Click(object sender, RoutedEventArgs e) { CancelClicked?.Invoke(this, e); Window.GetWindow(this)?.Close(); } }
2. 基于SlimWindow创建具体对话框
每个对话框都继承你的SlimWindow,XAML里只需要嵌入DialogWindowControl,几行代码就能搞定,完全符合你要的“少量XAML集成”:
示例对话框XAML(ADialogWindow.xaml)
<local:SlimWindow x:Class="YourNamespace.ADialogWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:YourNamespace"> <!-- 直接用DialogWindowControl,绑定标题和事件 --> <local:DialogWindowControl Title="A Title" OkClicked="OnDialogOk" CancelClicked="OnDialogCancel"> <!-- 这里放你的自定义内容 --> <Grid Background="Green"> <TextBlock Text="Content"/> </Grid> </local:DialogWindowControl> </local:SlimWindow>
对话框代码隐藏(ADialogWindow.xaml.cs)
public partial class ADialogWindow : SlimWindow { public ADialogWindow() { InitializeComponent(); } private void OnDialogOk(object sender, RoutedEventArgs e) { // 这里写你的确定逻辑:比如校验表单、保存数据 // 举个例子: if (!ValidateForm()) { // 如果校验不通过,就阻止窗口关闭 e.Handled = true; MessageBox.Show("表单填写有误"); } } private void OnDialogCancel(object sender, RoutedEventArgs e) { // 取消逻辑:比如提示用户未保存的内容 MessageBox.Show("确定要取消吗?未保存的内容会丢失"); } private bool ValidateForm() { // 模拟表单校验 return true; } }
3. 样式定制:直接访问内部控件,不用写一堆依赖属性
不需要为每个按钮的颜色、字体写依赖属性,直接通过DialogWindowControl的控件名(比如OkButton、CancelButton)在子类里修改样式:
比如在ADialogWindow的构造函数里改确定按钮背景色:
public ADialogWindow() { InitializeComponent(); // 假设你给DialogWindowControl起了x:Name="MainDialogControl" MainDialogControl.OkButton.Background = Brushes.Orange; // 或者用DevExpress主题资源 MainDialogControl.OkButton.Background = (Brush)FindResource("{dxgt:GridRowThemeKey ResourceKey=FocusedRowBrush}"); }
或者在XAML里用样式:
<local:SlimWindow x:Class="YourNamespace.ADialogWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:YourNamespace"> <local:DialogWindowControl x:Name="MainDialogControl" Title="A Title" OkClicked="OnDialogOk"> <!-- 自定义内容 --> <Grid Background="Green"> <TextBlock Text="Content"/> </Grid> </local:DialogWindowControl> <SlimWindow.Resources> <Style TargetType="Button" x:Key="CustomOkBtnStyle"> <Setter Property="Background" Value="{DynamicResource {dxgt:GridRowThemeKey ResourceKey=FocusedRowBrush}}"/> <Setter Property="Foreground" Value="White"/> </Style> </SlimWindow.Resources> </local:SlimWindow>
然后在构造函数里应用:
MainDialogControl.OkButton.Style = (Style)Resources["CustomOkBtnStyle"];
4. DevExpress主题兼容处理
- 别把自定义控件的默认样式放在
Themes/generic.xaml,DevExpress主题切换时不会自动加载这里的样式。正确做法是给每个DevExpress主题单独建资源字典,比如Themes/MetropolisDark.xaml、Themes/Office2019Colorful.xaml,在里面定义DialogWindowControl的样式。 - 所有颜色、边框等样式都用DevExpress的
DynamicResource引用主题键,比如{DynamicResource {dxgt:GridRowThemeKey ResourceKey=BorderFocusedBrush}},这样切换主题时控件会自动跟着变。 - 启动时加载所有主题资源字典,或者用DevExpress的
ThemeManager自动管理,确保切换主题时资源能正确更新。
内容的提问来源于stack exchange,提问作者Boppity Bop
相关产品推荐
相关产品推荐

