【问题标题】:Windows Forms Application Basics: Keeping all forms in one windowWindows 窗体应用程序基础知识:将所有窗体保存在一个窗口中
【发布时间】:2014-08-01 21:06:25
【问题描述】:

我正在使用 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 对象,并修复与此相关的错误。

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

让我发布(其中一个)我尝试过的真正有效的方法:

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 等。这个方法似乎需要花费的时间比它的价值要多得多,而且阅读起来更加混乱。

如果有人花时间解释一个更好的方法来做到这一点,我将非常感激,这不是草率且易于维护,避免变量冲突,不是硬意大利面条编码在一起等。任何在线资源链接我也将不胜感激,令人惊讶的是,我找不到很多与我所说的内容有关的东西。

【问题讨论】:

    标签: c# vb.net windows forms


    【解决方案1】:

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

    基本上,您正在寻找的是一个名为 Composite UI 的概念。 .NET 中最复合的 UI 应用程序更适合使用 WPF(恕我直言)。但是对于 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;
            }
    

    【讨论】:

    • 介意详细介绍一下吗?我也在我的在线研究中发现了这一点,但无法正确实施......我基本上会像上面那样添加/删除表单,但是添加到 MainPanel.Controls 集合而不是直接添加到 MainForm.Controls收藏
    • 你不想知道这是一项非常基本的任务
    • 好的,当我创建一个面板并尝试将我创建的各种用户控件加载到其中时,我得到“无法将顶级控件添加到控件中”。错误信息。我将使用史蒂夫发布的上述代码作为模板尝试相同的策略,因为它将 TopLevel 设置为 false。老实说,我不知道“TopLevel”是什么意思,所以这完全是我对所涉及的概念的误解,而不是了解具体的代码。
    • MSDN 定义 TopLevel 的方式如下:“顶级控件被定义为父控件,它不是另一个 Windows 窗体控件的父控件。”所以基本上,由于我添加到MainForm的Panel本身不是TopLevel控件,当然添加到它的UserControls不可能是TopLevel。显然,TopLevel 默认设置为 True?
    • 默认情况下,UserControls 上的 TopLevel 属性不是 True,UserControls 没有 TopLevel 属性。只有表单有 TopLevel 属性。我建议您将“页面”继承的类型更改为 UserControl 并再试一次,或者史蒂夫建议将 TopLevel 属性设置为 false。
    【解决方案2】:

    这是一个很好的例子。这假设您的表单上有一个名为 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()
    

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

    【讨论】:

      【解决方案3】:

      就个人而言,我不喜欢修改 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(不带标题)来托管控件(我添加了指示“页面”的标签,但这些也可以很容易地成为您的用户控件)。后退按钮由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;
          }
      }
      

      请注意,这是一个超级简单的实现,不关心关注点分离。如果您希望我更详细地介绍,请告诉我,我很乐意详细说明。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-07-13
        • 1970-01-01
        • 1970-01-01
        • 2010-10-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多