您的位置:首页 > 职场人生

在silverlight中定制自己的MessageBox(消息框) 推荐

2008-09-22 09:30 405 查看
 在silverlight中,如果想使用“消息框”可使用下面的方法,即:HtmlPage.Window.Alert("消息框内容")。如果想要显示更加复杂的内容或定义消息框样式的话,基本上没有什么好的方法。最近在网上看到了一篇文章,该文章的作者也谈到了上面所说的话题,相关链接如下:  

The Curious Incident of the MessageBox in the Silverlight App

在线演示如下:http://silverlight.services.live.com/invoke/72193/messagebox/iframe.html

  首先是普通样式:



接着是显示图形样式:



使用新的样式风格:



首先请下载本文中的源码(本人已部分修改了原文中的源码和相应的样式,以便进行DEMO演示)。下面是相应的类图和说明:



接下来,将会以这个类图来逐个解释相应类结构信息,首先看一下MessageBoxControls(相应内容见注释):




Code

/// <summary>

/// 消息框结果

/// </summary>

public enum MessageBoxResult

{

Yes,  //是

No,   //否

Cancel //取消

}

/// <summary>

/// 消息事件参数

/// </summary>

public class MessageBoxResultEventArgs : EventArgs

{

public MessageBoxResult Result { get; set; }

public object AsyncState { get; set; }

}

/// <summary>

/// 消息框控件类,该模板包括三个组件(三个Button和一个Panel)

/// </summary>

[TemplatePart(Name = RootElement, Type = typeof(Panel))]

[TemplatePart(Name = YesButtonElement, Type = typeof(Button))]

[TemplatePart(Name = NoButtonElement, Type = (typeof(Button)))]

[TemplatePart(Name = CancelButtonElement, Type = (typeof(Button)))]

public class MessageBoxControl : ContentControl

{

public event EventHandler<MessageBoxResultEventArgs> MessageBoxDismissed;

public MessageBoxControl()

{

DefaultStyleKey = typeof(MessageBoxControl);

}

public override void OnApplyTemplate()

{

#region 取消之前的事件绑定

if (yesButton != null)

{

yesButton.Click -= OnYesButton;

}

if (noButton != null)

{

noButton.Click -= OnNoButton;

}

if (cancelButton != null)

{

cancelButton.Click -= OnCancelButton;

}

#endregion

rootElement = base.GetTemplateChild(RootElement) as Panel;

yesButton = base.GetTemplateChild(YesButtonElement) as Button;

noButton = base.GetTemplateChild(NoButtonElement) as Button;

cancelButton = base.GetTemplateChild(CancelButtonElement) as Button;

#region 如果grid中有相应元素时,则绑定相应事件(详见下面的代码)

if (yesButton != null)

{

yesButton.Click += OnYesButton;

}

if (noButton != null)

{

noButton.Click += OnNoButton;

}

if (cancelButton != null)

{

cancelButton.Click += OnCancelButton;

}

#endregion

}

void OnYesButton(object sender, EventArgs args)

{

FireDismissed(MessageBoxResult.Yes);

}

void OnNoButton(object sender, EventArgs args)

{

FireDismissed(MessageBoxResult.No);

}

void OnCancelButton(object sender, EventArgs args)

{

FireDismissed(MessageBoxResult.Cancel);

}

/// <summary>

/// 调用绑定的事件,并传递相应参数

/// </summary>

/// <param name="result"></param>

void FireDismissed(MessageBoxResult result)

{

//当绑定的事件不为空时

(绑定部分参见MessageBox的构造函数)

if (MessageBoxDismissed != null)

{

MessageBoxDismissed(this, new MessageBoxResultEventArgs() { Result = result });

}

}

Button yesButton;

Button noButton;

Button cancelButton;

Panel rootElement;

#region 赋值信息参见generic.xaml中的"x:Name"声明

public const string RootElement = "RootElement";

public const string YesButtonElement = "YesButtonElement";

public const string NoButtonElement = "NoButtonElement";

public const string CancelButtonElement = "CancelButtonElement";

#endregion

}

而MessageBox这个控件使用封装类结构如下(相关内容见注释):




Code

public class UserControlContentAccessor : UserControl

{

/// <summary>

/// 获取当前UserControl的ContentProperty属性

/// </summary>

/// <param name="uc">当前UserControl</param>

/// <returns>ContentProperty属性</returns>

public static UIElement GetContent(UserControl uc)

{

return ((UIElement)uc.GetValue(UserControl.ContentProperty));

}

/// <summary>

/// 设置当前UserControl的ContentProperty属性

/// </summary>

/// <param name="uc">当前UserControl</param>

/// <param name="element">要设置的内容属性</param>

public static void SetContent(UserControl uc, UIElement element)

{

uc.SetValue(UserControl.ContentProperty, element);

}

}

/// <summary>

/// 消息框类,该类可以看成是对"消息框控件类"使用封装(封装了事件绑定和内容信息)

/// </summary>

public static class MessageBox

{

/// <summary>

/// 实际页面视图中的元素(用于当消息框关闭后,还原页面元素时使用)

/// </summary>

private static UIElement realVisual;

/// <summary>

/// 用于绑定当前页面中根元素节点

/// </summary>

private static Grid parentGrid;

/// <summary>

/// 状态值

/// </summary>

private static object asyncState;

/// <summary>

/// 用户绑定回调事件属性

/// </summary>

private static EventHandler<MessageBoxResultEventArgs> userCallback;

public static void ShowAsync(object content)

{

ShowAsync(content, null);

}

public static void ShowAsync(object content,

EventHandler<MessageBoxResultEventArgs> callback)

{

ShowAsync(content, null, callback);

}

public static void ShowAsync(object content, object userState,

EventHandler<MessageBoxResultEventArgs> callback)

{

ShowAsync(content, userState, callback, null);

}

public static void ShowAsync(object content, object userState,

EventHandler<MessageBoxResultEventArgs> callback, Style controlTemplate)

{

MessageBoxControl control = new MessageBoxControl();

control.Content = content;

//绑定指定样式

if (controlTemplate != null)

{

control.Style = controlTemplate;

}

ShowAsync(control, userState, callback);

}

public static void ShowAsync(MessageBoxControl control, object userState,

EventHandler<MessageBoxResultEventArgs> callback)

{

UserControl uc = Application.Current.RootVisual as UserControl;

if (uc != null)

{

asyncState = userState;//用户状态绑定

userCallback = callback;//回调方法

realVisual = UserControlContentAccessor.GetContent(uc);

realVisual.IsHitTestVisible = false; //使底层控件点击不可见

parentGrid = new Grid();//声明一个Grid对象,用于加载新的内容

UserControlContentAccessor.SetContent(uc, parentGrid);

parentGrid.Children.Add(realVisual); //加载realVisual内容(注:此处内容中的控制已不支持点击了)

parentGrid.Children.Add(control); //加载消息框实例,后加载的显示在上(前)面

control.MessageBoxDismissed += OnDismissed; //绑定要处理的事件,该事件会在点击消息框中的"yes"或"no"按钮时执行

}

}

static void OnDismissed(object sender, MessageBoxResultEventArgs e)

{

MessageBoxControl control = sender as MessageBoxControl;

UserControl uc = Application.Current.RootVisual as UserControl;

if (uc != null)

{  //清除之前的页面UI元素,并还原页面初始时的元素设置

parentGrid.Children.Clear();

realVisual.IsHitTestVisible = true;

UserControlContentAccessor.SetContent(uc, realVisual);

}

if (control != null)

{

control.MessageBoxDismissed -= OnDismissed;

}

try

{

if (userCallback != null)

{

//执行用户绑定的事件(并传递事件参数)

userCallback(null, new MessageBoxResultEventArgs()

{

Result = e.Result,

AsyncState = asyncState

});

}

}

finally

{

realVisual = null;

parentGrid = null;

asyncState = null;

userCallback = null;

}

}

}

