如何在 .Net MAUI 中始终保持 CollectionView 滚动到底部

huangapple go评论116阅读模式
英文:

How to keep CollectionView scrolled to bottom always in .Net MAUI

问题

I want to create a Log window using CollectionView. Whenever a new item is added, it should automatically scroll to the bottom. I attempted to implement this functionality using a behavior for easy code portability. Here's how I wrote the behavior:

namespace Behaviors;

public class ScrollToBottomBehavior
{
    public static readonly BindableProperty DataSourceProperty =
        BindableProperty.CreateAttached("DataSource",
                                        typeof(object),
                                        typeof(ScrollToBottomBehavior),
                                        null,
                                        BindingMode.TwoWay,
                                        propertyChanged: OnDataSourceChanged);

    public static int GetDataSource(BindableObject view) => (int)view.GetValue(DataSourceProperty);

    public static void SetDataSource(BindableObject view, int value) => view.SetValue(DataSourceProperty, value);

    private static void OnDataSourceChanged(BindableObject sender, object oldValue, object newValue)
    {
        if (sender is not CollectionView view) return;
        if (newValue is not ObservableCollection<object> collection) return;
        view?.ScrollTo(collection.Count - 1, position: ScrollToPosition.End);
    }
}

However, I failed because the Add method of ObservableCollection does not trigger the PropertyChanged event.

I also tried manually setting the SelectedItem to the last item of the ObservableCollection every time an item was added, but this didn't make the CollectionView scroll to the bottom automatically.

I have a couple of ideas:

  1. Modify the ObservableCollection to notify on Add, or
  2. Modify the CollectionView to add a ScrollToBottom property, as shown below, but I still encountered failure.
internal class CollectionViewExtended : CollectionView
{
    public static readonly BindableProperty ScrollToButtomProperty =
        BindableProperty.Create(nameof(ScrollToButtom), typeof(bool), typeof(CollectionViewExtended), false);

    public bool ScrollToButtom
    {
        get => (bool)GetValue(ScrollToButtomProperty);
        set => SetValue(ScrollToButtomProperty, value);
    }

    protected override void OnChildAdded(Element child)
    {
        base.OnChildAdded(child);
        if (ScrollToButtom)
        {
            ScrollTo(child, position: ScrollToPosition.End, animate: true);
        }
    }
}

Any suggestions will be thankful.

英文:

I want to create a Log window using CollectionView. Whenever a new item is added, it should automatically scroll to the bottom. I attempted to implement this functionality using a behavior for easy code portability. Here's how I wrote the behavior:

namespace Behaviors;


public class ScrollToBottomBehavior
{
    public static readonly BindableProperty DataSourceProperty =
        BindableProperty.CreateAttached(&quot;DataSource&quot;,
                                        typeof(object),
                                        typeof(ScrollToBottomBehavior),
                                        null,
                                        BindingMode.TwoWay,
                                        propertyChanged: OnDataSourceChanged);

    public static int GetDataSource(BindableObject view) =&gt; (int)view.GetValue(DataSourceProperty);

    public static void SetDataSource(BindableObject view, int value) =&gt; view.SetValue(DataSourceProperty, value);

    private static void OnDataSourceChanged(BindableObject sender, object oldValue, object newValue)
    {
        if (sender is not CollectionView view) return;
        //ObservableCollection&lt;object&gt; collection = newValue as ObservableCollection&lt;object&gt;;
        if (newValue is not ObservableCollection&lt;object&gt; collection) return;
        //view?.ScrollTo(collection.LastOrDefault(), null, ScrollToPosition.End);
        view?.ScrollTo(collection.Count - 1, position: ScrollToPosition.End);
    }
}

However, I failed because the Add method of ObservableCollection does not trigger the PropertyChanged event.

I also tried manually setting the SelectedItem to the last item of the ObservableCollection every time an item was added, but this didn't make the CollectionView scroll to the bottom automatically.

I have a couple of ideas:

  1. Modify the ObservableCollection to notify on Add, or
  2. Modify the CollectionView to add a ScrollToBottom property, as shown below, but I still encountered failure.
