基於WPF的自定義 MessageBox.
眾所周知WPF界面美觀.大多數WPF元素都可以簡單的修改其樣式,從而達到程序的風格統一.可是當你不得不彈出一個消息框通知用戶消息時(雖然很不建議在程序中頻繁的彈框,恩,我說的是不得不...).那個默認的System.Windows.MessageBox 就顯得太丑陋,太不搭調了.因此想到怎么搞一個新的MessageBox替換掉默認的.有童鞋說WPF擴展包中提供了新的MessageBox,那也只是把MessageBox的樣式從XP提高到了Win7樣式而已,大多還是與完全自定義樣式的WPF程序不搭調.貌似它也提供了修改樣式的接口,不過沒多少人會使用吧.也有人說,我隨便自定義一個控件,或者隨便在XAML中放一個POPUP 一個BORDER什么的 也可以模擬MessageBox的效果. 你累不?
屁話不多說了,正題開始...
/***********************************************萬能分隔線,無視上面的一切吧**************************************************************/
一:首先自定義核心的東東.消息框本身也是個窗口.那么我么就需要重新繼承一個Window類,這里起名 MessageBoxModule
class MessageBoxModule : Window { static MessageBoxModule() { // 指定自定義 控件 搜索的 樣式模板類型 DefaultStyleKeyProperty.OverrideMetadata( typeof( MessageBoxModule ), new FrameworkPropertyMetadata( typeof( MessageBoxModule ) ) ); } public MessageBoxModule() { try { this.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen; this.AllowsTransparency = true; this.WindowStyle = System.Windows.WindowStyle.None; this.ShowInTaskbar = false; this.Topmost = true; this.MouseLeftButtonDown += ( o, e ) => { this.DragMove(); }; // 為MessageBoxModule 掛載資源文件,為了使用資源中的一些 樣式定義. 注意 Uri中路徑的寫法. Resources.Source = new Uri( @"/Vito.Csharp.Wpf.Controls;component/Themes/Generic.xaml", UriKind.Relative ); if ( Resources.Contains( "MessageBoxButtonStyle" ) ) { MessageBoxModule.SetDefaultCtorButtonStyle( Resources["MessageBoxButtonStyle"] as Style ); } } catch { } } }
/Themes/Generic.xaml 樣式模板我就不多說了.這里主要介紹些Messagebox的封裝思路.
上面構造完,我們就得到了一個看起來類似消息框的窗口了. 消息框中需要有窗口標題,消息框顯示內容,和消息框的響應按鈕.接下來我們逐步完善此類.
下面我們在類中加入些屬性.
public new string Title { get { return (string)GetValue( TitleProperty ); } set { SetValue( TitleProperty, value ); } } public string Message { get { return (string)GetValue( MessageProperty ); } set { SetValue( MessageProperty, value ); } } public Brush TitleForeground { get { return (Brush)GetValue( TitleForegroundProperty ); } set { SetValue( TitleForegroundProperty, value ); } }
// 自定義響應按鈕的集合 public IList<Button> CtrlButtonCollection { get { return (IList<Button>)GetValue( CtrlButtonCollectionProperty ); } set { SetValue( CtrlButtonCollectionProperty, value ); } } public new static readonly DependencyProperty TitleProperty = DependencyProperty.Register( "Title", typeof( string ), typeof( MessageBoxModule ), new PropertyMetadata( "標題" ) ); public static readonly DependencyProperty MessageProperty = DependencyProperty.Register( "Message", typeof( string ), typeof( MessageBoxModule ), new PropertyMetadata( "" ) ); public static readonly DependencyProperty TitleForegroundProperty = DependencyProperty.Register( "TitleForeground", typeof( Brush ), typeof( MessageBoxModule ), new PropertyMetadata( DefaultTitleForeground ) ); public static readonly DependencyProperty CtrlButtonCollectionProperty = DependencyProperty.Register( "CtrlButtonCollection", typeof( IList<Button> ), typeof( MessageBoxModule ), new PropertyMetadata( new List<Button>() /*{ new Button() { Content = "確定" }, new Button() { Content = "取消" } }*/ ) );
其中 CtrlButtonCollection 屬性為本消息框的特色了,他是一組可控的響應按鈕集合.當你的消息框中不想使用默認提供的(eg: MessageBoxButton.OKCancel,MessageBoxButton.YesNo 等等)按鈕時,可以使用該集合,我們后面再說.
MessageBoxModule 類作為消息框 那么一定要有Show方法唄,那么我們來提供一組MessageBoxModule.Show方法,為了看起來很牛x 我們直接Copy System.Windows.MessageBox的部分Show方法來重寫.
public static MessageBoxResult Show( string messageBoxText ) { // .... } public static MessageBoxResult Show( string messageBoxText, string caption ) { // ....... } public static MessageBoxResult Show( string messageBoxText, string caption, MessageBoxButton button ) { // ....... } public static MessageBoxResult Show( Window owner, string messageBoxText ) { //... } public static MessageBoxResult Show( Window owner, string messageBoxText, string caption, MessageBoxButton button ) { // ...... } //特色 public static MessageBoxResult Show( Window owner, string messageBoxText, string caption, IList<MessageBoxButtonInfo> ctrlButtons ) { // .. }
為了兼容同志們曾經的MessageBox.Show方法,我們這里定義的Show方法都和默認消息框的一樣.多數情況下我們可能不需要自定義消息框按鈕的文字樣式等信息,所以我們提供了對
默認的 MessageBoxButton 枚舉的支持. 這樣我們可以只需要再想要替換新消息框的項目中加入自己的命名空間引用就可以了. 熟悉默認MessageBox的童鞋可能發現了上面的Show重載中沒有提供對 MessageBoxImage 枚舉的支持.是的,我故意沒有加入對圖片的支持. 因為我覺得加入個圖片很有可能破壞我們整個應用程序的風格.而且其實這個圖片的提示也沒有那么重要.完全是我的個人見解.如果您需要MessageBoxImage 那么您可以來完善這個.
大致思路: 因為MessageBoxImage也是枚舉,那么我們需要在我們的控件庫中加入默認的圖片對應.不過,我建議不要使用圖片資源,該用Path,路徑來替代圖片.因為如果使用某些個圖片作為默認資源,由於圖片無法動態修改前景 背景顏色,所以默認實用性不大,而路徑可以完全支持 大小,顏色的變換.(鄙人完全不建議在WPF的程序中使用任何圖片!應用程序背景,按鈕背景,特效之類的,完全可以使用WPF強大的顏色渲染和路徑支持來替代.) 根據傳入的MessageBoxImage值動態Binding指定的圖片(路徑)就行了.
上面前四個Show都是對后面的調用.所以我們大概看一下后2個SHow方法的實現.
public static MessageBoxResult Show( Window owner, string messageBoxText, string caption, MessageBoxButton button ) { var mbox = new MessageBoxModule(); mbox.Message = messageBoxText; mbox.Title = caption; mbox.Owner = owner; // 這個方法是檢測本次彈出的消息框是否使用了自定義的顏色配置,而不是使用默認提供的顏色配置.后面再說,這里無視. IsUseCustomInfoDefine( ref mbox ); if ( owner != null ) { mbox.WindowStartupLocation = WindowStartupLocation.CenterOwner; }
//這里的分支語句提供了傳入MessageBoxButton枚舉的具體響應實現. 其中CreateCtrlButton_ResultTrue,CreateCtrlButton_ResultFalse
// 等方法是創建一個按鈕 並默認了按鈕的響應 和Show方法完成后返回的結果. // 后面在看.
switch ( button ) { case MessageBoxButton.OKCancel: mbox.CtrlButtonCollection.Add( CreateCtrlButton_ResultTrue( mbox, "確定" ) ); mbox.CtrlButtonCollection.Add( CreateCtrlButton_ResultFalse( mbox, "取消" ) ); break; //break; case MessageBoxButton.YesNo: mbox.CtrlButtonCollection.Add( CreateCtrlButton_ResultTrue( mbox, "是" ) ); mbox.CtrlButtonCollection.Add( CreateCtrlButton_ResultFalse( mbox, "否" ) ); break; case MessageBoxButton.YesNoCancel: mbox.CtrlButtonCollection.Add( CreateCtrlButton_ResultTrue( mbox, "是" ) ); mbox.CtrlButtonCollection.Add( CreateCtrlButton_ResultFalse( mbox, "否" ) ); mbox.CtrlButtonCollection.Add( CreateCtrlButton_ResultFalse( mbox, "取消" ) ); break; case MessageBoxButton.OK: default: mbox.CtrlButtonCollection.Add( CreateCtrlButton_ResultTrue( mbox, "確定" ) ); break; } var result = mbox.ShowDialog(); // 本行代碼是消息框彈出的核心.ShowDialog方法會打開一個模態對話框.等待返回結果.這里的結果不是MessageBoxResult枚舉而是可空類型的布爾值(bool?) true對應着MessageBoxResult.Yes ,MessageBoxResult.OK的值.false對應着MessageBoxResult.Cancel,MessageBoxResult.No 的值.
// 了解這些我們就可以對ShowDialog方法返回值做MessageBoxResult轉換了.
switch ( button ) { //break; case MessageBoxButton.OKCancel: { return result == true ? MessageBoxResult.OK : result == false ? MessageBoxResult.Cancel : MessageBoxResult.None; } //break; case MessageBoxButton.YesNo: { return result == true ? MessageBoxResult.Yes : MessageBoxResult.No; } //break; case MessageBoxButton.YesNoCancel: { return result == true ? MessageBoxResult.Yes : result == false ? MessageBoxResult.No : MessageBoxResult.Cancel; } case MessageBoxButton.OK: default: { return result == true ? MessageBoxResult.OK : MessageBoxResult.None; } } }
private static Button CreateCtrlButton_ResultTrue( MessageBoxModule mbox, string content ) { return CreateCtrlButton( content, new RoutedEventHandler( ( o, e ) => { try { // 這里的DialogResult = true 賦值,表示着 Show方法的返回值可能為 Yes OK的值.
// 所以這個方法支持了MessageBoxButton.OKCancel,MessageBoxButton.YesNo,MessageBoxButton.OK ,MessageBoxButton.YesNoCancel
// 枚舉中的Yes Ok部分的支持. 同理另外2個方法類似.
mbox.DialogResult = true; //mbox.Close(); } catch { } } ) ); } private static Button CreateCtrlButton_ResultFalse( MessageBoxModule mbox, string content ) { return CreateCtrlButton( content, new RoutedEventHandler( ( o, e ) => { try { mbox.DialogResult = false; //mbox.Close(); } catch { } } ) ); } private static Button CreateCtrlButton_ResultNull( MessageBoxModule mbox, string content ) { return CreateCtrlButton( content, new RoutedEventHandler( ( o, e ) => { try { mbox.DialogResult = null; //mbox.Close(); } catch { } } ) ); }
到此,我們就完成了默認提供的Show方法的實現了.下面來看自定義的部分. 首先來看一下 MessageBoxButtonInfo這個類,
/// <summary> /// Vito.Csharp.Wpf.Controls.MessageBoxModule 組件中 MessageBoxButton 的自定義設置信息. /// </summary> public class MessageBoxButtonInfo { #region fields private string _contentText = ""; private MessageBoxResult _result = MessageBoxResult.OK; private Action<object> _action = null; #endregion // fields #region ctor /// <summary> /// 初始化 MIV.Bus.IEMS.MessageBox 自定義按鈕的基本信息. /// </summary> /// <param name="contentText">按鈕的文本內容</param> /// <param name="result">按鈕響應的返回結果</param> /// <param name="action">按鈕的響應動作</param> public MessageBoxButtonInfo( string contentText, MessageBoxResult result, Action<object> action ) { this._contentText = contentText; this._result = result; if ( null != action ) { this._action = action; } else { this._action = new Action<object>( ( o ) => { } ); } } #endregion // ctor #region Readonly Properties /// <summary> /// 獲取 MIV.Bus.IEMS.MessageBox 按鈕的文本內容. /// </summary> public string ContentText { get { return _contentText; } } /// <summary> /// 獲取 MIV.Bus.IEMS.MessageBox 按鈕響應的返回結果. /// </summary> public MessageBoxResult Result { get { return _result; } } /// <summary> /// 獲取 MIV.Bus.IEMS.MessageBox 按鈕的響應動作. /// </summary> public Action<object> Action { get { return _action; } } #endregion // Readonly Properties }
這個類中包含了一些自定義按鈕需要的參數.
ContentText 表示着自定義按鈕中的顯示文本(eg:例如 我想要顯示"確認""取消""是""否"之類的文字,我要顯示"不了,謝謝"字樣的類似取消功能的按鈕,那么這個參數就是攜帶該值的).
Result 指示了本個自定義的按鈕響應后文本框返回什么值(這個是之前版本的遺留,現在沒啥用處了.暫時無視.)
Action 表示本個按鈕的響應方法. 需要在按了按鈕之后做什么,那就傳遞給它吧.
下面看詳細的Show方法實現.
public static MessageBoxResult Show( Window owner, string messageBoxText, string caption, IList<MessageBoxButtonInfo> ctrlButtons ) { var mbox = new MessageBoxModule(); mbox.Message = messageBoxText; mbox.Title = caption; mbox.Owner = owner; IsUseCustomInfoDefine( ref mbox ); // 同上,檢測是否使用自定義主題顏色的配置. if ( owner != null ) { mbox.WindowStartupLocation = WindowStartupLocation.CenterOwner; } if ( null != ctrlButtons && ctrlButtons.Count > 0 ) { foreach ( var btnInfo in ctrlButtons ) { switch ( btnInfo.Result ) { case MessageBoxResult.Cancel: case MessageBoxResult.No: { var btn = CreateCtrlButton_ResultFalse( mbox, btnInfo.ContentText ); btn.Command = new MessageBoxCommand( btnInfo.Action ); // 為按鈕關聯響應動作. 這里我把Action封裝為了命令.MessageBoxCommand為自定義的命令. mbox.CtrlButtonCollection.Add( btn ); } break; case MessageBoxResult.None: { var btn = CreateCtrlButton_ResultNull( mbox, btnInfo.ContentText ); btn.Command = new MessageBoxCommand( btnInfo.Action ); mbox.CtrlButtonCollection.Add( btn ); } break; case MessageBoxResult.OK: case MessageBoxResult.Yes: default: { var btn = CreateCtrlButton_ResultTrue( mbox, btnInfo.ContentText ); btn.Command = new MessageBoxCommand( btnInfo.Action ); mbox.CtrlButtonCollection.Add( btn ); } break; } } var result = mbox.ShowDialog(); //同上一個Show方法.這里調用會顯示一個模態窗口. return MessageBoxResult.None;//為啥我說MessageBoxButtonInfo類中的Result沒用了,因為這里我始終返回None了.返回結果的目的是為了根據不同的結果做不同的處理,而這里的Action已經對其作出了響應.所以返回結果的用處不大. } else { return Show( owner, messageBoxText, caption, MessageBoxButton.OK ); } }
MessageBoxCommand 實現:
/// <summary> /// MIV.Bus.IEMS.MessageBoxModule 組件的自定義事件 /// </summary> public class MessageBoxCommand : ICommand { #region Private Fields private readonly Action<object> _command; private readonly Func<object, bool> _canExecute; #endregion #region Constructor public MessageBoxCommand( Action<object> command, Func<object, bool> canExecute = null ) { if ( command == null ) throw new ArgumentNullException( "command" ); _canExecute = canExecute; _command = command; } #endregion #region ICommand Members public void Execute( object parameter ) { _command( parameter ); } public bool CanExecute( object parameter ) { if ( _canExecute == null ) return true; return _canExecute( parameter ); } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } #endregion }
自定義命令.網上一堆文字,這里不做解釋了.
到這里,基本的Messagebox就已經完成了.我們可以使用 MessageBoxModule.Show 方法來實現消息框. 當我們敲出MessageBoxModule.的時候,我們會發現,次奧!MessageBoxModule下面彈出的東西怎么這么多? 好亂啊,各種靜態方法,DependencyProperty 之類的.而默認的MessageBox.彈出來的只有區區 Show,ReferenceEquals ,Equals三個方法.一眼就看到了Show.
再者,我們跳轉到MessageBox類時可以看到 這個類是"public sealed class MessageBox" 是密封的,並且也不是繼承Window的類.那么他是怎么實現的呢?很簡單,包裝一下而已. 隱藏掉了真正的窗口,留給我們使用的只是一個功能類而已.這樣使用者就不可以在界面中加入MessageBox.也無法搞其他的東西了.吐槽一下MS...
我們也來封裝一下我們自己的MessageBox類.如下:
/// <summary> /// 顯示消息框. /// </summary> public sealed class MessageBox { #region ctors static MessageBox() { } private MessageBox() { } #endregion // ctors #region custom settings /// <summary> /// 設置 MIV.Bus.IEMS.MessageBox 的按鈕樣式. /// </summary> /// <param name="buttonStyle"></param> public static void SetDefaultCtorButtonStyle( Style buttonStyle ) { MessageBoxModule.SetDefaultCtorButtonStyle( buttonStyle ); } /// <summary> /// 設置 MIV.Bus.IEMS.MessageBox 的一些自定義信息. /// </summary> /// <param name="mbCustomIf">MIV.Bus.IEMS.MessageBox 自定義信息結構</param> public static void SetMessageBoxCustomDefine( MessageBoxCustomInfo mbCustomIf ) { MessageBoxModule.SetMessageBoxCustomDefine( mbCustomIf ); } public static void ResetMessageBoxCustomDefine() { MessageBoxModule.ResetMessageBoxCustomDefine(); } #endregion // custom settings #region Show functions /// <summary> /// 顯示一個消息框,該消息框包含消息並返回結果。 /// </summary> /// <param name="messageBoxText">一個 System.String,用於指定要顯示的文本。</param> /// <returns>一個 System.Windows.MessageBoxResult 值,用於指定用戶單擊了哪個消息框按鈕。</returns> public static MessageBoxResult Show( string messageBoxText ) { return MessageBoxModule.Show( messageBoxText ); } /// <summary> /// 顯示一個消息框,該消息框包含消息和標題欄標題,並且返回結果。 /// </summary> /// <param name="messageBoxText">一個 System.String,用於指定要顯示的文本。</param> /// <param name="caption"> 一個 System.String,用於指定要顯示的標題欄標題。</param> /// <returns>一個 System.Windows.MessageBoxResult 值,用於指定用戶單擊了哪個消息框按鈕。</returns> public static MessageBoxResult Show( string messageBoxText, string caption ) { return MessageBoxModule.Show( messageBoxText, caption ); } /// <summary> /// 顯示一個消息框,該消息框包含消息、標題欄標題和按鈕,並且返回結果。 /// </summary> /// <param name="messageBoxText">一個 System.String,用於指定要顯示的文本。</param> /// <param name="caption"> 一個 System.String,用於指定要顯示的標題欄標題。</param> /// <param name="button">一個 System.Windows.MessageBoxButton 值,用於指定要顯示哪個按鈕或哪些按鈕。</param> /// <returns>一個 System.Windows.MessageBoxResult 值,用於指定用戶單擊了哪個消息框按鈕。</returns> public static MessageBoxResult Show( string messageBoxText, string caption, MessageBoxButton button ) { return MessageBoxModule.Show( messageBoxText, caption, button ); } /// <summary> /// 在指定窗口的前面顯示消息框。該消息框顯示消息並返回結果。 /// </summary> /// <param name="owner">一個 System.Windows.Window,表示消息框的所有者窗口。</param> /// <param name="messageBoxText">一個 System.String,用於指定要顯示的文本。</param> /// <returns> 一個 System.Windows.MessageBoxResult 值,用於指定用戶單擊了哪個消息框按鈕。</returns> public static MessageBoxResult Show( Window owner, string messageBoxText ) { return MessageBoxModule.Show( owner, messageBoxText ); } /// <summary> /// 在指定窗口的前面顯示消息框。該消息框顯示消息、標題欄標題和按鈕,並且返回結果。 /// </summary> /// <param name="owner"> 一個 System.Windows.Window,表示消息框的所有者窗口。</param> /// <param name="messageBoxText">一個 System.String,用於指定要顯示的文本。</param> /// <param name="caption"> 一個 System.String,用於指定要顯示的標題欄標題。</param> /// <param name="button">一個 System.Windows.MessageBoxButton 值,用於指定要顯示哪個按鈕或哪些按鈕。</param> /// <returns> 一個 System.Windows.MessageBoxResult 值,用於指定用戶單擊了哪個消息框按鈕。</returns> public static MessageBoxResult Show( Window owner, string messageBoxText, string caption, MessageBoxButton button ) { return MessageBoxModule.Show( owner, messageBoxText, caption, button ); } /// <summary> /// 在指定窗口的前面顯示消息框。該消息框顯示消息、標題欄標題和按鈕,並且支持自定義按鈕和動作。 /// </summary> /// <param name="owner"> 一個 System.Windows.Window,表示消息框的所有者窗口。</param> /// <param name="messageBoxText">一個 System.String,用於指定要顯示的文本。</param> /// <param name="caption"> 一個 System.String,用於指定要顯示的標題欄標題。</param> /// <param name="ctrlButtons">一組自定義的按鈕和響應動作。</param> /// <returns>始終為 MessageBoxResult.None ,返回結果在此無意義。</returns> public static MessageBoxResult Show( Window owner, string messageBoxText, string caption, IList<MessageBoxButtonInfo> ctrlButtons ) { return MessageBoxModule.Show( owner, messageBoxText, caption, ctrlButtons ); } #endregion // Show functions }
簡單吧?只是對MessageBoxModule的調用而已.為了讓使用者必須使用 MessageBox類而無法使用 MessageBoxModule 類.我們修改其限定:
internal sealed class MessageBoxModule : Window { //......... }
這回在外部看不到 MessageBoxModule了吧. MessageBox.Show(......) OY~ 安逸的很~
為了提供對自定義樣式 顏色的支持. 我們也加入了一些其他的方法:
#region Public Static Functions // 設置 消息框中響應按鈕的樣式. 靜態存儲.針對所有調用的消息框. public static void SetDefaultCtorButtonStyle( Style buttonStyle ) { CTRL_BUTTON_STYLE = buttonStyle; } // 設置 消息框中的 標題 文本 邊框 前景 背景等 以配合我們的應用程序主題風格.
// 其中 MessageBoxCustomInfo 為自定義的結構 存儲以上的信息.
public static void SetMessageBoxCustomDefine( MessageBoxCustomInfo mbCustomIf ) { if ( !default( MessageBoxCustomInfo ).Equals( mbCustomIf ) ) { MessageBoxModule.MB_CUSTOMINFO = mbCustomIf; MessageBoxModule.B_USED_CUSTOM_BRUSHES = true; } else { MessageBoxModule.MB_CUSTOMINFO = default( MessageBoxCustomInfo ); MessageBoxModule.B_USED_CUSTOM_BRUSHES = false; } } public static void ResetMessageBoxCustomDefine() { CTRL_BUTTON_STYLE = Button.StyleProperty.DefaultMetadata.DefaultValue as Style; MB_CUSTOMINFO = default( MessageBoxCustomInfo ); B_USED_CUSTOM_BRUSHES = false; } #region Show MessageBox Functions
MessageBoxCustomInfo結構:
/// <summary> /// MIV.Bus.IEMS.MessageBox 自定義信息結構. /// </summary> public struct MessageBoxCustomInfo { #region private fields // 一下布爾值表示 那些屬性為有效的. 在其有效時 才在MessageBox中賦值,否則 繼續使用默認提供的值. private bool isBackgroundChanged; private bool isTitleForegroundChanged; private bool isForegroundChanged; private bool isBorderBrushChanged; private bool isBorderThicknessChanged; private Brush mb_background; private Brush mb_title_foreground; private Brush mb_foreground; private Brush mb_borderbrush; private Thickness mb_borderthickness; #endregion // private fields #region public properties public bool IsBackgroundChanged { get { return isBackgroundChanged; } } public bool IsTitleForegroundChanged { get { return isTitleForegroundChanged; } } public bool IsForegroundChanged { get { return isForegroundChanged; } } public bool IsBorderBrushChanged { get { return isBorderBrushChanged; } } public bool IsBorderThicknessChanged { get { return isBorderThicknessChanged; } } public Brush MB_Background { get { return mb_background; } set { mb_background = value; isBackgroundChanged = true; } } public Brush MB_Title_Foreground { get { return mb_title_foreground; } set { mb_title_foreground = value; isTitleForegroundChanged = true; } } public Brush MB_Foreground { get { return mb_foreground; } set { mb_foreground = value; isForegroundChanged = true; } } public Brush MB_Borderbrush { get { return mb_borderbrush; } set { mb_borderbrush = value; isBorderBrushChanged = true; } } public Thickness MB_BorderThickness { get { return mb_borderthickness; } set { mb_borderthickness = value; isBorderThicknessChanged = true; } } #endregion // public properties }
IsUseCustomInfoDefine方法: 上面曾被2次略過....(=.=!) 判斷是否使用自定義的信息(說的就是 MessageBoxCustomInfo 啦)
private static void IsUseCustomInfoDefine( ref MessageBoxModule mbox ) {
// 判斷每一個屬性,有效時才賦值 否則忽略. if ( B_USED_CUSTOM_BRUSHES && null != mbox ) { if ( MB_CUSTOMINFO.IsBackgroundChanged ) { mbox.Background = MB_CUSTOMINFO.MB_Background; } if ( MB_CUSTOMINFO.IsBorderBrushChanged ) { mbox.BorderBrush = MB_CUSTOMINFO.MB_Borderbrush; } if ( MB_CUSTOMINFO.IsBorderThicknessChanged ) { mbox.BorderThickness = MB_CUSTOMINFO.MB_BorderThickness; } if ( MB_CUSTOMINFO.IsForegroundChanged ) { mbox.Foreground = MB_CUSTOMINFO.MB_Foreground; } if ( MB_CUSTOMINFO.IsTitleForegroundChanged ) { mbox.TitleForeground = MB_CUSTOMINFO.MB_Title_Foreground; } } }
具體調用方法:
// 修改默認的主題顏色. Vito.Csharp.Wpf.Controls.MessageBox.SetMessageBoxCustomDefine( new MessageBoxCustomInfo() { MB_Background = Brushes.Red, MB_Borderbrush = Brushes.Orange, MB_BorderThickness = new Thickness( 4 ), MB_Foreground = Brushes.White, MB_Title_Foreground = Brushes.Green } ); // 先設置自定義信息,再調用Show Vito.Csharp.Wpf.Controls.MessageBox.Show( this, "文本信息文本信息文本信息文本信息", "header", MessageBoxButton.YesNo );
自定義 Messagebox 的響應按鈕信息 的使用方法:
#region 自定義 Messagebox 的響應按鈕信息. List<MessageBoxButtonInfo> list = new List<MessageBoxButtonInfo>(); list.Add( new MessageBoxButtonInfo( "按鈕Yes", MessageBoxResult.Yes, new Action<object>( ( o ) => { // 這里是 點擊的響應動作 Action 上面已經講過. Vito.Csharp.Wpf.Controls.MessageBox.Show( "你點擊了按鈕Yes" ); } ) ) ); list.Add( new MessageBoxButtonInfo( "按鈕No", MessageBoxResult.No, new Action<object>( ( o ) => { Vito.Csharp.Wpf.Controls.MessageBox.Show( "你點擊了按鈕No" ); } ) ) ); list.Add( new MessageBoxButtonInfo( "按鈕OK", MessageBoxResult.OK, new Action<object>( ( o ) => { Vito.Csharp.Wpf.Controls.MessageBox.Show( "你點擊了按鈕OK" ); } ) ) ); list.Add( new MessageBoxButtonInfo( "按鈕Cancel", MessageBoxResult.Cancel, new Action<object>( ( o ) => { Vito.Csharp.Wpf.Controls.MessageBox.Show( "你點擊了按鈕Cancel" ); } ) ) ); list.Add( new MessageBoxButtonInfo( "按鈕Cancel1", MessageBoxResult.Cancel, new Action<object>( ( o ) => { Vito.Csharp.Wpf.Controls.MessageBox.Show( "你點擊了按鈕Cancel1" ); } ) ) ); #endregion // // 調用 r = Vito.Csharp.Wpf.Controls.MessageBox.Show( this, "文本信息文本信息文本信息文本信息文本信息文本信息", "Header", list );
好了到此就已經完成了.XAML資源也貼下一吧

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Vito.Csharp.Wpf.Controls"> <SolidColorBrush x:Key="TM_SubHeaderBackground" Color="#FF2D64A0" /> <SolidColorBrush x:Key="TM_MouseOverBorderBrush" Color="#FFA4BBD4" /> <SolidColorBrush x:Key="TM_SubTitleForeground" Color="#FFFBFBFB" /> <SolidColorBrush x:Key="TM_Textbackground" Color="#FFD9DFEC" /> <SolidColorBrush x:Key="TM_BackgroundBrush" Color="#ffd1e7ff" /> <SolidColorBrush x:Key="TM_ButtonNormalBorder" Color="Transparent" /> <LinearGradientBrush x:Key="TM_ButtonMouseOverBackground" EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="#FF0D66C4" /> <GradientStop Color="#FF328FF3" Offset="1" /> </LinearGradientBrush> <LinearGradientBrush x:Key="TM_ButtonPressBackground" EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="#FF0D66C4" /> <GradientStop Color="#FF0B498B" Offset="1" /> </LinearGradientBrush> <SolidColorBrush x:Key="TM_TransparentBrush" Color="Transparent" /> <RadialGradientBrush x:Key="MessageBoxBackground" GradientOrigin="0.158,0.301" Center="0.544,0.54" RadiusY="0.842" RadiusX="0.664"> <GradientStop Color="#FFC0D8F3" Offset="1" /> <GradientStop Color="#FFF0F6FD" /> </RadialGradientBrush> <Style x:Key="MessageBoxButtonStyle" TargetType="{x:Type Button}"> <Setter Property="Focusable" Value="False" /> <!--<Setter Property="Foreground" Value="{DynamicResource TM_SubTitleForeground}" />--> <Setter Property="Padding" Value="2" /> <Setter Property="BorderThickness" Value="1" /> <Setter Property="Background" Value="{DynamicResource TM_BackgroundBrush}" /> <Setter Property="BorderBrush" Value="{DynamicResource TM_TransparentBrush}" /> <Setter Property="Foreground" Value="{DynamicResource TM_SubHeaderBackground}" /> <Setter Property="HorizontalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="HorizontalContentAlignment" Value="Center" /> <Setter Property="VerticalContentAlignment" Value="Center" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type Button}"> <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True"> <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" /> </Border> <ControlTemplate.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="BorderBrush" TargetName="Bd" Value="#FF3399FF" /> <Setter Property="Background" TargetName="Bd" Value="{DynamicResource TM_ButtonMouseOverBackground}" /> <Setter Property="Foreground" Value="{StaticResource TM_Textbackground}" /> </Trigger> <Trigger Property="IsKeyboardFocused" Value="True"> <Setter Property="BorderBrush" TargetName="Bd" Value="#FF3399FF" /> <Setter Property="Background" TargetName="Bd" Value="{DynamicResource TM_ButtonMouseOverBackground}" /> </Trigger> <Trigger Property="IsPressed" Value="True"> <Setter Property="BorderBrush" TargetName="Bd" Value="#FF3399FF" /> <Setter Property="Background" TargetName="Bd" Value="{DynamicResource TM_ButtonPressBackground}" /> </Trigger> <Trigger Property="IsEnabled" Value="False"> <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <ControlTemplate x:Key="MessageBoxCT" TargetType="{x:Type local:MessageBoxModule}"> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="3" Margin="8"> <Border.Effect> <DropShadowEffect Color="#FF004289" Opacity="0.705" BlurRadius="12" ShadowDepth="1" /> </Border.Effect> <Grid x:Name="grid"> <Grid.RowDefinitions> <RowDefinition Height="auto" /> <RowDefinition Height="*" /> <RowDefinition Height="auto" /> </Grid.RowDefinitions> <TextBlock x:Name="textBlock" Text="{TemplateBinding Title}" Grid.Row="0" Margin="10,4" TextTrimming="CharacterEllipsis" Foreground="{TemplateBinding TitleForeground}" /> <Border Grid.Row="0" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0,0,0,1"/> <TextBlock Text="{TemplateBinding Message}" Grid.Row="1" Margin="10" TextTrimming="None" Foreground="{TemplateBinding Foreground}" TextWrapping="WrapWithOverflow" FontSize="{TemplateBinding FontSize}" /> <ItemsControl Grid.Row="2" Margin="10" ItemsSource="{TemplateBinding CtrlButtonCollection}" ScrollViewer.VerticalScrollBarVisibility="Disabled" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Padding="0,0,5,0"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <UniformGrid Rows="1" /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> </ItemsControl> </Grid> </Border> </ControlTemplate> <Style TargetType="{x:Type local:MessageBoxModule}"> <Style.Resources> <Storyboard x:Key="sbOpShow"> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="{x:Null}"> <EasingDoubleKeyFrame KeyTime="0" Value="0"/> <EasingDoubleKeyFrame KeyTime="0:0:0.15" Value="0.975"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </Style.Resources> <Style.Triggers> <EventTrigger RoutedEvent="FrameworkElement.Loaded"> <BeginStoryboard Storyboard="{StaticResource sbOpShow}"/> </EventTrigger> </Style.Triggers> <Setter Property="ResizeMode" Value="NoResize" /> <Setter Property="SizeToContent" Value="WidthAndHeight" /> <Setter Property="MinWidth" Value="330" /> <Setter Property="MinHeight" Value="145" /> <Setter Property="MaxWidth" Value="600" /> <Setter Property="MaxHeight" Value="330" /> <Setter Property="WindowStyle" Value="None" /> <Setter Property="Background" Value="{DynamicResource MessageBoxBackground}" /> <Setter Property="Foreground" Value="{StaticResource TM_SubHeaderBackground}" /> <Setter Property="AllowsTransparency" Value="True" /> <Setter Property="BorderThickness" Value="2"/> <Setter Property="BorderBrush" Value="{DynamicResource TM_SubHeaderBackground}"/> <Setter Property="Opacity" Value="0"/> <Setter Property="Template" Value="{StaticResource MessageBoxCT}" /> </Style> </ResourceDictionary>
CSDN源碼傳送門:
新版Code : WPF自定義MessageBox完善版 v2 (源碼)
NOTICE: 上面的傳送門Code為改進新版的Code, 與上面文章內容多有不同. 請注意.
感謝 @SubmarineX 童鞋提出的Bug.此問題在實際應用中已經被fixed.
各位朋友有建議我改為免費,我已經改成免費了.謝謝大家的建議!
/*******************************************************/
歡迎轉載!歡迎拍磚!
版權所有 © Vito野子
E-mail: vito2015@live.com
轉載請注明出處 http://www.cnblogs.com/Vito2008/p/MessageBox.html
/*******************************************************/