簡體   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