Windows窗体应用程序基础:将所有窗体保存在一个窗口中

时间:2014-08-01 21:06:25

标签: c# vb.net windows forms

我正在使用Visual Studio 2010在VB.net中编写Windows窗体应用程序(仍然欢迎使用C#响应)。

我已经创建了应用程序的功能,现在正在处理UI流程。基本上,我需要使应用程序的所有功能从一开始就显示/消失,介绍形式。他们点击Introduction.vb表单中的一个选项,原始材料消失,并被他们点击的任何内容替换。然后,如果他们想要返回上一页,则在下一页上有一个后退按钮。 这是最初的Introduction.vb:

Public Class Introduction
Inherits System.Windows.Forms.Form
Private Sub Introduction_Load(sender As System.Object, e As System.EventArgs) Handles Me.Load
End Sub

Private Sub AddOrRemoveButton_Click(sender As System.Object, e As System.EventArgs) Handles AddOrRemoveButton.Click
    AddRemoveCompany.Show() '<-- Show the AddRemoveCompany.vb form when they click on the button.
End Sub

Private Sub InvoiceDocumentButton_Click(sender As System.Object, e As System.EventArgs) Handles InvoiceDocumentButton.Click
    InvoicePrinterAndDocCreator.Show() '<-- .vb form
End Sub 

Private Sub LockOrUnlockButton_Click(sender As System.Object, e As System.EventArgs) Handles LockOrUnlockButton.Click
    LockUnlockPIN.Show() '<-- .vb form
End Sub

Private Sub ToExcelButton_Click(sender As System.Object, e As System.EventArgs) Handles ToExcelButton.Click
    ToExcel.Show() '<-- .vb form
End Sub
End Class

正如您所看到的,现在我只是为应用程序的每个区域创建了一个单独的表单,并在开始时将它们从主表单链接起来。每个后续表单上的后退按钮只关闭窗口。这一切都很有效,除了新页面在新窗口中打开,我想避免。相反,我希望在原始窗口中打开新部件。

从我的研究中,我发现为了实现这一点,我需要将我创建的每个表单(我愚蠢地为每个表单创建一个表单)更改为UserControl对象,然后显示或隐藏适当地控制主要形式。问题是,我不确定如何做到这一点。我知道如何将我的Forms对象更改为UserControls对象,并修复与此相关的错误。

当我尝试开发逻辑以显示/隐藏主要介绍页面的UserControls时,我的问题就出现了。我在网上找到了结果,建议我创建一个包含所有控件的Dictionary,然后根据需要添加/删除它。我还发现结果表明我应该能够使用主页上按钮上的逻辑显示/隐藏表单。我无法使用这些方法中的任何一种,经常会遇到错误,指出&#34;顶级控件无法添加到控件中。&#34; 基本上,我卡住,困惑,我尝试似乎总是抛出错误,我想知道实现这一点的最佳方法是什么。

让我发帖(其中之一)我尝试过的确实有效:

Public Class MainForm
Private Sub MainForm_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    Dim x = New Introduction
    Me.Controls.Add(x)
    x.Show()
End Sub
End Class

这个MainForm当然是替换旧的Introduction.vb表单,而是直接显示Introduction.vb UserControl。这是新的Introduction.vb UserControl:

Public Class Introduction
Inherits System.Windows.Forms.UserControl
Private Sub Introduction_Load(sender As System.Object, e As System.EventArgs) Handles Me.Load
End Sub

Private Sub AddOrRemoveButton_Click(sender As System.Object, e As System.EventArgs) Handles AddOrRemoveButton.Click
    ' Testing logic here:
    Dim y = New AddRemoveCompany '<-- One of my old forms that was converted to a UserControl.
    MainForm.Controls.Clear()
    MainForm.Controls.Add(y)
    y.Show()
End Sub

Private Sub InvoiceDocumentButton_Click(sender As System.Object, e As System.EventArgs) Handles InvoiceDocumentButton.Click
    InvoicePrinterAndDocCreator.Show() '<-- Still works, but still opens in a new window
End Sub

Private Sub LockOrUnlockButton_Click(sender As System.Object, e As System.EventArgs) Handles LockOrUnlockButton.Click
    LockUnlockPIN.Show()
End Sub

Private Sub TRSToExcelButton_Click(sender As System.Object, e As System.EventArgs) Handles TRSToExcelButton.Click
    TRSToExcel.Show()
End Sub
End Class

这个方法似乎草率,虽然我至少能够让下一个表单显示这种方式而不会抛出错误。例如,下一页上的后退按钮基本上只是清除所有旧控件,然后再次添加Introduction.vb UserControl,并再次显示它。那么,现在变量冲突呢?我将不得不确保我的所有变量名称都不同(如果我错了,请纠正我),因此对于每个表单,我将不得不将BackButton更改为BackButton1,BackButton2等。此方法似乎就像它将花费更多的时间而不是它的价值,而且阅读时会更加困惑。

我真的很感激,如果有人花时间解释一个更好的方法来做到这一点,这不是草率和易于维护,避免可变冲突,不是硬意大利面条编码在一起等。任何在线资源的链接我也会受到赞赏,但令人惊讶的是,我找不到很多超出我所说的内容。

3 个答案:

答案 0 :(得分:3)

有数百种方法可以做到这一点,一种是将表单的属性TopLevel设置为false。或者您的MainForm应该包含一个面板,您可以动态加载UserControl。

基本上你正在寻找的是一个名为Composite UI的概念。 .NET中最复杂的UI应用程序使用WPF更适合(imho)。但是WinForms也有相当简单的概念。(正如我上面提到的那样创建一个面板并动态加载UserControls)。

我必须承认我没有阅读你的所有文字(因为这是一个非常简单的问题的方法)。所以我希望我把一切都搞定。

例如:

public void button_Click(object sender, EventArgs e)
        {
            this.panelBoarder.Controls.Clear() //Hide old content

            if (this.pageTwo == null)
                this.pageTwo = new PageTwo(); // Create Page Two

            this.panelBoarder.Controls.Add(this.pageTwo);
            this.pageTwo.Visible = true;
        }

答案 1 :(得分:1)

这是一个很好的例子。这假设您的表单上有一个名为Panel1的面板,您希望在该面板中显示的表单是Form2:

Dim f2 As New Form2
f2.TopLevel = False
f2.ControlBox = False
f2.FormBorderStyle = Windows.Forms.FormBorderStyle.None
Panel1.Controls.Add(f2)
f2.Show()

您需要将以前的表单放入一个集合中,这样您就可以通过从集合中提取最后一个项目来向后退。希望这会有所帮助。

答案 2 :(得分:1)

就个人而言,由于以下几个原因,我不是修改Controls集合的粉丝:

  • 有很多不必要的重绘(反编译ControlsCollection.Add并查看)
  • You'll mess with the z-order
  • 我从来没有必要这样做来完成与UI相关的任务,上面描述的内容可以通过修改控件来完成
    • 保持简单:)

Here's a super bare-bones example of what I think you're asking for.

它使用TabPage(没有标题)来托管控件(我添加了指示&#34;页面&#34的标签;但这些可以很容易地成为您的用户控件)。后退按钮由Stack处理,因为这是您正在寻找的内容 - 推送新的页面选择,并在用户想要返回时弹出它们:

public partial class Form1 : Form
{
    //...
    Stack<TabPage> breadCrumbs = new Stack<TabPage>();

    private void SwitchTabs(TabPage page)
    {
        breadCrumbs.Push(tabControl1.SelectedTab);
        tabControl1.SelectedTab = page;
    }

    //...

    //Go back
    private void toolStripButton1_Click(object sender, EventArgs e)
    {
        if(breadCrumbs.Count == 0)
            return;

        var lastTab = breadCrumbs.Pop();
        tabControl1.SelectedTab = lastTab;
    }
}

请注意,这是一个非常简单的实现,不用担心问题的分离。如果您想让我了解更多细节,请告诉我,我很乐意详细说明。