【问题标题】:Update a Modeless Dialog from the Main Window with Windows Forms使用 Windows 窗体从主窗口更新无模式对话框
【发布时间】:2012-07-19 23:40:27
【问题描述】:

我正在开发一个 C#/.NET 3.5/Windows 窗体程序。我想创建一个无模式对话框,然后使用从主窗体生成的信息对其进行更新。我发现了其他方向的几个示例 - 对话框中的信息更新了主窗口,但我在相反的方向上遇到了麻烦。对话框中的 GUI 无法正常工作。鼠标光标是一个沙漏。我有时会看到更新,但我经常会看到一个纯白框、曾经位于对话框顶部的其他窗口的残留物,或者它冻结了。

最终,对话框将显示更复杂的信息,但现在我只是尝试复制一个显示为主窗口标签的计数器。要启动对话框,我执行以下操作:

    bool secondWindowOpen = false;
    Thread secondWindowThread;
    MyPopupWindow secondWindow;

    delegate void TextBoxDelegate(string message);

    private void buttonPop_Click(object sender, EventArgs e)
    {
        // If the second window is not open, then open it
        if (!secondWindowOpen)
        {
            secondWindowOpen = true;

            secondWindow = new MyPopupWindow();
            secondWindowThread = new Thread(secondWindow.MyMethod);
            secondWindowThread.Start();

        }
        else // Close the second window
        {
            secondWindowOpen = false;
            secondWindow.ShouldStop = true;

            secondWindowThread.Join();                
        }
    }

我用以下代码更新计数器:

if (secondWindow != null)
{
    secondWindow.CounterText = args.FrameNumber.ToString();
}

控制无模式对话框的代码如下所示。我承认设置文本字段的代码可能是错误的,但这是我目前所做的最好的事情(调用调用给我带来了麻烦)。

public partial class MyPopupWindow : Form
{
    public MyPopupWindow()
    {
        InitializeComponent();
    }

    public bool ShouldStop
    {
        get { return shouldStop; }
        set { shouldStop = value; }
    }
    private bool shouldStop = false;

    public void MyMethod()
    {            
        this.Show();
        this.Refresh();

        while (!shouldStop)
        {
            Thread.Sleep(100);
            labelCounter.Text = CounterText;
            Refresh();
        }

        this.Close();
    }

    public string CounterText;
}

我的主要问题如下:当无模式对话框只需要更新自己的 GUI 元素时,将它放入第二个线程的最佳方法是什么?从主窗口/线程更新这些 GUI 元素的最佳方法是什么?谢谢!

【问题讨论】:

    标签: c# .net winforms


    【解决方案1】:

    表单的工作方式是,如果程序是一个处理消息并将它们传递给要处理的表单的循环,那么其核心是。如果您的表单从未将控制权返回给您的消息循环,则您的程序将停止正常工作。您已尝试通过添加更多线程来解决此问题,但这种方式会导致其自身的痛苦。

    您不能在线程中执行此操作,因为应用于表单的所有操作都必须在 UI 线程上完成。 您可以使用 BeginInvoke 将 Invalidate 之类的调用传回给 UI 线程,但这会变得非常混乱 - 编写在一个 UI 线程上运行的协作窗口要比触发大量线程然后尝试将 UI 线程插入其中要好得多为他们做事。

    为此,您将创建表单,然后将控制权返回给您的消息处理循环。将来,您将通过单击按钮等事件关闭窗口。如果您需要因任何事件而更新窗口,您可以在事件处理程序中调用 invalidate 然后返回。

    【讨论】:

    • 谢谢。我对 Windows 窗体在幕后工作的方式不是很熟悉,所以你的解释很有帮助。最初我开始按照您的建议做一些事情,但是当失败时,我最终陷入了您看到的多线程混乱。现在它正在工作。我将发布我当前代码的示例。
    【解决方案2】:

    根据 Jason 的建议,我最终简化了事情并让它真正发挥作用。

    首先,当我显示第二个窗口时,不再启动新线程。相反,我执行以下操作:

    bool secondWindowOpen = false;
    MyPopupWindow secondWindow;
    
    private void buttonPop_Click(object sender, EventArgs e)
    {
        // If the second window is not open, then open it
        if (!secondWindowOpen)
        {
            secondWindowOpen = true;
            secondWindow = new MyPopupWindow();
            secondWindow.Show();                
        }
        else // Close the second window
        {
            secondWindowOpen = false;
            secondWindow.Close();
        }
    }
    

    然后我将第二个窗口中的代码简化为:

    public partial class MyPopupWindow : Form
    {
        public MyPopupWindow()
        {
            InitializeComponent();
        }
    
        public string CounterText
        {
            set { labelCounter.Text = value; }
        }
    }
    

    【讨论】:

      【解决方案3】:

      首先,请为我的英语道歉,因为我是法国人。

      那么,如果我理解您的问题,您想从第一个表单更新第二个表单的控件。

      请使用表单的 Tag 对象。

      1. 创建一个类来存储要在表单之间传输的数据
      2. 从第一个表单创建第二个表单的实例,如下所示:

        Form2 f = new Form2();
        f.Tag = MyDataObject();

      3. 像这样显示表单

        f.Show() => Modeless wayf.ShowDialog => Modal way

      4. 在 Form2 的构造函数中,您从 Tag 对象更新控件,如下所示:

        public Form2()
        {
        MyDataObject do = (MyDataObject)this.Tag;
        MyLabel.Text = do.LabelText;
        }

      5. 如果你想从 Form2 到主窗体,也可以这样做:

        进入Form2

        this.Tag = MyDataObject;
        this.Close();

      进入主窗体:

      `MyDataObject do = (MyDataObject)f2.Tag;`
      

      我知道这个话题很老,但希望这会有所帮助

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-06
        • 2019-01-01
        • 2017-06-07
        • 2016-10-31
        • 2023-04-06
        • 1970-01-01
        相关资源
        最近更新 更多