目標: スクロールビューアの仮想化スタック パネルに表示されているシグナルグラフのみを再測定して再描画します。
現在のビルド:
現在、スクロールビューアー (シグナルグラフ) のコンテナーが更新されるたびに測定に影響を与える依存関係プロパティ (UnitsOfTimePerAxisDivision) があります。
public static readonly DependencyProperty UnitsOfTimePerAxisDivisionProperty =
DependencyProperty.Register("UnitsOfTimePerAxisDivision",
typeof(int), typeof(SignalGraph),
new FrameworkPropertyMetadata(1), FrameworkPropertyMetadataOptions.AffectsMeasure);
ただし、これにより、表示されていないものも含め、すべてのシグナルグラフが更新されます。すべての信号に対して測定を実行してから再描画するのは、時間がかかりすぎます。
- 表示されているものだけを更新するにはどうすればよいですか?
こんな実験をしようと思ったのですが、
WPF では、コントロールがユーザーに表示されるかどうかをどのように判断できますか?
基本的に、各シグナルが表示されるかどうかをテストする propertychangedcallback を設定します。最終的にすべての信号をテストすることになりますが、少なくともすべての信号を描画することはありません。
私の2番目の質問は、測定/配置で呼び出される関数に依存してこれを実装できる方法があるかどうかです.
スタック パネルの仮想化に関する私の理解は次のとおりです。トップ レベルには、スクロールビューアを含むツリービューがあります。scrollviewer の controltemplate には、scrollcontentpresenter が設定されたサイズの列と行内にアイテムを配置するグリッドが含まれています。
ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ScrollContentPresenter
Grid.Column="0"
Grid.Row="0" />
<ScrollBar
Margin="{Binding RelativeSource={RelativeSource AncestorType={x:Type DaedalusGraphViewer:GraphViewer}},
Path=GraphHeight, Converter={StaticResource ScrollBarTopMarginConverter}}"
Grid.Row="0"
Grid.Column="1"
Width="18"
Name="PART_VerticalScrollBar"
Orientation="Vertical"
Value="{TemplateBinding VerticalOffset}"
Maximum="{TemplateBinding ScrollableHeight}"
ViewportSize="{TemplateBinding ViewportHeight}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"/>
<ScrollBar
Height="18"
Name="PART_HorizontalScrollBar"
Orientation="Horizontal"
Grid.Row="1"
Grid.Column="0"
Value="{TemplateBinding HorizontalOffset}"
Maximum="{TemplateBinding ScrollableWidth}"
ViewportSize="{TemplateBinding ViewportWidth}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/>
</Grid>
</ControlTemplate>
ですから、scrollviewer に再測定するよう指示し、scrollviewer が画面上で 100x100 を占めるとしましょう。これにより、利用可能なサイズが 100x100 の grids.measure(利用可能なサイズ) を呼び出して、スクロールビューアーがグリッドを測定します。
次に、グリッドはスクロールバーのサイズを差し引き (10 と推測します)、scrollviewerpresenter にそれ自体を 90x90 で測定するように指示します。プレゼンターは仮想化スタックパネルを使用します。これにより、子供たちは無限のサイズで自分自身を測定できます (垂直方向と水平方向の両方であると思います)。ただし、仮想化スタック パネルは、90x90 のサイズがいっぱいになるまで子 (シグナルグラフ) のみを測定し、その後、配置フェーズはスクロールビューアーから仮想化スタック パネルに進みます。
その場合は、signalgraph の Arrange メソッドの最後で呼び出しを行うことができ、画面上のシグナルグラフのみを配置して再描画する必要があります。
protected override Size ArrangeOverride(Size finalSize)
{
visuals.Clear();
DrawSignal();
return base.ArrangeOverride(finalSize);
}
ただし、スクロールビューアーとシグナルグラフの両方のメジャーオーバーライドにブレークポイントを設定すると、シグナルグラフのブレークポイントがヒットしません。
スクロールビューアを再測定すると、シグナルグラフが再測定されない理由がわかりません。
メジャー関数が、親から渡された最後のサイズ制約 (availableSize) を格納し、制約が変更されない限り、新しいメジャーを実行しない場合はありますか? 測定にならない可能性があると私が考えたもう1つの可能性は、スクロールビューアが子のサイズとは無関係にサイズを計算し、サイズが新しい場合にのみそれらを測定する場合です。
しかし、おそらく問題はこのようなものです。誰かがリフレクターを持っていて、実際のスクロールビューアーのメジャーオーバーライド コードを入手できたら、それは素晴らしいことです。そうでない場合は、明日リフレクターを入手して、その使用方法を見つけようとするかもしれません.
override Measureoverride ( size availableSize) { Size newSize = availableSize. if (availableSize != this.DesiredSize) { Chilren() を測定します。} }
そうでない場合、シグナルグラフが測定されない原因は何ですか?
編集:
ええ、仮想化するものがあります。私は完全に頭がおかしいわけではありません。ほとんどクレイジーです。このスタイルを適用すると、仮想化が壊れてしまうようです。それを削除すると、すべてが機能します。
組み込みの仮想化を使用することは、存在する各シグナルグラフの可視性を実際にテストしようとするよりもはるかに優れています。上記の #2 に対する答えはまだわかりませんが、この仮想化を機能させることができれば、それは必要ありません。ただし、現在のスタイルを維持し、そのスタイルが仮想化を壊している理由を理解したいと思います。
<!--Style for scrollviewer for signals-->
<Style x:Key="SignalScrollViewerStyle" TargetType="{x:Type Components:SignalScrollViewer}">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ScrollContentPresenter
Grid.Column="0"
Grid.Row="0" />
<ScrollBar
Margin="{Binding RelativeSource={RelativeSource AncestorType={x:Type DaedalusGraphViewer:GraphViewer}},
Path=GraphHeight, Converter={StaticResource ScrollBarTopMarginConverter}}"
Grid.Row="0"
Grid.Column="1"
Width="18"
Name="PART_VerticalScrollBar"
Orientation="Vertical"
Value="{TemplateBinding VerticalOffset}"
Maximum="{TemplateBinding ScrollableHeight}"
ViewportSize="{TemplateBinding ViewportHeight}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"/>
<ScrollBar
Height="18"
Name="PART_HorizontalScrollBar"
Orientation="Horizontal"
Grid.Row="1"
Grid.Column="0"
Value="{TemplateBinding HorizontalOffset}"
Maximum="{TemplateBinding ScrollableWidth}"
ViewportSize="{TemplateBinding ViewportWidth}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
編集2:
このページで解決策を見つけました: このページで解決策を見つけました:
デフォルトの scrollviewer スタイルをオーバーライドするときに、添付プロパティを scrollviewer contentpresenter にバインドしませんでした。うーん、その1行を見つけるのがどれほど難しいかは驚くべきことです。私は、仮想化が実際に何をするべきなのかわからないと思って、頭がおかしくなりました。
今の唯一の厄介な点は、レイアウト プロセスがどのように機能するかをまだ完全に理解していないことです。依存関係プロパティに metadaoption Effectsmeasure が指定されている場合、依存関係プロパティが変更されると、項目が再測定されます。要素のサイズが変更された場合、親は再測定しますか?
それは私の推測ですが、スクロールビューアの測定サイクル中に再測定されなかったスクロールビューアの子があった理由はまだ説明されていません。