【问题标题】:C# Switching Between Interface in the Same FormC#在同一表单中的界面之间切换
【发布时间】:2015-12-22 13:23:22
【问题描述】:

我用 Java 编写了一个数据库程序,现在我希望将其转换为 C# 用于学习目的。

我遇到的一个问题是在同一用户界面中的不同视图之间切换。我想在整个程序中保留一个表单,并在用户浏览程序时更改其上显示的内容。

我试图在表单上添加一个面板,在该表单中添加一个包含按钮的用户控件。单击按钮时,初始用户控件应被处理掉并显示新的用户控件。

这是我目前的代码;

public partial class Form1 : Form
{

    UserControl1 myControl1 = new UserControl1();
    UserControl2 myControl2 = new UserControl2();

    public Form1()
    {
        InitializeComponent();
        panel1.Controls.Add(myControl1);
    }

    public void PanelVersion2()
    {
        panel1.Controls.Remove(myControl1);
        panel1.Controls.Add(myControl2);
    }
}

在我的 UserControl 类中;

public partial class UserControl1 : UserControl
{
        public event EventHandler AddControl;
        public UserControl1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Form1 fm = new Form1();
            fm.PanelVersion2();
        }
    }
}

这种意识形态是创建 UI 的“最佳”方式吗?有没有更有效的方法来在用户界面中移动,同时保持原始表单?

【问题讨论】:

  • 我认为你可以使用 BringToFront() 方法来做到这一点。 msdn.microsoft.com/en-us/library/…
  • Winforms 是一个大的乐高盒子,完全由你来拼凑。没有一个总体框架可以强迫你以某种方式做事。你想做的事情会让你走得很远,但你必须知道基本规则。 Controls.Remove() 很危险,您必须在要删除的控件上调用 Dispose() 方法。最好在没有 Remove() 的情况下立即处理它。将这些片段拼接在一起的另一种快速方法是this way

标签: c# forms visual-studio panel


【解决方案1】:

由于问题是关于 WinForms 的,我不想,好吧.. 违反惯例并回答建议您立即使用不同的技术,我将首先正常回答该问题,并提供事后的想法我建议你实际上这样做。无论任何人说什么,都不要为此使用 MDI。它不是为此而设计的,只会让您的用户感到困惑。所以这里是一个基于小视图的控制器框架,采用简约的方法。

首先是宿主表单的接口(IHost.cs):

public interface IHost
{
    /// <summary>
    ///     Destroys the current view and creates a new from name
    /// </summary>
    /// <param name="name">The name of the view you wish to start</param>
    void SwitchView(string name);

    View CurrentView { get; }
}

然后,视图界面。现在,Visual Studio 会告诉你这是设计中的 UserControl。不会错!它是,但不应该被用作一个。如果您确实删除了它在右侧创建的类,则永远不要真正将东西放在该设计器上。这是所有视图的基础,如果您编辑它,所有视图都将具有界面的该部分。 (查看.cs)

    using System.Windows.Forms; //Above your namespace

    public class View : UserControl
    {
        /// <summary>
        ///     Warning! Attempting to use this constructor and host (eg switching views)
        ///     will result in exceptions unless host is manually set
        /// </summary>
        protected View()
        {
        }
        protected View(IHost host) 
        {
            Host = host;
        }

        public virtual IHost Host { get; }
    }

现在主机表单看起来像这样(HostForm.cs,这是我的入口点,也是我向主要用户展示的东西):

    using System.Collections.Generic; //Above your namespace
    using System.Windows.Forms; //Above your namespace

    public partial class HostForm : Form, IHost
    {
        public View CurrentView { get; private set; }

        public HostForm()
        {
            InitializeComponent();
            SwitchView("UserLabel");
        }

        public void SwitchView(string name)
        {
            Controls.Remove(CurrentView);
            CurrentView = CreateViewFromName(name);
            Controls.Add(CurrentView);
            CurrentView.Show();
        }

        private View CreateViewFromName(string name)
        {
            switch (name.ToLowerInvariant())
            {
                case "userlabel":
                    return new UserLabel(this);
                case "usertext":
                    return new UserText(this);
            }
            throw new KeyNotFoundException("Could not find a form with that name!");
        }
    }

从这里开始,创建一个普通的 UserControl,但在 cs 代码中将“UserControl”更改为 View,并在您的主机表单中为其添加名称转换,就像您在上面看到的那样。这是我创建的两个视图(设计省略) (UserLabel.cs)

    public partial class UserLabel : View
    {
        public UserLabel(IHost host) : base(host)
        {
            InitializeComponent();
        }

        private void SubmitButton_Click(object sender, System.EventArgs e)
        {
            Host.SwitchView("UserText");
        }
    }

(用户文本.cs)

    public partial class UserText : View
    {
        public UserText(IHost host) : base(host)
        {
            InitializeComponent();
        }

        private void LoginButton_Click(object sender, EventArgs e)
        {
            Host.SwitchView("UserLabel");
        }
    }

请随时在评论部分提出有关此设计的问题。

现在我真正推荐的是什么?如果您需要 Windows 桌面应用程序,并且不想针对通用应用程序框架,我推荐 WPF。 WikipediaMicrosoft Developer Network(MSDN) 都有很好的入门指南。至于模式,我建议您使用MVVM 并从那里继续。网上有很多资源。

【讨论】:

  • 说实话,您提出的您可能会立即拥有完全不同的技术的建议并不令人惊讶。作为一个从 Java 过来的人,我对在一个表单中简单地获取多个接口是多么困难感到惊讶。 WPF 在表单中的控件之间切换有何不同?
  • 由于 WPF(使用 MVVM)具有集成的数据控制器(DataContext),因此您可以根据它处理切换视觉效果。通常,您可以将控件的“可见性”上下文绑定到数据模型上的某些属性。最重要的是,窗口中的窗口渲染也是可能的,但我不鼓励这样做。通常,如果问题是如何在 WPF 中的一般视图之间导航,那么下面的 SO 帖子已经回答了这个问题。 stackoverflow.com/questions/19654295/wpf-mvvm-navigate-views
【解决方案2】:

您不要让表单显示表单,也不要让表单决定显示哪个面板,因为这样很难从代码中正确跟踪应用程序中的窗口。是的,您可以遍历 Application.OpenFormssomeContainer.Controls 以找到您要查找的内容,但您不希望这样。

您需要申请design patterns,例如MVP、MVVM、MVC 或application controller

在这个答案中解释这些模式会有点长(我稍后可能会尝试),但请尝试搜索提到的术语。

【讨论】:

  • 我在我的 Java 程序中使用了 MVC,所以我对这个概念有一个初学者的理解。您是否建议有一个控制器类来决定在每个面板中显示哪些用户控件?那么我将如何编写 UserControl 内的按钮单击?如果您有时间,请用代码示例详细说明您的答案。
  • 我不太熟悉 WinForms 中的这些模式,我会让某些操作引发控制器订阅的用户定义事件。
【解决方案3】:

也许您应该将表单的职责与用户控件的职责分开,并且在控件中保留对主表单的引用可能会有所帮助

UserControl1 myControl1 = new UserControl1 { MainForm = this };

这只是一个学习示例的建议,也许你应该搜索一个 UI 设计模式以便做更详细的事情。

【讨论】:

    猜你喜欢
    • 2013-06-06
    • 1970-01-01
    • 1970-01-01
    • 2018-12-07
    • 1970-01-01
    • 2015-10-27
    • 1970-01-01
    • 2011-11-25
    • 1970-01-01
    相关资源
    最近更新 更多