C# 多线程任务表单调用问题,有更好的方法吗?

C# 多线程任务表单调用问题,有更好的方法吗?,c#,multithreading,winforms,C#,Multithreading,Winforms,我有一个我编写的应用程序,它执行一些繁重的任务,在其中我显示一个任务表单。此任务表单显示当前进度,以及在繁重任务线程中设置的状态文本。我现在遇到的问题是,我的Invoke调用(UpdateStatus方法)在表单实际有时间显示自己之前被调用,并开始抛出异常 这是我的表格: public partial class TaskForm : Form { const int WM_SYSCOMMAND = 0x0112; const int SC_MOVE = 0xF010;

我有一个我编写的应用程序,它执行一些繁重的任务,在其中我显示一个任务表单。此任务表单显示当前进度,以及在繁重任务线程中设置的状态文本。我现在遇到的问题是,我的Invoke调用(UpdateStatus方法)在表单实际有时间显示自己之前被调用,并开始抛出异常

这是我的表格:

public partial class TaskForm : Form
{
    const int WM_SYSCOMMAND = 0x0112;
    const int SC_MOVE = 0xF010;

    /// <summary>
    /// The task dialog's instance
    /// </summary>
    private static TaskForm Instance;

    /// <summary>
    /// Private constructor... Use the Show() method rather
    /// </summary>
    private TaskForm()
    {
        InitializeComponent();
    }

    public static void Show(Form Parent, string WindowTitle, string InstructionText, string SubMessage, bool Cancelable, ProgressBarStyle Style, int ProgressBarSteps)
    {
        // Make sure we dont have an already active form
        if (Instance != null && !Instance.IsDisposed)
            throw new Exception("Task Form is already being displayed!");

        // Create new instance
        Instance = new TaskForm();

        // === Instance form is setup here === //
        // Setup progress bar...
        // Hide Instruction panel if Instruction Text is empty...
        // Hide Cancel Button if we cant cancel....
        // Set window position to center parent

        // Run form in a new thread
        Thread thread = new Thread(new ThreadStart(ShowForm));
        thread.IsBackground = true;
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
        Thread.Sleep(500); // Wait for Run to work or the Invoke exceptions are thrown
    }

    public static void CloseForm()
    {
        // No exception here
        if (Instance == null || Instance.IsDisposed)
            return;

        try
        {
            Instance.Invoke((Action)delegate()
            {
                Instance.Close();
                Application.ExitThread();
            });
        }
        catch { }
    }

    protected static void ShowForm()
    {
        Application.Run(Instance);
    }

    public static void UpdateStatus(string Message)
    {
        if (Instance == null || Instance.IsDisposed)
            throw new Exception("Invalid Operation. Please use the Show method before calling any operational methods");

        Instance.Invoke((Action)delegate()
        {
            Instance.labelContent.Text = Message;
        });
    }

    new public void Show()
    {
        base.Show();
    }
}

如果ShowForm()方法中没有Thread.Sleep(),我会遇到可怕的调用异常(InvalidOperationException=>“在创建窗口句柄之前,无法对控件调用Invoke或BeginInvoke”)。是否有更好的方式显示此表单以防止这些问题?我感到内疚,不得不使用Thread.Sleep()来等待GUI像其所支持的那样弹出。

您可以使用
IsHandleCreated
属性来确定是否已创建窗口句柄。所以不需要睡眠时间,我们不能保证睡眠时间是恒定的

所以你可以用

TaskForm.Show(this, "My Window Title", "Header Text", false);
while(!this.IsHandleCreated); // Loop till handle created
TaskForm.UpdateStatus("Status Message");

我用过这个,它对我有用,我也欢迎任何关于这个解决方案的评论。

这太完美了:D。谢谢:D繁重的任务应该在不同的线程上进行,而不是表单…繁重的任务在不同的线程上,然后表单。。。但是UpdateStatus()方法是从重任务线程调用的,如果在显示任务窗体之前调用UpdateStatus()(因为它在新线程中打开,因此不会停止重任务线程),则会发生调用异常。在与主UI窗体相同的线程中显示“任务”窗体,然后在另一个线程中启动重任务。如果要确保表单完全显示,请连接Showed()事件,然后启动繁重的任务线程。
TaskForm.Show(this, "My Window Title", "Header Text", false);
while(!this.IsHandleCreated); // Loop till handle created
TaskForm.UpdateStatus("Status Message");