2014-05-06 27 views
0

我想在加載表單時防止閃爍。我通過一個新線程加載表單,然後調用回UI。但是由於我在非UI線程上創建表單,覆蓋(CreateParams)不能按預期工作。當我在UI線程上創建它時完美無瑕地工作。我怎樣才能讓它在UI線程上返回時覆蓋它?當不在UI線程上時CreateParams

// 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() 
    { 
    } 
} 
+1

我編輯了你的標題。請參閱「[應該在標題中是否包含」標籤「](http://meta.stackoverflow.com/questions/19190/)」,其中共識是「不,他們不應該」。 –

+0

所以你只想在獨立的線程上運行構造函數,然後將表單遷移到UI線程? –

+0

@DanielBrückner,是的。因爲有時表單在加載時會很慢,我不想凍結UI。 – user3447537

回答

4

不要這樣做。 WinForms控件必須在它們將被使用的線程上創建,並且它們必須從創建它們的線程中使用(唯一的例外是InvokeRequired,Invoke,BeginInvokeEndInvoke)。不遵守這些基本規則將導致失敗。

5

考慮到您正在調用UI線程,它與線程沒有任何關係,這應該不是很明顯。 CreateParams返回的值實際上只在創建本機窗口時才使用。在UI線程上運行的Controls.Add()調用會發生哪種情況。代碼的這方面沒有錯。並且,如果您嘗試設置在錯誤線程上創建的窗口的父級,則會導致程序崩潰。

真正的問題是您正在使用的WS_EX_COMPOSITED樣式標誌。合成僅支持頂級窗口。 Winforms中的Form類。但是你通過將TopLevel屬性設置爲false來擊敗它。樣式標誌只是停止產生效果,對於客戶端窗口沒有其他選擇。您需要將其移至包含此子窗口的父窗體。

+0

我不確定這是否正確。當我在反射器中打開框架時,我看到'Control'的默認構造函數調用內部構造函數'Control(bool)'。第二個構造函數調用'this.CreateParams'(違反了不調用構造函數的規則),當this.DefaultSize返回任何非零大小的部分時調用該構造函數。 Form覆蓋'DefaultSize'將其設置爲{300,300},所以應該在構造函數運行的任何線程上調用'CreateParams'。 –

+0

另外,'Control(bool)'調用了像'InitMouseWheelSupport'和'WindowsFormsSynchronizationContext.InstallIfNeeded'這樣的東西,它們中有一些非常特定於UI線程的代碼。 –

+0

這是無關緊要的,Invoke()當然堅持認爲這已經完成了。 –

相關問題