2013-03-27 108 views
7

我們正在創建一個大量使用高度裝飾的輸入元素的WPF應用程序。裝飾元素的一個簡單示例是TextBox,它在沒有焦點時看起來像只讀TextBlock,並在接收焦點後變爲TextBox。另外,當更改的值被保存到數據庫時會提供額外的視覺反饋。問題是,顯示一個包含很多這些元素的視圖(比方說100)非常慢,並且使應用程序非常無響應。如何在WPF中懶洋洋地創建UI元素?

我們已經實現了這個裝飾器作爲用戶控件,它包含所有必需的元素(例如TextBlock顯示未聚焦的文本和旋轉圖像忙標誌)。然後,我們將輸入元素添加爲此裝飾器控件的子元素,這意味着除了所有額外的元素之外,裝飾器還在其可視化樹中包含輸入元素。在XAML,這將是這樣的:

<custom:Decorator Context="{Binding ValueHelper}" > 
    <TextBox Text="{Binding ValueHelper.Text}"/> 
</custom:Decorator> 

這很容易讓我們來裝點我們想要的任何輸入元素,無論是任何一個文本框中,日期選擇器,組合框或任何自定義元素。

現在回到問題:比方說,我們有一個視圖,其中包含100個裝飾文本框,我們導航到該視圖。怎麼了?至少我的四核筆記本電腦凍結很長一段時間,因爲它必須創建許多文本塊,矩形,圖像等,以提供每個裝飾元素的視覺反饋,儘管沒有裝飾品可見但。真正需要的僅僅是100個TextBlocks,因爲這是屏幕上可見的。只有在元素接收到鼠標懸停事件後,或者在需要其他元素時才關注。而且,一次只能編輯一個元素,因此只有一個輸入元素(在這種情況下是文本框)對於整個應用程序就足夠了。

那麼,如何在不爲視圖中的每個元素創建所有裝飾元素(或實際輸入元素)的情況下實現相同裝飾的最佳方式是什麼?


裝飾文本框,以澄清使用情況的一個例子:

文本框時像沒有焦點或鼠標光標,只讀TextBlock的目前並未在它的上面(狀態1)。此外,還顯示了三個點(「...」),因爲元素不會有任何價值。

當鼠標光標移動到元素的頂部時,TextBlock周圍出現一個綠色的虛線矩形,表示該元素可以被修改(狀態2)。如果TextBox碰巧是隻讀的,顏色將會變成紅色。

接收聚焦元件後變成可用於修改的實際值(狀態3)實際文本框。

文本框失去它的焦點之後,並表明,該值正在被保存忙指示符顯得元件(狀態4)的左邊的值存儲到數據庫中。

最後,該值已被保存和元件返回到表示新的值(狀態5)它的空閒狀態。 (實際上這些元素有更多的狀態與驗證和其他特定要求有關,但是您肯定知道元素真的是高度裝飾的。)

enter image description here

回答

4

除了繪製所有的UI元素前期的,只畫出了那些需要

WPF允許你修改使用DataTrigger對象的Template,這樣你就可以調整模板您根據您的觸發器

裝飾你的裝飾一個例子風格可能會是這個樣子:

<Style TargetType="{x:Type ContentControl}"> 
    <!-- Default Template --> 
    <Setter Property="ContentTemplate" 
      Value="{StaticResource NoDecoratorTemplate}" /> 

    <Style.Triggers> 
     <DataTrigger Property="Text" Value=""> 
      <Setter Property="ContentTemplate" 
        Value="{StaticResource BlankTemplate}" /> 
     </DataTrigger> 
     <Trigger Property="IsMouseOver" Value="True"> 
      <Setter Property="ContentTemplate" 
        Value="{StaticResource MouseOverTemplate}" /> 
     </Trigger> 
     <Trigger Property="IsFocused" Value="True"> 
      <Setter Property="ContentTemplate" 
        Value="{StaticResource FocusedTemplate}" /> 
     </Trigger> 
     <DataTrigger Property="{Binding IsLoading}" Value="True"> 
      <Setter Property="ContentTemplate" 
        Value="{StaticResource LoadingTemplate}" /> 
     </DataTrigger> 
    </Style.Triggers> 
</Style> 

另外,WPF不應該加載不可見的項目。你可以嘗試設置你的修飾器Visibility="Collapsed"作爲測試,看看是否修復加載時間。

如果它不和你不想去Template路線,你可以確保所有對象的Visibility設置爲Collapsed,首先,他們只得到設置爲Visible時,他們應該顯示。

如果不解決您的加載時間,那麼您的問題可能是在其他地方。例如,它看起來像一些裝飾器項目是根據放置在其中的內容控件進行大小設置的,所以可能導致實際速度變慢的不是顯示對象,而是確定對象的大小。

+0

謝謝!控件模板絕對是裝飾元素的方式。但是,這並不能解決實際輸入元素的問題。 TextBox是我們最輕的元素,我們有更重的自定義輸入元素(例如日期選擇器),我們無法創建。我們已經設置了可見性來摺疊,但仍然會創建可視化樹,並加載所有相關資源,這會導致嚴重的性能問題。 – user544511 2013-03-28 08:04:43

+0

@ user544511當你說「所有相關資源被加載」時,你的意思是每個裝飾器都被加載了嗎?因爲如果你使用的裝飾一個UI控制和換出的模板,因爲只有一個元素在視覺樹同時 – Rachel 2013-03-28 11:52:10

+0

對不起,我正在度假,不能剛纔的答覆存在,你不應該讓這種行爲。我的意思是創建了實際的輸入元素(這是裝飾器的子元素,例如日期選取器或文本框),它的所有資源(包括子元素)都被加載並添加到可視樹中(即使它已摺疊)。這導致巨大的性能下降,因爲日期選擇器的元素比例如重量要大得多。一個文本框。 – user544511 2013-04-02 11:08:57