在silverlight中,如果想使用“消息框”可使用下面的方法,即:HtmlPage.Window.Alert("消息框内容")。如果想要显示更加复杂的内容或定义消息框样式的话,基本上没有什么好的方法。最近在网上看到了一篇文章,该文章的作者也谈到了上面所说的话题,相关链接如下:
The Curious Incident of the MessageBox in the Silverlight App
在线演示如下: [url]http://silverlight.services.live.com/invoke/72193/messagebox/iframe.html[/url]
首先是普通样式:
接着是显示图形样式:
使用新的样式风格:
首先请下载本文中的源码(本人已部分修改了原文中的源码和相应的样式,以便进行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
原帖链接: [url]http://files.cnblogs.com/daizhj/silverlight_MessageBox.rar[/url]
本文出自 “代震军:http://t.sina..” 博客,转载请与作者联系!