繁体   English   中英

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

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

我正在使用C#/。NET 3.5 / Windows Forms程序。 我想创建一个“无模式对话框”,然后使用从主窗体生成的信息对其进行更新。 我已经找到了另一个方向的示例-对话框中的信息会更新主窗口,但是在反向时遇到了麻烦。 对话框中的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元素的最佳方法是什么? 谢谢!

表单的工作方式是,如果程序是处理消息并将其传递到要处理的表单的循环,则其核心是核心。 如果您的窗体从不将控制权返回到消息循环,则程序将停止正常运行。 您试图通过添加更多线程来解决此问题,但是那样会导致它自己的痛苦。

您不能在线程中执行此操作,因为应用于表单的所有操作都必须在UI线程上完成。 您可以使用BeginInvoke将诸如Invalidate之类的调用传递回UI线程,但这确实很麻烦-编写在一个UI线程上运行的协作窗口比触发许多线程然后尝试将UI线程插入其中要好得多为他们做事。

为此,您将创建表单,然后将控制权返回到消息处理循环。 在将来的某个时间,您将关闭诸如单击按钮之类的事件的窗口。 如果由于任何事件而需要更新窗口,则可以在事件处理程序中调用invalidate然后返回。

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

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

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

请使用表单的Tag对象。

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

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

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

暂无
暂无

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

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