この考えは非常に複雑ですが、私の考えでは、メッセージごとに 1 つのビューアーを作成し、現在表示されているメッセージを表示するために必要な数だけビューアーを作成します。VirtualizingStackPanel コントロールは、これを管理するための優れたツールになると思います。ここで、VirtualizingStackPanel の実装について説明しているシリーズを見つけました。
明らかに、これはメッセージ バッファを別のデータ構造に維持することを意味します。
編集:標準の ListBox コントロールがその実装で VirtualizingStackPanel を使用していることに気付きました。これを念頭に置いて、私の修正された提案は次のとおりです。
- 各メッセージのソースを含むデータ構造を作成します。
- 「その場で」メッセージ ソースから FlowDocument を作成するデータ構造のプロパティを作成します。
- ListBox を上記のデータ構造のコレクションにバインドします。
- 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>