2

我正在开发 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 元素的最佳方法是什么?谢谢!

4

3 回答 3

1

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

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

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

于 2012-07-20T17:23:20.103 回答
0

根据 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; }
    }
}
于 2012-07-20T19:29:47.400 回答
0

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

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

请使用表单的标签对象。

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

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

  3. 显示表单

    f.Show() => Modeless way或者f.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;`

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

于 2013-10-03T09:59:07.387 回答