2010-01-20 20 views
1

我們已經通過.NET Compact Framework應用程序獲得了Model-View-Presenter設置。一個標準的CF窗體正在實現視圖接口,並傳遞給演示者的構造函數。主持人通過調用view.Run();告訴窗體顯示自己。然後該視圖自身執行一個Show(),並且演示者再次接管,加載數據並將其填充到視圖中。.NET Compact Framework:如何在運行代碼之前確保窗體可見?

問題在於控件返回給演示者之前,視圖沒有完成顯示。由於展示者代碼在加載數據時阻塞了幾秒鐘,其效果是該表單幾秒鐘內不可見。直到演示者完成數據加載後,表單才變得可見,即使在演示者開始加載數據之前,自身的Show()形式本身也是如此。

在標準的Windows環境中,我可以在窗體上使用.Shown事件......但是緊湊框架沒有這個,我找不到等價的東西。

有沒有人知道在開始演示者的一些代碼之前,我的表單是否完全可見,是否存在偶數,拼寫或其他方式?在這一點上,我可以確定表單呼叫主持人,並告訴主持人開始它的數據加載。

僅供參考 - 我們正試圖避免多線程,以減少複雜性和資源使用。

回答

1

如果您的關鍵問題是表單在您的演示者數據加載方法完成之前不會繪製,並且您調用了Form_Load中的this.Show(),請嘗試在此之後直接應用Application.DoEvents() .Show()強制/允許表單繪製。

protected void Form_Load(blah blah blah) 
{ 
    this.Show(); 
    Application.DoEvents(); 

    ... data loading methods ... 
} 
+0

as rediculous as this is,Application.DoEvents()靜態方法解決了問題,而不必使用任何額外的線程。我知道我不是「做正確的事情「並可能導致UI凍結等,但這對於我們所需要的就足夠了。 – 2010-01-20 17:19:04

2

的一般規則是:永遠不做阻塞UI線程

在Windows(和Windows CE爲好)的UI具有異步特性上。這意味着大多數API調用不一定會立即執行它們應該執行的任何操作。相反,它們生成一系列事件,這些事件放入事件隊列中,之後由事件泵檢索,實質上,這是一個在UI線程上運行的無限循環,逐個從隊列中挑選事件並處理它們。

從上面的結論可以得出結論,如果你在請求某個動作(即在你的情況下顯示窗口)之後繼續在UI線程上做很長的事情,事件泵將不能繼續進行拾取事件(因爲你還沒有控制它),因此,你的請求的行動無法完成。

一般方法如下:如果您必須執行復雜的數據轉換/加載/準備/任何,請在單獨的線程上執行它,然後使用Control.BeginInvoke將委託注入UI線程,然後觸摸從該委託內部實際的UI控件。

儘管您對多線程帶來的「複雜性」非常不理智,但很少有人會害怕。這裏有一個小例子來說明這一點:

public void ShowUI() 
{ 
    theForm = new MyForm(); 
    theForm.Show(); 

    // BeginInvoke() will take a new thread from the thread pool 
    // and invoke our delegate on that thread 
    new Action(PrepareData).BeginInvoke(null,null); 
} 

public void PrepareData() 
{ 
    // Prepare your data, do complex computation, etc. 

    // Control.BeginInvoke will put our delegate on the UI event queue 
    // to be retrieved and executed on the UI thread 
    theForm.BeginInvoke(new Action(PutDataInTheForm)); 
} 

public void PutDataInTheForm() 
{ 
    theForm.textBox1.Text = "data is ready!"; 
} 

雖然你可能有其他解決辦法玩,一般的想法始終保持不變:如果你做任何事情,在UI線程上長時間,你的用戶界面將「凍結」。當你在屏幕上添加新的UI元素時,它甚至不會重繪,因爲重畫也是一個異步過程。

因此,您必須在單獨的線程上完成所有複雜和長期的工作,並且只做簡單,小巧,保證在UI線程上運行快速的事情。沒有其他選擇,真的。

希望這會有所幫助。

+0

我對這是解決方案感到樂觀!但BeginInvoke引發NotSupportedException「.NET Compact Framework不支持異步調用委託」。 :( – 2010-01-20 16:05:36

+1

.NET Compact Framework不支持BeginInvoke - 但是,您可以使用ThreadPool.QueueUserWorkItem來執行基本相同的操作。如果要使它看起來更好,請將線程池訪問換成擴展方法: public static IAsyncResult BeginInvoke (This function Func function); – 2010-01-20 16:33:03

0

不需要創建另一個線程,如果你不想(雖然幾秒鐘不得不以某種方式處理)。 您可以使用激活的事件。因爲它會在表單被激活時觸發,所以你需要一個布爾表單本地來檢查表單是否被第一次創建。 另一種選擇是在完成表單呈現後立即斷開事件處理程序。

相關問題