7

高度に装飾された入力要素を多用するWPFアプリケーションを作成しています。装飾された要素の簡単な例は、フォーカスがない場合は読み取り専用のTextBlockのように見え、フォーカスを受け取るとTextBoxに変わるTextBoxです。また、変更された値がデータベースに保存されるときに、追加の視覚的なフィードバックが提供されます。問題は、これらの要素を多く含むビュー(たとえば、100)を表示するのが非常に遅く、アプリケーションが非常に応答しなくなることです。

このデコレータは、必要なすべての要素を含むUserControlとして実装されています(たとえば、フォーカスのないテキストを表示するTextBlockや、ビジーインジケーターの回転画像)。次に、このデコレータコントロールの子として入力要素を追加します。つまり、すべての追加要素に加えて、デコレータのビジュアルツリーにも入力要素が含まれます。XAMLでは、これは次のようになります。

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

これにより、テキストボックス、日付ピッカー、コンボボックス、カスタム要素など、必要な入力要素を簡単に装飾できます。

ここで問題に戻ります。100個の装飾されたテキストボックスを含むビューがあり、そのビューに移動するとします。何が起こるのですか?少なくとも私のクアッドコアラップトップは、装飾がまだ表示されていませんが、装飾されたすべての要素に視覚的なフィードバックを提供するために何百ものテキストブロック、長方形、画像などを作成する必要があるため、長時間フリーズします。画面に表示されるのは100TextBlockだけなので、実際に必要なのは100TextBlockだけです。他の要素が必要な場合は、要素がマウスオーバーイベントまたはフォーカスを受け取った後でのみです。また、一度に編集される要素は1つだけなので、アプリケーション全体で1つの入力要素(この場合はテキストボックス)だけで十分です。

では、ビュー内のすべての要素に対してすべての装飾要素(または実際の入力要素)を作成せずに同じ装飾を実現するための最良の方法は何でしょうか?


ユースケースを明確にするための装飾されたTextBoxの例:

テキストボックスは、フォーカスがない場合、またはマウスカーソルが現在その上にない場合(状態1)、読み取り専用のTextBlockのように見えます。また、要素には現在値がないため、3つのドット( "...")が表示されます。

マウスカーソルを要素の上に移動すると、TextBlockの周囲に緑色の点線の長方形が表示され、要素を変更できることを示します(状態2)。TextBoxがたまたま読み取り専用だった場合、色は赤になります。

フォーカス要素を受け取った後、実際の値を変更するために使用できる実際のTextBoxに変わります(状態3)。

テキストボックスがフォーカスを失った後、値はデータベースに保存され、値が現在保存されていることを示すために、要素の左側にビジーインジケーターが表示されます(状態4)。

最後に、値が保存され、要素は新しい値を示すアイドル状態に戻ります(状態5)。(実際には、要素には検証やその他の特定の要件に関連するさらに多くの状態がありますが、要素が実際に高度に装飾されていることは確かにわかります。)

ここに画像の説明を入力してください

4

1 に答える 1

4

すべてのUI要素を事前に描画するのではなく、必要なものだけを描画します

WPFでは、Templateを使用してオブジェクトのを変更DataTriggerできるため、トリガーに基づいてデコレータのテンプレートを調整できます。

デコレータのスタイルの例は次のようになります。

<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

ロード時間が修正されない場合、問題はおそらく別の場所にあります。たとえば、一部のデコレータアイテムは、内部に配置されたコンテンツコントロールに応じてサイズが変更されているように見えるため、実際に速度が低下しているのは、オブジェクトを表示するのではなく、オブジェクトのサイズを決定している可能性があります。

于 2013-03-27T13:25:04.033 に答える