0

如果您有时间,请创建一个新的空白应用 (XAML)模板并编写以下 XAML 代码。

我认为创建WPF 应用程序是没有用的,因为它看起来好像容器回收不起作用。此外,GridView必须替换为ListView

<Page.Resources>
  <vm:MainViewModel x:Key="Main" />
</Page.Resources>

<Page.DataContext>
  <Binding Source="{StaticResource Main}" />
</Page.DataContext>

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"
      VerticalAlignment="Center">
  <Grid.Resources>
    <Style x:Key="GridViewStyle1"
           TargetType="GridView">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="GridView">
            <ScrollViewer HorizontalSnapPointsAlignment="Near"
                          HorizontalSnapPointsType="MandatorySingle">
              <ItemsPresenter VirtualizingStackPanel.VirtualizationMode="Standard" />
            </ScrollViewer>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
  </Grid.Resources>
  <GridView Style="{StaticResource GridViewStyle1}"
            ItemsSource="{Binding Items}"
            SelectionMode="None">
    <GridView.ItemTemplate>
      <DataTemplate>
        <StackPanel Orientation="Horizontal"
                    Loaded="StackPanel_Loaded">
          <Grid Width="800"
                Height="400">
            <ScrollViewer HorizontalScrollBarVisibility="Hidden"
                          VerticalScrollBarVisibility="Visible">
              <Border Background="#b7d84b">
                <TextBlock Foreground="Black"
                           Text="{Binding Message}" />
              </Border>
            </ScrollViewer>
          </Grid>
        </StackPanel>
      </DataTemplate>
    </GridView.ItemTemplate>
  </GridView>
</Grid>

创建视图模型和Item类:

public class MainViewModel
{
    private const int NumberOfItems = 10000;

    public ObservableCollection<Item> Items
    {
        get;
        private set;
    }

    public MainViewModel()
    {
        var tempCollection = new ObservableCollection<Item>();

        for (var index = 0; index < NumberOfItems; ++index)
        {
            var item = new Item
            {
                Id = index,
                Message = GetMessage(index)
            };

            tempCollection.Add(item);
        }

        Items = tempCollection;
    }

    private string GetMessage(int index)
    {
        var sb = new StringBuilder();

        for(var i = 0; i < 100; ++i)
        {
            sb.Append("...\n");
        }

        sb.Append("This is item #");
        sb.Append(index);

        return sb.ToString();
    }
}

public class Item
{
    public string Message { get; set; }
    public int Id { get; set; }
}

启动应用程序时,您可以滚动浏览一系列项目。我注意到,当您垂直滚动特定项目以便可以看到“这是项目#x”消息时,您会在向右滚动后再次看到另一条消息“这是项目#x”(尽管您没有滚动项目垂直。)

这是因为项目是虚拟化的。并且当一个项目变为现实时,将使用池中的一个容器。如果你运气不好,容器已经滚动了......

池中有 10 个项目:

代码隐藏文件中的程序输出

文件背后的代码:

private readonly DateTime _start;

public MainPage()
{
    this.InitializeComponent();
    _start = DateTime.Now;
}

[Conditional("DEBUG")]
public void WriteDebugMessage(string message)
{
    var span = DateTime.Now - _start;
    Debug.WriteLine(
        "{0:D2}:{1:D2}:{2:D3} - {3}",
        span.Minutes,
        span.Seconds,
        span.Milliseconds,
        message);
}

private void StackPanel_Loaded(object sender, RoutedEventArgs e)
{
    WriteDebugMessage("StackPanel loaded.");
}

接下来,我重铸了 ItemsPresenter 对象:

<ItemsPresenter VirtualizingStackPanel.VirtualizationMode="Standard"/>

如果它有效,它不会提高性能。

有谁知道这个问题的优雅解决方案?我不想因为公共领域太多而被解雇;)我还考虑过写一个附加属性...

4

1 回答 1

0

更新:

我还是不知道为什么

<ItemsPresenter VirtualizingStackPanel.VirtualizationMode="Standard"/>

不起作用。所以我最新的解决方案是 hack。此外,向左滚动可能会显示一个被放回的项目,尽管您已经垂直滚动了它。我使用 MainPage.xaml.cs 中的附加属性来定义每个垂直ScrollViewer的垂直偏移量:

public static double GetVerticalOffset(DependencyObject obj)
{
    return (double)obj.GetValue(VerticalOffsetProperty);
}

public static void SetVerticalOffset(DependencyObject obj, double value)
{
    obj.SetValue(VerticalOffsetProperty, value);
}

public static readonly DependencyProperty VerticalOffsetProperty =
    DependencyProperty.RegisterAttached("VerticalOffset", typeof(double), typeof(MainPage), new PropertyMetadata(-1.0, OnVerticalOffsetPropertyChanged));

private static void OnVerticalOffsetPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var sv = d as ScrollViewer;
    if (sv != null)
    {
        sv.ScrollToVerticalOffset((double) e.NewValue);
    }
}

每次在数据虚拟化解决方案中请求特定项目的数据时,项目的VerticalOffset属性都会设置为 0。这会触发委托,因为默认值为 -1。

于 2013-04-20T13:02:22.257 回答