其实通过上面的类,我们可以看出作者是如何在当前页面中显示消息框信息的,也就是上面代码段里

的如下代码:





realVisual = UserControlContentAccessor.GetContent(uc);

realVisual.IsHitTestVisible = false; //使底层控件点击不可见

parentGrid = new Grid();//声明一个Grid对象,用于加载新的内容

UserControlContentAccessor.SetContent(uc, parentGrid);

parentGrid.Children.Add(realVisual); //加载realVisual内容(注:此处内容中的控制已不支持点击了)

parentGrid.Children.Add(control); //加载消息框实例,后加载的显示在上(前)面





也就是通过realVisual来保存原有的页面元素信息,然后重新按指定顺序(先realVisual再messagecontrol)加载UIElement来实现显示消息框的方式,当然这种有HACK味道的做法到底效果好不好,连原作者都表示怀疑,他

本人也感觉还应有更好的Solution。

当然realVisual变量的一个重要用处在于当消息框被关闭时,用它来还原页面中的元素,而这块代码就是上面所说的OnDismissed方法所做的事了,代码如下:

OnDismissed (object sender, MessageBoxResultEventArgs e)

{

MessageBoxControl control = sender as MessageBoxControl;

UserControl uc = Application.Current.RootVisual as UserControl;

if (uc != null)

{  //清除之前的页面UI元素,并还原页面初始时的元素设置

parentGrid.Children.Clear();

realVisual.IsHitTestVisible = true;

UserControlContentAccessor.SetContent(uc, realVisual);

}





}

这样,我们可以在应用程序中使用该类来显示相应的消息框了,其声明和使用代码如下:

//普通样式

void OnNormalClick(object sender, EventArgs args)

{

MessageBox.ShowAsync("简单调用, 无回调, 无状态, 无样式!");

//下面注释的代码包括状态和回调事件 

//MessageBox.ShowAsync("As previously but with a callback - hit NO", (s, e) =>

// {

// Debug.Assert(e.Result == MessageBoxResult.No);

// });

//MessageBox.ShowAsync("As previously but with state - hit YES", 101, (s, e) =>

// {

// Debug.Assert((e.Result == MessageBoxResult.Yes) && ((int)e.AsyncState == 101));

// });

}

//显示图形

void OnShapeClick(object sender, EventArgs args)

{

MessageBox.ShowAsync(new Ellipse()

{

Width = 80,

Height = 80,

Fill = new SolidColorBrush(Colors.Green)

});

}

//转换样式

void OnChangeStyleClick(object sender, EventArgs args)

{

Style myStyle = this.Resources["myStyle"] as Style;

MessageBox.ShowAsync("使用一个不同的样式",

101,//状态

(s, e) => //处理事件

{

if (e.Result == MessageBoxResult.No && ((int)e.AsyncState == 101))

{

HtmlPage.Window.Alert("您点击了No按钮");

}

if (e.Result == MessageBoxResult.Yes)

{

HtmlPage.Window.Alert("您点击了Yes按钮");

}

},

myStyle);

}

说到这里,还有一个内容没有介绍,也就是作者所定义的两个样式文件,其中之一被放置到了generic.xaml中,以便做了控制默认加载样式,其绑定直接在MessageBoxControl构造函数中完成,如下:

 

public MessageBoxControl()

{

DefaultStyleKey = typeof(MessageBoxControl);

}

而另外的样式被放在了page.xaml中,以便于程序运行时访问,这里就不多作介绍了。不过本人已修改了这两个样式中的一些数值,主要是为了显示时比例更好看一些。

好了,今天的内容就先到这里了。

tag : silverlight,messagexbox

作者: 代震军, daizhj

原帖链接: http://files.cnblogs.com/daizhj/silverlight_MessageBox.rar
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息