简体   繁体   English

使用Windows窗体从主窗口更新无模式对话框

[英]Update a Modeless Dialog from the Main Window with Windows Forms

I'm working on a C#/.NET 3.5/Windows Forms program. 我正在使用C#/。NET 3.5 / Windows Forms程序。 I would like to create a Modeless Dialog box and then update it with information generated from the main form. 我想创建一个“无模式对话框”,然后使用从主窗体生成的信息对其进行更新。 I've found several examples of the other direction - info from a dialog box updates the main window, but I'm having trouble going in the reverse direction. 我已经找到了另一个方向的示例-对话框中的信息会更新主窗口,但是在反向时遇到了麻烦。 The GUI in the dialog box just doesn't function properly. 对话框中的GUI不能正常运行。 The mouse cursor is an hourglass. 鼠标光标是一个沙漏。 I sometimes see updates, but I often see a solid white box, remnants of other windows that were once on top of the dialog box, or it freezes. 我有时会看到更新,但是我经常会看到一个白色的实心框,曾经位于对话框顶部的其他窗口的残留或冻结。

Eventually the Dialog box will display more complicated information, but for now I'm just trying to duplicate a counter that appears as a label on the Main Window. 最终,对话框将显示更复杂的信息,但是现在我只是想复制一个在主窗口中显示为标签的计数器。 To launch the dialog, I do the following: 要启动对话框,请执行以下操作:

    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();                
        }
    }

I update the counter with the following code: 我使用以下代码更新计数器:

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

The code for controlling the Modeless Dialog box looks like the following. 用于控制“无模式对话框”的代码如下所示。 I'll admit the code for setting the text field is probably wrong, but it's the best thing I have working at the moment (Invoke calls were giving me trouble). 我承认设置文本字段的代码可能是错误的,但这是我目前最好的工作(调用给我带来了麻烦)。

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;
}

My big questions are the following: What is the best way to put a Modeless Dialog Box into a second thread when it just needs to update its own GUI elements? 我的主要问题如下:当仅需要更新自己的GUI元素时,将无模式对话框放入第二个线程的最佳方法是什么? What is the best way to update those GUI elements from the Main Window/Thread? 从主窗口/线程更新那些GUI元素的最佳方法是什么? Thanks! 谢谢!

The way forms work is that at the core if the program is a loop that processes messages and passes them out to the forms to be processed. 表单的工作方式是,如果程序是处理消息并将其传递到要处理的表单的循环,则其核心是核心。 If your form never returns control to your message loop, your program stops working properly. 如果您的窗体从不将控制权返回到消息循环,则程序将停止正常运行。 You've tried to solve this by adding more threads, but that way leads to pain of its own. 您试图通过添加更多线程来解决此问题,但是那样会导致它自己的痛苦。

You can't do this in a thread as all operations applied to your form MUST be done on the UI thread. 您不能在线程中执行此操作,因为应用于表单的所有操作都必须在UI线程上完成。 You could pass back calls like Invalidate to the UI thread using BeginInvoke, but that gets really messy - it's much better to write cooperative windows that run on the one UI thread than to fire off lots of threads that then try to prod the UI thread into doing things for them. 您可以使用BeginInvoke将诸如Invalidate之类的调用传递回UI线程,但这确实很麻烦-编写在一个UI线程上运行的协作窗口比触发许多线程然后尝试将UI线程插入其中要好得多为他们做事。

To do this you would create the form and then return control to your message handling loop. 为此,您将创建表单,然后将控制权返回到消息处理循环。 At a future time you would close the window from an event like a button click. 在将来的某个时间,您将关闭诸如单击按钮之类的事件的窗口。 If you need to update the window as result of any events, you would call invalidate in your event handler and then return. 如果由于任何事件而需要更新窗口,则可以在事件处理程序中调用invalidate然后返回。

Based on Jason's suggestions, I ended up simplifying things and getting it to actually work. 根据Jason的建议,我最终简化了事情并使之真正起作用。

First, no more starting a new thread when I display the second window. 首先,当我显示第二个窗口时,不再需要启动新线程。 Instead, I do the following: 相反,我执行以下操作:

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();
    }
}

Then I simplified the code in the second window to the following: 然后,我将第二个窗口中的代码简化为以下内容:

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

    public string CounterText
    {
        set { labelCounter.Text = value; }
    }
}

First of all, please apologize for my English because I'm french. 首先,因为我是法国人,请为我的英语道歉。

Then, if i understood your problem, you would like to update the controls of a second Form from a first one. 然后,如果我理解您的问题,那么您想从第一个Form更新第二个Form的控件。

please, use the Tag object of the Forms. 请使用表单的Tag对象。

  1. Create a class to stock the Data you want to transmit between the forms 创建一个类以存储要在表单之间传输的数据
  2. Create an instance of the second Form from the first one as this : 从第一个Form创建第二个Form的实例,如下所示:

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

  3. display the Form like 显示形式像

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

  4. In the constructor of your Form2 you update your controls from your Tag object as this : 在Form2的构造函数中,您可以从Tag对象更新控件,如下所示:

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

  5. If you want to do it from the Form2 to the Main Form, do the same : 如果要从Form2到主窗体执行此操作,请执行以下操作:

    Into the Form2 进入Form2

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

Into the Main Form : 进入主要形式:

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

I know the topic is old but hope this helps 我知道这个话题很旧,但希望对您有所帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM