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>

ビュー モデルとアイテムクラスを作成します。

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; }
}

アプリを起動すると、一連の項目をスクロールできます。特定のアイテムを縦にスクロールして「This is item #x」というメッセージが表示されると、右にスクロールした後に「This is item #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"/>

それが機能したとしても、パフォーマンスは向上しません。

問題のエレガントな解決策を知っている人はいますか? public フィールドが多すぎるためにクビになりたくない ;) 添付プロパティを書くことも考えました...

4

1 に答える 1

0

更新しました:

なぜだかまだわからない

<ItemsPresenter VirtualizingStackPanel.VirtualizationMode="Standard"/>

動作しません。だから私の最新の解決策はハックです。また、左にスクロールすると、すでに垂直にスクロールしたにもかかわらず、元に戻されたアイテムが表示される場合があります。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 に答える