原文:《模拟MessageBox》 Posted on 2014/01/07
================================================================================
这段时间在用WPF开发项目。界面采用的是类似Win8系统的Metro风格,但是系统自带MessageBox貌似不能被Style,于是重写MessageBox。
之前一直没有写过自定义控件,就不知道怎么下手。于是从网上找了好些资料,发现了这篇博文《WPF 自定义 MessageBox (相对完善版)》。看了代码解释并运行了Demo,觉得根据实际需要改造下应该可以用到项目里来。
以前一直很好奇为什么能Style很多控件,而MessageBox却不能Style,查过.NET Reflector,发现:
public sealed class MessageBox : System.Object
MessageBox类 是直接继承自Object类,实际上是对具体细节进行了封装。
总体结构建立在Vito.K的代码基础之上,我加入的一些功能:
- 关闭按钮:
在MessageBoxModule中定义关闭命令的依赖项属性:
1 /// <summary> 2 /// 关闭命令 3 /// </summary> 4 public static readonly DependencyProperty CloseCommandProperty = 5 DependencyProperty.Register( 6 "CloseCommand", 7 typeof(RoutedCommand), 8 typeof(MessageBoxModule));
1 /// <summary> 2 /// 关闭命令 3 /// </summary> 4 public RoutedCommand CloseCommand 5 { 6 get { return (RoutedCommand)GetValue(CloseCommandProperty); } 7 set { SetValue(CloseCommandProperty, value); } 8 }
设置方法:
1 /// <summary> 2 /// 设置关闭窗口命令 3 /// </summary> 4 private void SetupCloseCommand() 5 { 6 InputGestureCollection inputGestures = 7 new InputGestureCollection(); 8 inputGestures.Add(new KeyGesture(Key.F4, ModifierKeys.Alt)); 9 10 CloseCommand = new RoutedCommand( 11 "CloseCommand", 12 typeof(MessageBoxModule), 13 inputGestures); 14 15 CommandBindings.Add( 16 new CommandBinding(CloseCommand, CloseCommandExecuted)); 17 }
在public MessageBoxModule()方法中调用即可。
在MessageBoxModule的Style文件中对该命令的使用:<Button x:Name="CloseButton" Command="{TemplateBinding CloseCommand}" .../>
- 通过标题栏拖动MessageBox:
之前写过的无边框的Windows窗体都是通过Rectangle的MouseLeftButtonDown事件来触发拖动窗体的,然后这个方法在这边行不通,于是又用这方法,还是行不通:
1 <i:Interaction.Triggers> 2 <i:EventTrigger EventName="MouseLeftButtonDown"> 3 <i:InvokeCommandAction Command="{TemplateBinding DragOverCommand}"/> 4 </i:EventTrigger/> 5 </i:Interaction.Triggers>
无意间看到《WPF编程宝典 C# 2010版》第18章中的无外观控件代码中的TemplatePart。照猫画虎地写下了以下代码:
在Style文件中:<Rectangle x:Name="PART_TitleRectangle" .../>
在MessageBoxModule类中:
在类前面加上:1 [TemplatePart(Name="PART_TitleRectangle", Type=typeof(Rectangle))] 2 internal sealed class MessageBoxModule : Window 3 { }
重载public void OnApplyTemplate()方法:
1 public override void OnApplyTemplate() 2 { 3 base.OnApplyTemplate(); 4 5 // 为TitleRectangle添加MouseLeftButtonDown事件处理程序 6 Rectangle rect = GetTemplateChild("PART_TitleRectangle") as Rectangle; 7 if (rect != null) 8 { 9 rect.MouseLeftButtonDown += (sender, e) => { DragMove(); }; 10 } 11 }
- 显示详细信息:
主要是Style中几个相关控件的Visibility的设置,依据是MessageBoxModule类中的指定值,即DependencyProperty MessageDetailProperty是否为空来选择是否启用显示相信信息功能:
1 <DockPanel x:Name="RootLayoutPanel"> 2 ... 3 <Separator Visibility="{Binding Path=Visibility, ElementName=MessageDetailTextBlock}" DockPanel.Dock="Bottom"/> 4 <!--信息区--> 5 <DockPanel x:Name="ContentDockPanel" DockPanel.Dock="Top"> 6 ... 7 <TextBlock x:Name="MessageTextBlock" Text="{TemplateBinding Message}" DockPanel.Dock="Top" /> 8 <Grid Visibility="{Binding Path=IsChecked, ElementName=DetailInfoToggleButton, Converter={converter:BooleanToVisibilityConverter}}" > 9 <TextBlock x:Name="MessageDetailTextBlock" 10 Text="{TemplateBinding MessageDetail}" 11 Visibility="{TemplateBinding MessageDetail, Converter={converter:StringToVisibilityConverter}}" 12 DockPanel.Dock="Bottom" /> 13 </Grid> 14 </DockPanel> 15 </DockPanel>
- 加入MessageBoxImage:
通过MessageBoxModule类中的DependencyProperty MessageBoxIconTypeProperty来指定显示哪种类型的图片:
1 /// <summary> 2 /// 消息框图标 3 /// </summary> 4 public static readonly DependencyProperty MessageBoxIconTypeProperty = 5 DependencyProperty.Register( 6 "MessageBoxIconType", 7 typeof(MessageBoxIcon), 8 typeof(MessageBoxModule), 9 new PropertyMetadata(MessageBoxIcon.None));
MessageBoxIcon是枚举类型类似于MessageBoxImage的一个枚举类型:
1 /// <summary> 2 /// 图标 3 /// </summary> 4 public enum MessageBoxIcon 5 { 6 None = 0, 7 Error = 0x10, 8 //Hand = 0x10, 9 //Stop = 0x10, 10 Question = 0x20, 11 Warning = 0x30, 12 //Exclamation = 0x30, 13 //Asterisk = 0x40, 14 //Information = 0x40, 15 }
在Style文件中:
1 <!--信息区--> 2 <DockPanel x:Name="ContentDockPanel" DockPanel.Dock="Top" Margin="15,10"> 3 <Image x:Name="MB_MistakeImage" Visibility="Collapsed" Source="/Controls;component/Images/messagebox_mistake.png"/> 4 <Image x:Name="MB_QueryImage" Visibility="Collapsed" Source="/Controls;component/Images/messagebox_query.png"/> 5 <Image x:Name="MB_WarningImage" Visibility="Collapsed" Source="/Controls;component/Images/messagebox_warning.png"/> 6 ... 7 </DockPanel>
用ControlTemplate.Triggers进行控制对应Image的Visibility属性:
1 <ControlTemplate.Triggers> 2 <Trigger Property="MessageBoxIconType" Value="Error"> 3 <Setter Property="Visibility" TargetName="MB_MistakeImage" Value="Visible"/> 4 </Trigger> 5 <Trigger Property="MessageBoxIconType" Value="Question"> 6 <Setter Property="Visibility" TargetName="MB_QueryImage" Value="Visible"/> 7 </Trigger> 8 <Trigger Property="MessageBoxIconType" Value="Warning"> 9 <Setter Property="Visibility" TargetName="MB_WarningImage" Value="Visible"/> 10 </Trigger> 11 </ControlTemplate.Triggers>
【END】