不在UI线程上的CreateParams

时间:2014-05-06 21:01:32

标签: c# multithreading winforms

我正在尝试阻止加载表单时出现闪烁。我正在通过新线程加载表单,然后调用回UI。但由于我在非UI线程上创建表单,因此覆盖(CreateParams)无法正常工作。当我在UI线程上创建它时,它可以完美地工作。如何在它回到UI线程时覆盖它?

// How the loading is done, from UI thread
Thread GetPage = new Thread(() => LoadPage<T>(panel));

public static void LoadPage<T>(Panel Panel)
{ 
  Form form = Activator.CreateInstance(typeof(T)) as Form;

  // Now invoke to UI
   Panel.Invoke((MethodInvoker)delegate
   {
       form.TopLevel = false;
       form.AutoScroll = true;
       Panel.Controls.Add(form);
       form.Show();
   }
}

// Example of a form

public partial class Start : Form
{
    protected override CreateParams CreateParams { get { CreateParams cp =     
             base.CreateParams; cp.ExStyle |= 0x02000000; return cp; } }

    public Start()
    {
    }
 }

2 个答案:

答案 0 :(得分:5)

考虑到你正在调用UI线程,它与线程没有任何关系应该是显而易见的。事实上,只有在创建本机窗口时才会使用CreateParams返回的值。在Controls.Add()调用中会发生这种情况,该调用在UI线程上运行。代码的这个方面没有错。如果你试图设置在错误的线程上创建的窗口的父级,那么你需要崩溃程序。

真正的问题是您正在使用的WS_EX_COMPOSITED样式标志。只有顶级窗口才支持合成。 Winforms中的Form类。但是你通过将TopLevel属性设置为 false 来击败它。样式标志只是停止生效,对于客户端窗口没有其他选择。您需要将其移动到包含此子窗口的父窗体。

答案 1 :(得分:4)

不要这样做。必须在将要使用它们的线程上创建WinForms控件,并且必须在创建它们的线程中使用它们(唯一的例外是InvokeRequiredInvoke,{{1}和BeginInvoke)。不遵守这些基本规则将导致失败。