3

ソケットを介してデバイスに接続し、ストリーミングテキストデータ(1秒あたり約1メッセージ)を取得するWPFアプリケーションがあります。このデータはUIに表示されます。ユーザーは、「データに「abc」が含まれている場合は行を強調表示する」「…太字にする」などのルールを作成できるため、プレーンテキスト出力では機能しないため、「リッチ」テキストである必要があります。

これに対する私の現在の解決策は、フォーマットされた出力を含むFlowDocumentをViewModelに含めることです。ビューには、ViewModelのFlowDocumentにバインドされたFlowDocumentScrollViewerがあります。

これは機能しますが、FlowDocumentが大きくなると(約6,000行)、パフォーマンスが低下し始めます。現在のアルゴリズムでは行数が10,000に制限されていますが、状況はさらに悪化し、アプリが使用できなくなります。10,000行に達したら、追加されたすべての行の行を削除します。その結果、FlowDocumentScrollViewerは新しい行ごとに2つの更新通知を受け取ります。

バッチ削除する方法を見つけようとしましたが(10,000行に達したら、最も古い1,000行を削除します)、FlowDocumentに一括削除はありません。1,000回ループして削除を実行すると、1,000回の更新通知が発生し、UIがロックされます。

それが私の問題です、ここに私の質問があります:

WPFを使用してストリーミングリッチテキストコンテンツを表示するための最良の方法は何ですか? 1秒あたり最大1つのメッセージを受け取り、各メッセージは最大150文字であり、最後の10000メッセージを保持したいと思います。私はこれを間違った方法で行っていますか?パフォーマンスが向上する他のコントロール/オブジェクトはありますか?

編集:ここにいくつかの要件があります

  • 出力テキストを印刷できる必要があります
  • 別のドキュメントに貼り付けることができるように、出力テキストを選択してコピーできる必要があります
4

3 に答える 3

5

パフォーマンスの低下は、FlowDocument 内のブロック数が多いことが原因のようです。メッセージを受信するたびに Run を作成し、その Run を Paragraph に追加して、その段落をドキュメントに追加しました。

アルゴリズムを変更したので、パラグラフを作成し、そのパラグラフに 250 ランを追加し、新しいパラグラフを作成し、250 ランを追加します ... などです。これにより、基本的にブロックの数が半分になります。

これには、最大行数 (10,000) に達したときにも利点があります。追加された新しい行ごとに 1 行を削除する (および CPU を固定する) 代わりに、最も古い段落を削除するだけで、最も古い 250 行が即座に削除されます。

この比較的単純な変更により、パフォーマンスが許容範囲内に収まりました。CPU を固定して UI を固定する代わりに、CPU は比較的低く、約 15% のスパイクが発生するようになりました。

于 2009-04-14T15:33:06.313 に答える
0

FlowDocumentScrollViewers は、列などにコンテンツを表示する機能により、オーバーヘッドが発生する可能性があります。通常の WPF RichTextBox が機能しない理由はありますか? また、.NET 3.5 SP1 はありますか? 次のリンクは、SP1 で FlowDocuments のパフォーマンスが大幅に向上したことを示しています: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/a116da54-ce36-446a-8545-3f34e9b9038d

于 2009-04-07T18:18:31.650 に答える
0

この考えは非常に複雑ですが、私の考えでは、メッセージごとに 1 つのビューアーを作成し、現在表示されているメッセージを表示するために必要な数だけビューアーを作成します。VirtualizingStackPanel コントロールは、これを管理するための優れたツールになると思います。ここで、VirtualizingStackPanel の実装について説明しているシリーズを見つけました。

明らかに、これはメッセージ バッファを別のデータ構造に維持することを意味します。

編集:標準の ListBox コントロールがその実装で VirtualizingStackPanel を使用していることに気付きました。これを念頭に置いて、私の修正された提案は次のとおりです。

  1. 各メッセージのソースを含むデータ構造を作成します。
  2. 「その場で」メッセージ ソースから FlowDocument を作成するデータ構造のプロパティを作成します。
  3. ListBox を上記のデータ構造のコレクションにバインドします。
  4. Document プロパティが前述のデータ構造のプロパティにバインドされている FlowDocumentScrollViewer を使用して、ListBox の ItemTemplate を定義します。

編集 2:印刷/ズームについて: WPF での印刷 (おそらく VisualBrush を含むもの) についてはあまり役に立ちませんが、ズームは非常に簡単に行うことができます。このアイデアをテストするために ZoomListBox を作成しました。XAML は次のようになります。

<ListBox
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    x:Class="Test.ZoomListBox"
    d:DesignWidth="640" d:DesignHeight="480"
    x:Name="ThisControl">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel IsItemsHost="True">
                <VirtualizingStackPanel.LayoutTransform>
                    <ScaleTransform ScaleX="{Binding ElementName=ThisControl, Path=Zoom}" ScaleY="{Binding ElementName=ThisControl, Path=Zoom}" />
                </VirtualizingStackPanel.LayoutTransform>
            </VirtualizingStackPanel>
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
</ListBox>

そして、背後にあるコードは次のとおりです。

public partial class ZoomListBox
{
    public ZoomListBox()
    {
        this.InitializeComponent();
    }

    public double Zoom
    {
        get { return (double)GetValue(ZoomProperty); }
        set { SetValue(ZoomProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Zoom.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ZoomProperty =
        DependencyProperty.Register("Zoom", typeof(double), typeof(ZoomListBox), new UIPropertyMetadata(1.0));
}

そしてそれを使用する例:

<Grid x:Name="LayoutRoot">
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <l:ZoomListBox x:Name="ZoomList">
        <Button>Foo</Button>
        <Button>Foo</Button>
        <Button>Foo</Button>
        <Button>Foo</Button>
        <Button>Foo</Button>
        <Button>Foo</Button>
        <Button>Foo</Button>
    </l:ZoomListBox>
    <Slider Grid.Row="1" Value="{Binding ElementName=ZoomList, Path=Zoom}" Minimum="0.5" Maximum="5" /> 
</Grid>
于 2009-04-07T19:36:19.777 に答える