多线程任务表单调用问题,有没有更好的方法来做到这一点? [英] Multithreaded Task Form Invoke Issue, Is there a Better way to do this?

查看:51
本文介绍了多线程任务表单调用问题,有没有更好的方法来做到这一点?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have an application that i wrote that does a few heavy tasks, in which i display a Task Form. This task form shows the current progress, as well as Status text that is set within the heavy tasks thread. The issue I'm coming across right now is that My Invoke call (The UpdateStatus method) is getting called before the form actually has time to display itself, and starts throwing exceptions.

这是我的表格:

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

注意:我确实删掉了一些与我的问题无关的代码

NOTE: I did cut out some code that is none related to my question

问题出在这个例子中:

//显示任务对话框

TaskForm.Show(this, "My Window Title", "Header Text", false);
TaskForm.UpdateStatus("Status Message"); // Exception Thrown HERE!!

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

Without the Thread.Sleep() in the ShowForm() method, i get the dreaded Invoke exception (InvalidOperationException => "Invoke or BeginInvoke cannot be called on a control until the window handle has been created."). Is there a better way to display this form to prevent these issues? I feel guilty having to use a Thread.Sleep() to wait for the GUI to popup like its suppossed to.

推荐答案

您可以使用 IsHandleCreated 属性 [msdn] 判断是否已经创建了窗口句柄.所以不需要 sleep 时间,我们不能保证它是恒定的.

You can use IsHandleCreated Property [msdn] to determine whether the window handle has been created. So no need of a sleep time which we cannot guarantee to be constant.

所以你可以使用类似的东西,

so you can use something like,

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

我已经使用过它并且对我有用,我也欢迎对此解决方案提出任何意见.

I have use this and it worked for me, I welcome any comments regarding this solution too.

这篇关于多线程任务表单调用问题,有没有更好的方法来做到这一点?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