2012-07-20 37 views
1

我正在研究C#/ .NET 3.5/Windows Forms程序。我想创建一个无模式对话框,然后使用主窗体生成的信息对其进行更新。我发现了其他方向的几个例子 - 来自对话框的信息更新了主窗口,但我遇到了相反的麻烦。对话框中的图形用户界面无法正常工作。鼠标光标是沙漏。我有时会看到更新,但我经常看到一个坚实的白色盒子,其他窗口的残余物曾经在对话框的顶部,或者它冻结。使用Windows窗体从主窗口更新无模式对话框

最终,对话框将显示更复杂的信息,但现在我只是想重复出现的主窗口标签的计数器。要启动对话,我做到以下几点:

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

回答

1

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

您可以在一个线程应用于所有操作的表格必须在UI线程做无法做到这一点。 您可以使用BeginInvoke将调用像Invalidate一样传递给UI线程,但这会变得非常混乱 - 编写在一个UI线程上运行的协作窗口要比触发大量线程然后尝试制作UI线程要好得多为他们做事。

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

+0

感谢。我并不熟悉Windows Forms在封面上的工作方式,因此您的解释有所帮助。最初我开始按照你的建议来做,但是当我失败时,我最终陷入了你看到的多线程混乱中。现在它正在工作。我会发布一个我当前代码的例子。 – GrandAdmiral 2012-07-20 19:31:43

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

仅供参考,我不得不打电话刷新labelCounter – 2015-04-13 13:20:52

0

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

然后,如果我理解你的问题,你想从第一个更新第二种形式的控制。

请使用窗体的标签对象。

  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. 如果你想从窗体2到主窗体做,做同样的:

    进入窗体2

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

进入主要形式有:

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

我知道这个题目是旧的,但希望这有助于

相关问题