65.9K
CodeProject 正在变化。 阅读更多。
Home

Silverlight 中的模态窗口

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.96/5 (16投票s)

2008年9月28日

CPOL

4分钟阅读

viewsIcon

138889

downloadIcon

2353

展示了一种创建模态窗口的通用机制。

注意:版本 2

本文是对 2008 年 9 月发布的初版文章的更新。初版文章发布后,有人指出在模态窗口中承载 ComboBoxDataGrid 等控件存在问题。问题在于 Popup 类未添加到视觉树中。
作为解决方案,我添加了一个 static 属性,该属性只需在应用程序中设置一次,最好将其初始化为**主页面的 VisualRoot**,并且它必须是**Grid 类**。

public partial class MainPage : UserControl
{
	public MainPage()
	{
		InitializeComponent();

		ModalControl.ParentHost = LayoutRoot; // Init the parent control
	}

	// Rest of the code removed
}

初始化 ModalControl.ParentHost 后,您就可以使用模态窗口来承载 ComboBoxesDataGrids

演示项目展示了如何使用 ModalControl 和更新的 MessageBox

引言

本文介绍了如何实现一个类,该类能够模态地显示任何 UserControl 派生控件。

背景

我对此类的第一个实现要求您从该类派生您的控件,以便它们可以模态显示。
这种方法效果很好,并且是最完整、最易于使用的实现。但是,Expression Blend 设计器窗口不会显示那些不直接派生自 UserControl 的控件,因此我们会失去 Blend 的所有出色设计功能。

这让我思考,在不失去 Blend 设计功能的情况下,我还能如何实现相同的行为。经过一番思考,我意识到聚合必须是解决方案。

ModalControl 类的特性

  • 模态显示任何 UserControl 派生控件
  • 拖动托管控件
  • 在浏览器窗口大小调整时居中托管控件
  • 阻止托管控件拖出浏览器窗口

项目

此项目基于 Silverlight Wizard 项目,展示了如何模态地显示该向导,我还构建了一个 MessageBox,演示了 ModalControl 类如何被封装以创建独立的模态窗口。

它看起来是什么样的

在这里,我们可以看到 Silverlight Wizard 项目的主页已更改,以便一个按钮可以模态地显示向导。我还添加了一个“显示对话框”按钮,它将弹出我通过聚合 ModalControl 实现的一个模态对话框窗口。

modal01.png

在这里,我们看到 Silverlight Wizard 以模态方式显示,而无需对其进行任何更改。我们从外部使用 ModalControl 类。

modal02.png

这里是模态对话框

modal03.png

Using the Code

您可以通过以下两种方式使用 ModalControl 类提供的服务

  • 用作辅助类,并将要模态显示的 UserControl 传递给 ShowModal 函数。
  • ModalClass 封装到您的控件中,MessageBox 展示了如何使用此技术。

ModalControl 作为辅助

请注意,在下面的代码中,我们只需要定义一个 ModalControl 实例;重要的是 ShowModal 接受要显示的控件作为参数,而 HideModal 返回 UserControl

// Declare a class instance member of the ModalControl
ModalControl _oModalCtrl = new ModalControl();

void OnShowWizardClick(object sender, RoutedEventArgs e)
{
    // Instantiate the wizard
    Wizard oWizard = new Wizard();

    // Set data context and add pages to the wizard
    oWizard.DataContext = LayoutRoot.DataContext;
    oWizard.Pages.Add(new WizardPage1());
    oWizard.Pages.Add(new WizardPage2());
    oWizard.Pages.Add(new WizardPage3());

    // Add a Pages event listener to the izard
    oWizard.PageEvent += new WizardPageEvent(OnPageEvent);

    // call ShowModal by passing the wizard refernce to the modal control
    // this call will show the wizard modally, it could be any user control
   _oModalCtrl.ShowModal(oWizard);
}

// Here we handle the wizard page events
void OnPageEvent(Wizard sender, WizardEventArgs e)
{
   _txtMsg.Text = string.Format("Action: {0}, Current: {1}, New: {2}",
   e.Action, e.CurrentPageIndex, e.NewPageIndex);

   // When we hit the Finish button on the wizard we call close on the
   // modal control and that returns to us the wizard reference so we could
   // do some processing if we need to - sender prameter does the same
   if(e.Action == WizardAction.Finish)
   {
     // Close the wizard
     Wizard oWizard = (Wizard)_oModalCtrl.HideModal();
   }
}

封装 ModalControl

ModalControl 封装到您自己的类中同样简单,这在 ModalWizard 项目中的 MessageBox 类中有充分演示。这里的代码是 MessageBox 实际实现的一个简化版本,但它显示了重要的部分。

public class MessageBox : UserControl
{
 // Static demofunction
 public static MessageBox Show(string Title, string Message)
 {
  // Here we create the MessageBox instance
  MessageBox oBox = new MessageBox(Title, Message);
  // Use its private member to show the dialog
  oBox.ModalHost.ShowModal(oBox);
  // Return the reference to the MessageBox
  return oBox;
 }

 // Instance memebers
 // --------------------------------------------------------------------
 // Declare a private instance of the ModalControl
 ModalControl ModalHost;

 // Pass the parameters to the constructor
 private MessageBox(string Title, string Message)
 {
  InitializeComponent();
  txtTitle.Text = Title;
  txtMessage.Text = Message;

  ModalHost = new ModalControl();  // Instantiate the ModalControl

  btClose.Click += OnCloseClick;
 }
 // Handle the close button click
 private void OnCloseClick(object sender, RoutedEventArgs e)
 {
  // On modal control call HideModal to close the message box
  ModalHost.HideModal();
 }
}

使用 MessageBox 类/控件

以下代码段显示了如何使用 MessageBox 控件;您必须记住,ModalControl 并非真正地模态显示子/托管控件,它只是提供了模态的“错觉”。在此版本的 MessageBox 中,我们不需要维护对 MessageBox 的引用
由于我假设我们一次只显示一个 MessageBox。这个假设允许我有一个单一的 static 引用 MessageBox,因此使得 MessageBox 更像 WinForms MessageBox

void OnShowDialogClick(object sender, RoutedEventArgs e)
{
 	MessageBox.Show("Some modal title", "This is some message!",
		MessageBox.Buttons.YesNo,
		MessageBox.Icons.Information, OnDialogClosed);
}

bool OnDialogClosed(object sender, ExitCode e)
{
	Debug.Print("Dialog Closed with code: " + e);
	return true;
}

关注点

非常重要的是要记住,模态窗口并非真正模态,当前视图和模态控件之间放置了一个半透明的画布。如果关闭模态窗口时需要退出代码或其他任何详细信息,您必须实现
某些回调或事件处理程序。本项目中的 MessageBoxModalWizard 类演示了所有这些要点。

特别感谢

读者 Predrag Tomasevic 识别出 Popup 类未添加到视觉树的问题。

历史

  • 2008 年 9 月 28 日:初次发布
  • 2009 年 3 月 11 日:文章更新
© . All rights reserved.