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

WinForms 的简单向导

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (12投票s)

2010年10月26日

CPOL

3分钟阅读

viewsIcon

89555

一个简单的向导

更新:2018-05-17

本文最初发表于 8 年前。 后来 CodePlex 停止了服务。 因此,我已将代码移至 GitHub,以便仍然觉得这有用的任何人都可以使用。 只需单击本文顶部的新的下载链接即可。

引言

SimpleWizard/Capture.PNG

正在寻找一种快速简便的方法来创建向导主机? 别再找了。 SimpleWizard 为您的向导页面、导航甚至基本主机提供了所需的接口。 主机需要做一些工作,因为它的 UI 相当简陋,但本文的主题实际上是如何处理导航等。 我将所有美化工作留给读者。

接口

public interface IWizardPage
{
   UserControl Content { get; }
   void Load();
   void Save();
   void Cancel();
   bool IsBusy { get; }

   bool PageValid { get; }
   string ValidationMessage { get; }
}

这是基本要求:一个可以用于向导页面的接口。 只需创建一些用户控件(页面),继承 IWizardPage,然后就可以进行该步骤了。

集合和导航

public enum WizardPageLocation
{
    Start,
    Middle,
    End
}
public class WizardPageCollection : Dictionary<int, IWizardPage>
{
    public IWizardPage CurrentPage { get; private set; }
    public IWizardPage FirstPage { get; }
    public IWizardPage LastPage { get; }

    public WizardPageLocation PageLocation { get; private set; }

    public bool CanMoveNext { get; }
    public bool CanMovePrevious { get; }

    public WizardPageCollection()
    {
        PageLocation = WizardPageLocation.Start;
    }

        public delegate void 
	WizardPageLocationChangedEventHanlder(WizardPageLocationChangedEventArgs e);
    public event WizardPageLocationChangedEventHanlder WizardPageLocationChanged;

    public IWizardPage MovePageFirst()
    public IWizardPage MovePageLast()
    public IWizardPage MovePageNext()
    public IWizardPage MovePagePrevious()

    public int IndexOf(IWizardPage wizardPage)

    public void Reset()

    private void NotifyPageChanged(int previousPageIndex)
}
public class WizardPageLocationChangedEventArgs
{
    public WizardPageLocation PageLocation { get; set; }
    public int PageIndex { get; set; }
    public int PreviousPageIndex { get; set; }
}

您可以看到,我只提供了方法等的签名。这是为了清晰起见。 您可以在源代码中找到实际实现,网址为 http://simplewizard.codeplex.com/

现在,为了更好地了解 MovePage...() 方法中发生的事情,请在此处查看 MovePageNext()

public IWizardPage MovePageNext()
{
   int previousPageIndex = IndexOf(CurrentPage);

   if (PageLocation != WizardPageLocation.End &&
      CurrentPage != null)
      {
         // Find the index of the next page
         int nextPageIndex = (from x in this
                              where x.Key > IndexOf(CurrentPage)
                              select x.Key).Min();

         // Find the index of the last page
         int lastPageIndex = (from x in this
                              select x.Key).Max();

         // If the next page is the last page
         if (nextPageIndex == lastPageIndex)
         {
            PageLocation = WizardPageLocation.End;
         }
         else { PageLocation = WizardPageLocation.Middle; }

         // Set the current page to be the next page                
         CurrentPage = this[nextPageIndex];
         NotifyPageChanged(previousPageIndex);

         return CurrentPage;
      }
      return null;
}

您会注意到我们继承自 Dictionary<int, IWizardPage>。 键是页码,值是 IWizardPage。 简单地继承上述字典可以很好地为我们处理所有集合相关的事情。 现在,我们只需要关注导航即可。

有一些属性允许您直接访问集合中的当前页面、第一页和最后一页,以及一些属性,这些属性会告诉您是否可以向前移动,这些方法允许您实际在页面之间来回移动(如果可能)。 您唯一真正需要用到这个东西的地方是在您的主机窗体中,我们稍后会看到...

我想这样总结得很好。

向导主机

public partial class WizardHost : Form
{
   private const string VALIDATION_MESSAGE = "Current page is not valid. 
	Please fill in required information";

   public WizardPageCollection WizardPages { get; set; }
   public bool ShowFirstButton { get; set; }
   public bool ShowLastButton { get; set; }

   public bool NavigationEnabled { get; set; }

   public delegate void WizardCompletedEventHandler();
   public event WizardCompletedEventHandler WizardCompleted;

   public WizardHost()
   {
      InitializeComponent();
      WizardPages = new WizardPageCollection();
      WizardPages.WizardPageLocationChanged += new 

WizardPageCollection.WizardPageLocationChangedEventHanlder
	(WizardPages_WizardPageLocationChanged);
   }

   void WizardPages_WizardPageLocationChanged(WizardPageLocationChangedEventArgs e)
   {
      LoadNextPage(e.PageIndex, e.PreviousPageIndex, true);
   }

   private void NotifyWizardCompleted()
   private void OnWizardCompleted()
   public void UpdateNavigation()
   private bool CheckPageIsValid()
   public void LoadWizard()
   public void LoadNextPage(int pageIndex, int previousPageIndex, bool savePreviousPage)

   private void btnFirst_Click(object sender, EventArgs e)
   private void btnPrevious_Click(object sender, EventArgs e)
   private void btnNext_Click(object sender, EventArgs e)
   private void btnLast_Click(object sender, EventArgs e)
}

这就是所有工作发生的地方。 在这里,您有 WizardPageCollection,一些属性用于选择是否在向导上显示“第一页”和“最后一页”按钮(不显示“下一步”和“上一步”按钮是没有意义的,这就是为什么只有 2 个属性)。

所有导航更新都在这里进行,以及检查当前页面在移动到下一页之前是否有效。 CheckPageIsValid() 调用 IWizardPage 上的 PageValid 属性。 如果它返回 false,则会显示一个消息框以及该页面的 ValidationMessage 属性。

同样,有关更多详细信息,请参阅源代码。

当您准备好启动向导时,您所需要做的就是添加您的向导页面,并将向导主机显示为对话框。 这是一个例子

private void button1_Click(object sender, EventArgs e)
{
   WizardHost host = new WizardHost();
   host.Text = "My Wizard";
   host.WizardCompleted += 
	new WizardHost.WizardCompletedEventHandler(host_WizardCompleted);
   host.WizardPages.Add(1, new Page1());
   host.WizardPages.Add(2, new Page2());
   host.WizardPages.Add(3, new Page3());
   host.LoadWizard();
   host.ShowDialog();
}

结论

SimpleWizard 允许您忘记所有导航问题,只需将您的用户控件添加到 WizardHost 实例即可。 就这么简单。

历史

  • 2010 年 10 月 26 日:初始发布
© . All rights reserved.