1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ListView/GridViewで表示範囲のItemVMのみを列挙する

Last updated at Posted at 2023-12-16

ソースコードだけ確認したい場合はこちら - Github gist

用途:表示範囲内に限定して更新処理したい

  • 例え1000件程度のデータだろうと表示範囲外コンテンツの更新処理が行われないようにしたい場合。

方法:ListViewBase.ContainerContentChanging イベントの活用

InRecycleQueue で表示範囲の内外を判定

ContainerContentChanging イベントの InRecycleQueuetrue の場合、表示範囲外にアイテムが出たと判定できます。

private void CutListItemsListView_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
{
    var item = args.Item as StoryboardCutViewModel;
    if (args.InRecycleQueue)
    {
        _vm.RealizedVMItems.Remove(item);
        Debug.WriteLine($"{item} InRecycleQueue");
    }
    else
    {
        _vm.RealizedVMItems.Add(item);    
        Debug.WriteLine($"{item} Displaying!");
    }
}

カスタム添付プロパティとして実装

ListViewExtensions_RealizedCollection.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

#nullable enable
namespace SampleApp.Views.Extensions;

public static partial class ListViewExtensions
{
        public static ICollection<object>? GetRealizedCollection(DependencyObject obj)
    {
        return (ICollection<object>?)obj.GetValue(RealizedCollectionProperty);
    }

    public static void SetRealizedCollection(DependencyObject obj, ICollection<object> value)
    {
        obj.SetValue(RealizedCollectionProperty, value);
    }

    public static readonly DependencyProperty RealizedCollectionProperty =
        DependencyProperty.RegisterAttached("RealizedCollection", typeof(ICollection<object>), typeof(ListViewExtensions), new PropertyMetadata(null, OnRealizedCollectionChanged));

    private static void OnRealizedCollectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var list = (ListViewBase)d;
        if (e.OldValue is ICollection<object> oldCollection)
        {
            list.ContainerContentChanging -= List_ContainerContentChanging;
        }

        if (e.NewValue is ICollection<object> collection)
        {
            list.ContainerContentChanging += List_ContainerContentChanging;
        }
        
        static void List_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
        {
            var collection = GetRealizedCollection(sender);
            if (collection == null)
            {
                sender.ContainerContentChanging -= List_ContainerContentChanging;
                return;
            }

            if (args.InRecycleQueue)
            {
                collection.Remove(args.Item);
            }
            else
            {
                collection.Add(args.Item);
            }
        }
    }
}

DataContextに任意のViewModelインスタンスがセットされてる状態で、以下のように使用します。

<ListView
    ItemsSource="{Binding DisplayItems}"
    xmlns:myViewExt="using:SampleApp.Views.Extensions"
    myViewExt:ListViewExtensions.RealizedCollection="{Binding RealizedVMItems}"
    />

おまけ:表示範囲にIn/Outしたタイミングでコマンドを実行するカスタム添付プロパティ

ListViewExtensions_RealizedCommand.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

#nullable enable
namespace SampleApp.Views.Extensions;

public static partial class ListViewExtensions
{
    public static ICommand? GetRealizedCommand(DependencyObject obj)
    {
        return (ICommand?)obj.GetValue(RealizedCommandProperty);
    }
    
    public static void SetRealizedCommand(DependencyObject obj, ICommand? value)
    {
        obj.SetValue(RealizedCommandProperty, value);
    }
    
    public static readonly DependencyProperty RealizedCommandProperty =
        DependencyProperty.RegisterAttached("RealizedCommand", typeof(ICommand), typeof(ListViewExtensions), new PropertyMetadata(null, OnRealizeCommandPropertyChanged));
    
    
    public static ICommand? GetDerealizedCommand(DependencyObject obj)
    {
        return (ICommand?)obj.GetValue(DerealizedCommandProperty);
    }
    
    public static void SetDerealizedCommand(DependencyObject obj, ICommand? value)
    {
        obj.SetValue(DerealizedCommandProperty, value);
    }
    
    public static readonly DependencyProperty DerealizedCommandProperty =
        DependencyProperty.RegisterAttached("DerealizedCommand", typeof(ICommand), typeof(ListViewExtensions), new PropertyMetadata(null, OnRealizeCommandPropertyChanged));
    
    
    private static void OnRealizeCommandPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var list = (ListViewBase)d;
        if (e.OldValue is ICommand oldCommand)
        {
            list.ContainerContentChanging -= ForCommand_ContainerContentChanging;
        }
    
        if (e.NewValue is ICommand newCommand)
        {
            list.ContainerContentChanging -= ForCommand_ContainerContentChanging;
            list.ContainerContentChanging += ForCommand_ContainerContentChanging;
        }
    }
    
    private static void ForCommand_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
    {
        if ((args.InRecycleQueue ? GetDerealizedCommand(sender) : GetRealizedCommand(sender)) is { } command
            && command.CanExecute(args.Item)
            )
        {
            command.Execute(args.Item);
        }
    }
}

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?