1

我有一个带有网格的 Windows 8 XAML 页面,其中显示了 100 多种不同字体的示例文本。每个网格视图项中的示例文本都是相同的,并且可以使用页面顶部的文本框进行更改。

每次您键入一个字符时,所有网格视图项都会更新。问题是这明显很慢。特别是如果您快速打字。

我不确定是什么让它这么慢。它是否更新了所有网格视图项目,包括不在屏幕上的项目?是其他什么原因导致了这个问题,而这个特殊的绑定只是一个红鲱鱼?

这是我的绑定代码(我从数据模板中删除了一些 xaml 以使其更清晰):

<ScrollViewer>
    <GridView x:Name="FontGridView" ItemsSource="{Binding Fonts}" SelectionMode="Multiple"  Margin="116,0,40,46">
        <GridView.ItemTemplate>
            <DataTemplate>
                <Grid Width="600" MinHeight="100" MaxHeight="120">
                    <TextBox Text="{Binding ElementName=pageRoot, Path=DataContext.SampleText, Mode=OneWay}"
                                FontFamily="{Binding FamilyName}" FontSize="32" Background="Transparent" />
                </Grid>
            </DataTemplate>
        </GridView.ItemTemplate>
    </GridView>
</ScrollViewer>

有没有更好的方法来做到这一点,或者我可以打开任何其他性能调整的东西吗?

更新:自从 Visual Studio 2012 RC 发布以来,您不太可能犯此错误。WinRT 应用程序的模板不再以这种方式使用 ScrollViewer。对于那些移植了他们使用 Visual Studio 2011 创建的应用程序的人,我在这里保留了这个问题。

4

3 回答 3

2

尝试删除 ScrollViewer。

因为 GridView 在滚动查看器内部,所以它实际上被赋予了无限的宽度。这可能会杀死 GridView 中 WrapGrid 的虚拟化。

此外,GridView 内部已经包含一个 ScrollViewer。显然,您不需要其中两个。但是内部的 ScrollViewer 也会吃掉鼠标滚轮事件,而没有给外部 ScrollViewer 做出反应的事件。因此,用鼠标滚动将不起作用。

Visual Studio 11 (bèta 1) 模板包含这样的代码,用于在 GridView 上设置边距。但是,最好在 GridView 的 ItemsPanel 上设置一个边距,如下所示:

<GridView x:Name="FontGridView" ItemsSource="{Binding Fonts}" SelectionMode="Multiple">
  <GridView.ItemTemplate>
    <DataTemplate>
      <Grid Width="600" MinHeight="100" MaxHeight="120">
        <TextBox Text="{Binding ElementName=pageRoot, Path=DataContext.SampleText, Mode=OneWay}"
                 FontFamily="{Binding FamilyName}" FontSize="32" Background="Transparent" />
      </Grid>
    </DataTemplate>
  </GridView.ItemTemplate>
  <GridView.ItemsPanel>
    <ItemsPanelTemplate>
      <WrapGrid x:Name="itemGridViewPanel" Margin="116,53,116,46"/>
    </ItemsPanelTemplate>
  </GridView.ItemsPanel>
</GridView>

您的原始代码不包括您在 GridView 上设置的边距。但不管它是什么,在 WrapGrid 上设置相同的边距。

另请注意,我给 WrapGrid 起了一个名字。您可以使用该名称在屏幕方向更改时更改边距,通常如下所示:

<VisualStateManager.VisualStateGroups>
  <VisualStateGroup>
    <VisualState x:Name="FullScreenLandscape"/>
    <VisualState x:Name="Filled"/>
    <VisualState x:Name="FullScreenPortrait">
      <Storyboard>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemGridViewPanel"
                                       Storyboard.TargetProperty="Margin">
          <DiscreteObjectKeyFrame KeyTime="0" 
                                  Value="96,53,96,46"/>
        </ObjectAnimationUsingKeyFrames>
      </Storyboard>
    </VisualState>
    <VisualState x:Name="Snapped"/>
  </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

更新:

我以前做过这个,但是使用了 VariableSizedWrapGrid。这会产生正确的布局,但不幸的是,我担心 VariableSizedWrapGrid 不是虚拟化面板。

WrapGrid 正在虚拟化,但滚动时左边距的行为似乎错误。但它在右边距是正确的。

哦,好吧,在两周内,我们应该有可用的候选版本。希望情况会有所改善...

更新:

微软似乎意识到了这一点。请参阅http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/17385f7d-aadc-4edc-bbff-8738a2f0c917

更新:

似乎 WrapGrid 尚未在候选版本中修复。

于 2012-05-25T23:51:08.940 回答
1

简化您的数据模板。

<DataTemplate>
  <TextBlock Text="{Binding ElementName=pageRoot, Path=DataContext.SampleText}"
             Width="600" MinHeight="100" MaxHeight="120"
             FontFamily="{Binding FamilyName}" FontSize="32" />
</DataTemplate>

你不需要网格。看起来你也不需要一个(复杂的)TextBox,只需要一个(简单的)TextBlock。

此外,固定这些文本块 ( ) 的高度Height="120"可能有助于(优化)布局过程。

更新:

我知道你的代码是从“真实的东西”简化而来的。但这可能隐藏了我们真正的问题。请记住,数据模板针对屏幕上的每个项目进行了实例化。越复杂,需要实例化的对象就越多(CPU 和内存使用),可能需要数据绑定(CPU),需要测量和布局(CPU),需要渲染(CPU 和 GPU)。

只需使用非常简单的数据模板进行测试。如果你的程序现在更快了,或者不是,你知道数据模板是否是性能问题。

请注意,数据模板的复杂性不是通过您需要描述它的 xaml 元素的数量来衡量的,因为这些元素可能具有非常不同的内部复杂性。例如,如果您需要做的只是显示文本,不允许编辑,则更喜欢 TextBlock 而不是 TextBox。

此外,如果其中一些元素设置了很多属性,请使用样式来设置它们。在许多对象上使用样式比在许多对象上设置许多属性更有效,尤其是在内存使用方面。而且您使用的内存越少,您的程序就会越快(由于现代 CPU 多级缓存架构)。

例如:

<GridView x:Name="FontGridView" ItemsSource="{Binding Fonts}" SelectionMode="Multiple">
  <GridView.Resources>
    <Style TargetType="TextBlock">
      <Setter Property="Width" Value="600" />
      <Setter Property="MinHeight" Value="100" />
      <Setter Property="MaxHeight" Value="120" />
      <Setter Property="FontSize" Value="32" />
    </Style>
  </GridView.Resources>
  <GridView.ItemTemplate>
    <DataTemplate>
      <TextBlock Text="{Binding ElementName=pageRoot, Path=DataContext.SampleText}"
                 FontFamily="{Binding FamilyName}" />
    </DataTemplate>
  </GridView.ItemTemplate>
</GridView>
于 2012-05-25T19:23:49.037 回答
0

尝试使用 VirtualizingStackPanel

<GridView.ItemsPanel>
    <ItemsPanelTemplate>
        <VirtualizingStackPanel Orientation="Horizontal"/>
    </ItemsPanelTemplate>
</GridView.ItemsPanel>
于 2012-05-25T17:30:30.580 回答