在一个用户控件的点击事件中切换主窗体中的用户控件。

4
这可能听起来很愚蠢,但我很难搞清楚这个问题;任何帮助将不胜感激:
我有两个名为“Safety_Check”和“OEE_Track”的用户控件。在我的MainForm中,我有一个名为“pnl_main_controller”的面板,这是我显示这两个用户控件的地方。我在主窗体上有两个按钮,并且我可以在两者之间动态转换而没有任何问题。
安全检查用户控件:
public partial class Safety_Check : UserControl
    {
        private static Safety_Check _instance;

        public static Safety_Check instance
        {
            get
            {
                if (_instance == null)
                    _instance = new Safety_Check();
                return _instance;
            }
        }

        public Safety_Check()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ///////------------------------
        }

    }

OEE_Track 用户控制

public partial class OEE_Track : UserControl
    {

        private static OEE_Track _instance;

        public static OEE_Track instance
        {
            get
            {
                if (_instance == null)
                    _instance = new OEE_Track();
                return _instance;
            }
        }

        public OEE_Track()
        {
            InitializeComponent();
        }
    }

主窗体:

public partial class MainForm : Form
    {
     private void btn_reg_Click(object sender, EventArgs e)
        {
            if (!pnl_main_controller.Contains(Safety_Check.instance))
            {
                pnl_main_controller.Controls.Add(Safety_Check.instance);
                Safety_Check.instance.Dock = DockStyle.Fill;
                Safety_Check.instance.BringToFront();
            }
            else
            {
                Safety_Check.instance.BringToFront();
            }        }

       private void btn_OEE_Click(object sender, EventArgs e)
        {
            if (!pnl_main_controller.Contains(OEE_Track.instance))
            {
                pnl_main_controller.Controls.Add(OEE_Track.instance);
                OEE_Track.instance.Dock = DockStyle.Fill;
                OEE_Track.instance.BringToFront();
            }
            else
            {
                OEE_Track.instance.BringToFront();
            }
     }

我想要做的是,在“Safety_Check”用户控件上有一个名为“Button1”的按钮,每当我按下它时,我希望“Safety_Check”从“pnl_main_controller”中消失,并将“OEE_Track”呈现在面板中。

1
如果你只想让它消失,那么你可以使用visible属性并将其设置为false,然后将pnl_main_control的visible属性设置为true,并调用bringtofront函数。 - Anil
我尝试过了,Safety_Check.instance.Hide(); main.pnl_main_controller.Controls.Add(OEE_Track.instance); OEE_Track.instance.Dock = DockStyle.Fill; OEE_Track.instance.BringToFront(); Safety_Check实例会消失,但它没有将OEE_Track带到面板上。 - Dinu Kuruppu
2个回答

4
有几种解决方案可用于控件之间的交互。控件是类,就像其他任何类一样,它们可以使用其公共属性和方法或使用某个中介来相互交互。
在这种情况下,您的控件不需要相互了解,也不需要直接相互交互:
- 它们可以向另一个知道两个控件的对象询问,以为它们完成工作。 - 或者它们可以引发其请求通知,订阅该通知的人将为其服务。
要求另一个对象为其完成工作有多种解决方案。例如,您可以在父窗体和子控件中实现特定界面,将父对象强制转换为该特定界面,并调用执行工作的特定方法。
对于引发请求通知,一种简单的解决方案是依赖于事件。您可以在子控件中创建事件,并在需要父对象为其完成工作时引发该事件。然后,在父对象中订阅该事件并执行工作。
示例 - 使用事件
假设您有一个名为 User Control1 的控件,其中包含 Button1,并且您已处理了 Button1 的 Click 事件。然后,您可以创建 Button1Clicked 事件,并在单击 Button1 时引发它:
public event EventHandler Button1Clicked;
private void Button1_Click(object sender, EventArgs e)
{
    Button1Clicked?.Invoke(this, e);
}

然后在父表单中订阅事件并执行你想要的操作:

private void userControl11_Button1Clicked(object sender, EventArgs e)
{
    //Hide userControl11 and show userControl21 
}

示例 - 使用接口

我假设您有一个包含一些标准方法的接口:

public interface IDoSomething
{
    void DoSomething();
    void DoSomethingElse();
}

你已经在父表单中实现了接口:

public class Form1: Form, IDoSomething
{
    // ...

    public void DoSomething()
    {
        //Hide userControl11 and show userControl21 
    }
    public void DoSomethingElse()
    {
        // ...
    }
}

然后在你的用户控件中:

private void Button1_Click(object sender, EventArgs e)
{
    var f = FindForm() as IDoSomething;
    if(f!=null)
        f.DoSomething();
}

1
我希望能对Reza Aghaei的回答进行补充,我认为这个方法可以变得更好。
第一种方法:
如果我是你,我会创建一个接口ICheckedView,至少包含一个需要实现的方法。
ICheckedView
{
    void Continue();
}

现在,我们可以将此接口应用于解决方案中的任何类,最有可能是视图。 接下来,我会让您的主窗体实现此接口并实现所需的方法。 在这种情况下,我们希望我们的主窗体从面板中移除控件并添加新控件。坦白地说,我们的安全检查控件不需要(也许不应该)知道其他控件或接下来会发生什么。它只用于控制流程。
最后,您需要向Safety_Check添加一个公共属性或甚至构造函数参数,其中包括ICheckedView。 当单击安全检查控件时,它可以告诉已传递给它的人(我们将称之为客户端),它必须继续。
第二种方法是使用action delegate
如果您向安全检查添加一个 Action 委托,您就可以插入任何签名与该委托匹配的方法 (void methodName())。您的 Safety_Check 控件的构造函数应包括一个 Action,并且该 Action 将被分配给该类的私有字段。然后,在调用时,该操作可以直接被调用。
关于此方法的注意事项
因为我们可能从 UI 线程中调用,所以可能没问题,但是在这里需要考虑线程安全性。调用所需的模式可以帮助您解决这个问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接