internal class CollectionViewExtended : CollectionView
{
    public static readonly BindableProperty ScrollToButtomProperty =
        BindableProperty.Create(nameof(ScrollToButtom), typeof(bool), typeof(CollectionViewExtended), false);

    public bool ScrollToButtom
    {
        get =&gt; (bool)GetValue(ScrollToButtomProperty);
        set =&gt; SetValue(ScrollToButtomProperty, value);
    }

    protected override void OnChildAdded(Element child)
    {
        base.OnChildAdded(child);
        if (ScrollToButtom)
        {
            ScrollTo(child, position: ScrollToPosition.End, animate: true);
        }
    }

}

Any sugguestions will be thankful.

答案1

得分: 1

CollectionView 定义了一个名为 ItemsUpdatingScrollMode 的属性,它由一个可绑定的属性支持。此属性获取或设置一个 ItemsUpdatingScrollMode 枚举值,表示在向 CollectionView 添加新项时,CollectionView 的滚动行为。ItemsUpdatingScrollMode 枚举定义了以下成员:

  • KeepItemsInView:在添加新项时,保持列表中的第一项显示。
  • KeepScrollOffset:确保在添加新项时保持当前滚动位置不变。
  • KeepLastItemInView:调整滚动偏移以保持列表中的最后一项在添加新项时显示。

ItemsUpdatingScrollMode 属性的默认值是 KeepItemsInView。因此,当向 CollectionView 添加新项时,列表中的第一项将保持显示。要确保在添加新项时显示列表中的最后一项,请将 ItemsUpdatingScrollMode 属性设置为 KeepLastItemInView

<CollectionView ItemsUpdatingScrollMode="KeepLastItemInView">
    ...
</CollectionView>

有关更多信息,请查阅文档:在添加新项时控制滚动位置

注意:

实际上,滚动完成后可以使用 ScrollTo 方法的 position 参数指定项的确切位置。此参数接受 ScrollToPosition 枚举成员。

有关更多信息,请查阅文档:控制滚动位置

英文:

CollectionView defines a ItemsUpdatingScrollMode property, which is backed by a bindable property. This property gets or sets a ItemsUpdatingScrollMode enumeration value that represents the scrolling behavior of the CollectionView when new items are added to it. The ItemsUpdatingScrollMode enumeration defines the following members:

  • KeepItemsInView keeps the first item in the list displayed when new
    items are added.
  • KeepScrollOffset ensures that the current scroll position is
    maintained when new items are added.
  • KeepLastItemInView adjusts the scroll offset to keep the last item in
    the list displayed when new items are added.

The default value of the ItemsUpdatingScrollMode property is KeepItemsInView. Therefore, when new items are added to a CollectionView the first item in the list will remain displayed. To ensure that the last item in the list is displayed when new items are added, set the ItemsUpdatingScrollMode property to KeepLastItemInView:

&lt;CollectionView ItemsUpdatingScrollMode=&quot;KeepLastItemInView&quot;&gt;
    ...
&lt;/CollectionView&gt;

For more information, check document: Control scroll position when new items are added.

Note:

In fact, the exact position of the item after the scroll has completed can be specified with the position argument of the ScrollTo methods. This argument accepts a ScrollToPosition enumeration member.

For more information, check document: Control scroll position.

答案2

得分: 0

这在Windows平台上不起作用 - 经我测试在Android上可以工作 - 截止到.NET 7目前来看,“可能”会在.NET 8中修复 - 它已经被添加到“待办事项”中,但我没有看到任何确认是否已经进行了检查或有修复的日期。
您可以在这里查找更多信息:

[Windows] CollectionView ItemsUpdatingScrollMode property not working
#4116

英文:

This is not working for Windows platform - works on Android tested by me - currently as of .NET 7 and "probably" will be fixed by .NET 8 - it got added to the "backlog" but I don't see any confirmation about it being checked or a date to have it fixed
You can check for more information here:

[Windows] CollectionView ItemsUpdatingScrollMode property not working
#4116

huangapple
  • 本文由 发表于 2023年6月27日 17:14:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/76563351.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定