0

目标:重新测量,然后仅重绘那些在滚动查看器的虚拟化堆栈面板中显示的信号图。

当前版本:

目前我有一个依赖属性(UnitsOfTimePerAxisDivision),只要滚动查看器(信号图)中的容器更新,它就会影响度量。

public static readonly DependencyProperty UnitsOfTimePerAxisDivisionProperty =
      DependencyProperty.Register("UnitsOfTimePerAxisDivision",
      typeof(int), typeof(SignalGraph),
      new FrameworkPropertyMetadata(1), FrameworkPropertyMetadataOptions.AffectsMeasure);

但是,这会更新每个信号图,包括那些不可见的信号图。运行测量然后重绘每个信号太耗时了。

  1. 我怎样才能只更新可见的?

我想过做一些这样的测试,

在 WPF 中,如何确定控件是否对用户可见?

通过基本上设置一个propertychangedcallback,我在其中测试每个信号是否可见。我最终还是会测试所有的信号,但至少我不会画出所有的信号。

我的第二个问题是是否有某种方法可以通过在测量/排列中调用的函数来实现这一点。

我对虚拟化堆栈面板的理解如下:在顶层,我们有一个包含滚动查看器的树视图。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(available size) 来测量网格。

然后网格减去滚动条的大小(我们只猜十个),并告诉 scrollviewerpresenter 用 90x90 来衡量自己。演示者使用虚拟化堆栈面板,然后给孩子们无限的大小来测量自己(我认为是垂直和水平)。但是,虚拟化堆栈面板仅测量子级(信号图),直到它填充了 90x90 的大小,然后排列阶段从滚动查看器向下进行到虚拟化堆栈面板。

如果是这种情况,我可以在信号图的排列方法的末尾进行调用,并且只应排列和重绘屏幕上的信号图。

  protected override Size ArrangeOverride(Size finalSize)
    {
      visuals.Clear();
      DrawSignal();
      return base.ArrangeOverride(finalSize);
    }

但是,我发现当我为滚动查看器和信号图在测量覆盖中设置断点时,信号图中的断点没有被命中。

如果重新测量滚动查看器,我无法理解为什么不重新测量信号图。

  1. 测量函数是否存储了其父级传递给它的最后一个大小约束(availableSize),然后除非约束改变,否则不执行新的测量?我认为可能导致无法测量的另一种可能性是,滚动查看器是否独立于其子项的大小计算其大小,然后仅在大小是新的时才测量它们。

    但也许问题是这样的。如果有人有反射器并且可以给我实际的滚动查看器测量覆盖代码,那将是惊人的。如果没有,我明天可能会尝试获得反射器并弄清楚如何使用它。

    覆盖Measureoverride(大小availableSize){大小newSize = availableSize。if (availableSize != this.DesiredSize) { 测量 chilren(); } }

  2. 如果不是这种情况,那么是什么原因导致无法测量信号图?

编辑:

是的,我有一些东西要虚拟化。我并不完全疯了。主要是疯了。应用这种风格似乎打破了虚拟化。删除它使一切正常。

使用内置的虚拟化比尝试实际测试每个存在的信号图的可见性要好得多。我仍然不知道上面#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:

在此页面上找到了解决方案: 我在此页面上找到了解决方案:

" http://social.msdn.microsoft.com/Forums/vstudio/en-US/deae32d8-d7e2-4737-8c05-bbd860289425/lost-virtualization-on-styled-scrollviewer?forum=wpf

覆盖默认滚动查看器样式时,我没有将附加属性绑定到滚动查看器内容演示器。呃,令人惊讶的是,这条线是多么难以找到。我快疯了,以为我不知道虚拟化实际上应该做什么。

现在唯一麻烦的是我还没有完全理解布局过程是如何工作的。如果我有一个带有 metadaoption 影响测量的依赖属性,然后依赖属性发生变化,该项目将重新测量。如果元素的大小发生变化,父母会重新测量吗?

这将是我的猜测,但它仍然不能解释为什么我有 scrollviewer 的孩子在 scrollviewer 的测量周期中没有重新测量。

4

2 回答 2

1

使用反射器没有意义。VirtualizingStackPanel 维护一个可见容器的列表。当您开始向上或向下滚动时,VirtualizingStackPanel 将删除不再需要的容器,但会创建新容器。最后移除 5 个旧项目但添加 5 个新项目,因此可见容器的数量始终保持不变,因此只需更改属性 UnitsOfTimePerAxisDivision 并且不用担心哪些容器是可见的。

如果 ScrollViewer 将 90x90 传递给 VirtualizingStackPanel 并且 VirtualizingStackPanel 将无穷大传递给容器,则容器只会在处于无效测量状态时重新测量,否则它们会返回其当前大小的“旧”大小。

只需让 WPF 完成工作,不必担心性能问题。VirtualizingStackPanel 拥有可见的容器,因此不会对所有可能的容器进行任何重新测量或性能影响。即使您有 1000 个项目,也只会使用 20 个。

于 2013-10-04T07:16:52.703 回答
0

所以问题是我未能以我的滚动查看器样式将 cancontentscroll 属性附加到我的滚动内容演示者。

 <ScrollContentPresenter 
                CanContentScroll="{TemplateBinding ScrollViewer.CanContentScroll}"
于 2013-10-04T23:13:25.847 回答