diff --git a/components/Behaviors/OpenSolution.bat b/components/Behaviors/OpenSolution.bat
new file mode 100644
index 000000000..814a56d4b
--- /dev/null
+++ b/components/Behaviors/OpenSolution.bat
@@ -0,0 +1,3 @@
+@ECHO OFF
+
+powershell ..\..\tooling\ProjectHeads\GenerateSingleSampleHeads.ps1 -componentPath %CD% %*
\ No newline at end of file
diff --git a/components/Behaviors/samples/Assets/icon.png b/components/Behaviors/samples/Assets/icon.png
new file mode 100644
index 000000000..8435bcaa9
Binary files /dev/null and b/components/Behaviors/samples/Assets/icon.png differ
diff --git a/components/Behaviors/samples/Behaviors.Samples.csproj b/components/Behaviors/samples/Behaviors.Samples.csproj
new file mode 100644
index 000000000..82315d71c
--- /dev/null
+++ b/components/Behaviors/samples/Behaviors.Samples.csproj
@@ -0,0 +1,23 @@
+
+
+
+
+ Behaviors
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/Behaviors/samples/Dependencies.props b/components/Behaviors/samples/Dependencies.props
new file mode 100644
index 000000000..d7912ab7d
--- /dev/null
+++ b/components/Behaviors/samples/Dependencies.props
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/Behaviors/samples/ItemsView Behaviors.md b/components/Behaviors/samples/ItemsView Behaviors.md
new file mode 100644
index 000000000..0ccc7054b
--- /dev/null
+++ b/components/Behaviors/samples/ItemsView Behaviors.md
@@ -0,0 +1,31 @@
+---
+title: ItemsView Behaviors
+author: githubaccount
+description: A set of behaviors for the ItemsView control.
+keywords: Behaviors, Control, Behavior
+dev_langs:
+ - csharp
+category: Xaml
+subcategory: Behaviors
+discussion-id: 532
+issue-id: 0
+icon: assets/icon.png
+---
+The new control `ItemsView` which can replace `ListView`&`GridView`, does not support `ISupportIncrementalLoading`.
+
+Here are some Behaviors to help you make `ItemsView` support `ISupportIncrementalLoading`.
+
+## NeedMoreItemTriggerBehaviorSample
+
+This trigger behavior can excute actions when the `ItemsView` scrolling to bottom.
+You can customize the loading behavior through actions, but note that you may need to debounce manually.
+
+> [!SAMPLE NeedMoreItemTriggerBehaviorSample]
+
+## LoadMoreItemBehaviorSample
+
+If you don't have complex loading requirements, you can use this behavior.
+It automatically calls `ISupportIncrementalLoading.LoadMoreItemsAsync` when the `ItemsSource` changes, in addition to when `ItemsView` scrolls to the bottom.
+Besides, this behavior has a built-in debounce function.
+
+> [!SAMPLE LoadMoreItemBehaviorSample]
diff --git a/components/Behaviors/samples/LoadMoreItemBehaviorSample.xaml b/components/Behaviors/samples/LoadMoreItemBehaviorSample.xaml
new file mode 100644
index 000000000..c10cccc11
--- /dev/null
+++ b/components/Behaviors/samples/LoadMoreItemBehaviorSample.xaml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/Behaviors/samples/LoadMoreItemBehaviorSample.xaml.cs b/components/Behaviors/samples/LoadMoreItemBehaviorSample.xaml.cs
new file mode 100644
index 000000000..e322b0373
--- /dev/null
+++ b/components/Behaviors/samples/LoadMoreItemBehaviorSample.xaml.cs
@@ -0,0 +1,84 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#if WINAPPSDK
+
+using CommunityToolkit.WinUI.Controls;
+using Microsoft.UI;
+
+namespace BehaviorsExperiment.Samples;
+
+[ToolkitSampleBoolOption(nameof(LoadMoreItemBehavior.IsActive), true, Title = nameof(LoadMoreItemBehavior.IsActive))]
+[ToolkitSampleNumericOption(nameof(LoadMoreItemBehavior.LoadingOffset), 100d, 50d, 500d, 50d, Title = nameof(LoadMoreItemBehavior.LoadingOffset))]
+[ToolkitSampleNumericOption(nameof(LoadMoreItemBehavior.LoadCount), 20, 1, 50, 1, Title = nameof(LoadMoreItemBehavior.LoadCount))]
+
+[ToolkitSample(id: nameof(LoadMoreItemBehaviorSample), "LoadMoreItemBehavior", description: $"A sample for showing how to create and use a LoadMoreItemBehavior.")]
+public sealed partial class LoadMoreItemBehaviorSample : Page
+{
+ private static readonly Random _random = new Random();
+
+ public LoadMoreItemBehaviorSample()
+ {
+ this.InitializeComponent();
+ }
+
+ public static SolidColorBrush GetColor()
+ {
+ var rand = _random.Next(4);
+ var color = rand switch
+ {
+ 0 => Colors.Red,
+ 1 => Colors.Blue,
+ 2 => Colors.Green,
+ 3 => Colors.Yellow,
+ _ => Colors.Black
+ };
+ return new(color);
+ }
+
+ public MyCollection ViewModels { get; } = [.. Enumerable.Repeat(0, 50).Select(_ => _random.Next(5, 10) * 500)];
+}
+
+public partial class MyCollection : ObservableCollection, ISupportIncrementalLoading
+{
+ private static readonly Random _random = new Random();
+
+ public int Num
+ {
+ get => _num;
+ set
+ {
+ if (_num == value)
+ {
+ return;
+ }
+
+ _num = value;
+ OnPropertyChanged(new PropertyChangedEventArgs(nameof(Num)));
+ }
+ }
+
+ private int _num;
+
+ public bool HasMoreItems => true;
+
+ public IAsyncOperation LoadMoreItemsAsync(uint count)
+ {
+ return LoadMoreItemsTaskAsync(count).AsAsyncOperation();
+ }
+
+ public async Task LoadMoreItemsTaskAsync(uint count)
+ {
+ await Task.Delay(1000);
+ foreach (var i in Enumerable.Repeat(0, (int)count).Select(_ => _random.Next(5, 10) * 500))
+ {
+ Add(i);
+ }
+
+ Num++;
+ return new LoadMoreItemsResult { Count = count };
+ }
+}
+
+#endif
diff --git a/components/Behaviors/samples/NeedMoreItemTriggerBehaviorSample.xaml b/components/Behaviors/samples/NeedMoreItemTriggerBehaviorSample.xaml
new file mode 100644
index 000000000..b3c5c402b
--- /dev/null
+++ b/components/Behaviors/samples/NeedMoreItemTriggerBehaviorSample.xaml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/Behaviors/samples/NeedMoreItemTriggerBehaviorSample.xaml.cs b/components/Behaviors/samples/NeedMoreItemTriggerBehaviorSample.xaml.cs
new file mode 100644
index 000000000..090597d43
--- /dev/null
+++ b/components/Behaviors/samples/NeedMoreItemTriggerBehaviorSample.xaml.cs
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#if WINAPPSDK
+
+using CommunityToolkit.WinUI.Controls;
+using Microsoft.UI;
+
+namespace BehaviorsExperiment.Samples;
+
+[ToolkitSampleBoolOption(nameof(NeedMoreItemTriggerBehavior.IsActive), true, Title = nameof(NeedMoreItemTriggerBehavior.IsActive))]
+[ToolkitSampleNumericOption(nameof(NeedMoreItemTriggerBehavior.LoadingOffset), 100d, 50d, 500d, 50d, Title = nameof(NeedMoreItemTriggerBehavior.LoadingOffset))]
+
+[ToolkitSample(id: nameof(NeedMoreItemTriggerBehaviorSample), "NeedMoreItemTriggerBehavior", description: $"A sample for showing how to create and use a NeedMoreItemTriggerBehavior.")]
+public sealed partial class NeedMoreItemTriggerBehaviorSample : Page
+{
+ private static readonly Random _random = new();
+
+ public NeedMoreItemTriggerBehaviorSample()
+ {
+ this.InitializeComponent();
+ }
+
+ public static SolidColorBrush GetColor()
+ {
+ var rand = _random.Next(4);
+ var color = rand switch
+ {
+ 0 => Colors.Red,
+ 1 => Colors.Blue,
+ 2 => Colors.Green,
+ 3 => Colors.Yellow,
+ _ => Colors.Black
+ };
+ return new(color);
+ }
+
+ public IEnumerable ViewModels { get; } = Enumerable.Repeat(0, 50).Select(_ => _random.Next(5, 10) * 500);
+
+ private int _num;
+
+ public void IncrementCount()
+ {
+ _num++;
+ MyRun.Text = _num.ToString();
+ }
+}
+
+#endif
diff --git a/components/Behaviors/src/CommunityToolkit.WinUI.Controls.Behaviors.csproj b/components/Behaviors/src/CommunityToolkit.WinUI.Controls.Behaviors.csproj
new file mode 100644
index 000000000..43551ee24
--- /dev/null
+++ b/components/Behaviors/src/CommunityToolkit.WinUI.Controls.Behaviors.csproj
@@ -0,0 +1,13 @@
+
+
+
+
+ Behaviors
+ This package contains Behaviors.
+
+ CommunityToolkit.WinUI.Controls.BehaviorsRns
+
+
+
+
+
diff --git a/components/Behaviors/src/Dependencies.props b/components/Behaviors/src/Dependencies.props
new file mode 100644
index 000000000..d7912ab7d
--- /dev/null
+++ b/components/Behaviors/src/Dependencies.props
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/Behaviors/src/LoadMoreItemBehavior.cs b/components/Behaviors/src/LoadMoreItemBehavior.cs
new file mode 100644
index 000000000..7d3ee7c89
--- /dev/null
+++ b/components/Behaviors/src/LoadMoreItemBehavior.cs
@@ -0,0 +1,244 @@
+#region Copyright
+
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#endregion
+
+#if WINAPPSDK
+
+using System.Collections;
+using System.Collections.Specialized;
+using Microsoft.Xaml.Interactivity;
+
+namespace CommunityToolkit.WinUI.Controls;
+
+///
+/// A behavior that makes support .
+///
+public class LoadMoreItemBehavior : Behavior
+{
+ ///
+ /// Identifies the property.
+ ///
+ public static readonly DependencyProperty LoadingOffsetProperty = DependencyProperty.Register(
+ nameof(LoadingOffset),
+ typeof(double),
+ typeof(LoadMoreItemBehavior),
+ new PropertyMetadata(100d));
+
+ ///
+ /// Gets or sets Distance of content from scrolling to bottom.
+ ///
+ public double LoadingOffset
+ {
+ get => (double)this.GetValue(LoadingOffsetProperty);
+ set => this.SetValue(LoadingOffsetProperty, value);
+ }
+
+ ///
+ /// Identifies the property.
+ ///
+ public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register(
+ nameof(IsActive),
+ typeof(bool),
+ typeof(LoadMoreItemBehavior),
+ new PropertyMetadata(true));
+
+ ///
+ /// Gets a value indicating whether the behavior is active.
+ ///
+ public bool IsActive
+ {
+ get => (bool)this.GetValue(IsActiveProperty);
+ set => this.SetValue(IsActiveProperty, value);
+ }
+
+ ///
+ /// Identifies the property.
+ ///
+ public static readonly DependencyProperty IsLoadingMoreProperty = DependencyProperty.Register(
+ nameof(IsLoadingMore),
+ typeof(bool),
+ typeof(LoadMoreItemBehavior),
+ new PropertyMetadata(false));
+
+ ///
+ /// Gets or sets if more items are being loaded.
+ ///
+ public bool IsLoadingMore
+ {
+ get => (bool)this.GetValue(IsLoadingMoreProperty);
+ set => this.SetValue(IsLoadingMoreProperty, value);
+ }
+
+ ///
+ /// Identifies the property.
+ ///
+ public static readonly DependencyProperty LoadCountProperty = DependencyProperty.Register(
+ nameof(LoadCount),
+ typeof(int),
+ typeof(LoadMoreItemBehavior),
+ new PropertyMetadata(20));
+
+ ///
+ /// Gets or sets the "count" parameter when triggering .
+ ///
+ public int LoadCount
+ {
+ get => (int)this.GetValue(LoadCountProperty);
+ set => this.SetValue(LoadCountProperty, value);
+ }
+
+ ///
+ /// Raised when more items need to be loaded.
+ ///
+ public event Func>? LoadMoreRequested;
+
+ private ItemsRepeater? ItemsRepeater => (ItemsRepeater?)this.ScrollView?.Content;
+
+ private ScrollView? ScrollView => this.AssociatedObject?.ScrollView;
+
+ private long _scrollViewOnPropertyChangedToken;
+ private long _itemsSourceOnPropertyChangedToken;
+
+ private INotifyCollectionChanged? _lastObservableCollection;
+
+ ///
+ protected override void OnAttached()
+ {
+ this.LoadMoreRequested += async (sender, args) =>
+ {
+ if (sender.ItemsSource is ISupportIncrementalLoading sil)
+ {
+ _ = await sil.LoadMoreItemsAsync((uint)this.LoadCount);
+ return sil.HasMoreItems;
+ }
+
+ return false;
+ };
+ this._scrollViewOnPropertyChangedToken = this.AssociatedObject.RegisterPropertyChangedCallback(ItemsView.ScrollViewProperty, this.ScrollViewOnPropertyChanged);
+ this._itemsSourceOnPropertyChangedToken = this.RegisterPropertyChangedCallback(ItemsView.ItemsSourceProperty, this.ItemsSourceOnPropertyChanged);
+ }
+
+ ///
+ protected override void OnDetaching()
+ {
+ this.AssociatedObject.UnregisterPropertyChangedCallback(ItemsView.ScrollViewProperty, this._scrollViewOnPropertyChangedToken);
+ this.AssociatedObject.UnregisterPropertyChangedCallback(ItemsView.ItemsSourceProperty, this._itemsSourceOnPropertyChangedToken);
+ if (this._lastObservableCollection is not null)
+ this._lastObservableCollection.CollectionChanged -= this.TryRaiseLoadMoreRequested;
+ if (this.ItemsRepeater is not null)
+ this.ItemsRepeater.SizeChanged -= this.TryRaiseLoadMoreRequested;
+ if (this.ScrollView is not null)
+ this.ScrollView.ViewChanged -= this.TryRaiseLoadMoreRequested;
+ }
+
+ ///
+ /// When the data source changes or , .
+ /// This method reloads the data.
+ /// This method is intended to solve the problem of reloading data when the data source changes and the 's does not change
+ ///
+ private async void ItemsSourceOnPropertyChanged(DependencyObject sender, DependencyProperty dp)
+ {
+ if (sender is ItemsView { ItemsSource: ISupportIncrementalLoading sil })
+ {
+ if (sil is INotifyCollectionChanged ncc)
+ {
+ if (this._lastObservableCollection is not null)
+ this._lastObservableCollection.CollectionChanged -= this.TryRaiseLoadMoreRequested;
+
+ this._lastObservableCollection = ncc;
+ ncc.CollectionChanged += this.TryRaiseLoadMoreRequested;
+ }
+
+ // On the first load, the `ScrollView` is not yet initialized and can be given to `AdvancedItemsView_OnSizeChanged` to trigger.
+ if (this.ScrollView is not null)
+ await this.TryRaiseLoadMoreRequestedAsync();
+ }
+ }
+
+ private async void TryRaiseLoadMoreRequested(object? sender, object e) => await this.TryRaiseLoadMoreRequestedAsync();
+
+ ///
+ /// After this method, the will be triggered
+ ///
+ ///
+ /// is the key to continuous loading.
+ /// When new data is loaded, it makes the of the larger,
+ /// Or when the is changed to a different source or set for the first time, becomes 0.
+ /// This method can reload the data.
+ ///
+ private void ScrollViewOnPropertyChanged(DependencyObject sender, DependencyProperty dp)
+ {
+ this.AssociatedObject.UnregisterPropertyChangedCallback(ItemsView.ScrollViewProperty, this._scrollViewOnPropertyChangedToken);
+ if (this.ScrollView is null)
+ return;
+ this.ScrollView.ViewChanged += this.TryRaiseLoadMoreRequested;
+ if (this.ItemsRepeater is not null)
+ this.ItemsRepeater.SizeChanged += this.TryRaiseLoadMoreRequested;
+ }
+
+ ///
+ /// Determines if the scroll view has scrolled to the bottom, and if so triggers the .
+ /// This event will only cause the source to load at most once
+ ///
+ public async Task TryRaiseLoadMoreRequestedAsync()
+ {
+ if (this.AssociatedObject is null || this.ScrollView is null)
+ return;
+
+ var loadMore = true;
+ // Load until a new item is loaded in
+ while (loadMore)
+ {
+ if (this.AssociatedObject is null || !this.IsActive || this.IsLoadingMore)
+ return;
+
+ // LoadMoreRequested is only triggered when the view is not filled.
+ if ((this.ScrollView.ScrollableHeight is 0 && this.ScrollView.ScrollableWidth is 0) ||
+ (this.ScrollView.ScrollableHeight > 0 &&
+ this.ScrollView.ScrollableHeight - this.LoadingOffset < this.ScrollView.VerticalOffset) ||
+ (this.ScrollView.ScrollableWidth > 0 &&
+ this.ScrollView.ScrollableWidth - this.LoadingOffset < this.ScrollView.HorizontalOffset))
+ {
+ this.IsLoadingMore = true;
+ var before = this.GetItemsCount();
+ if (this.LoadMoreRequested is not null && await this.LoadMoreRequested(this.AssociatedObject, EventArgs.Empty))
+ {
+ var after = this.GetItemsCount();
+ // This can be set to the count of items in a row,
+ // so that it can continue to load even if the count of items loaded is too small.
+ // Generally, 20 items will be loaded at a time,
+ // and the count of items in a row is usually less than 10, so it is set to 10 here.
+ if (before + 10 <= after)
+ loadMore = false;
+ }
+ // No more items or ItemsSource is null
+ else
+ loadMore = false;
+
+ this.IsLoadingMore = false;
+ }
+ else
+ {
+ // There is no need to continue loading if it fills up the view
+ loadMore = false;
+ }
+ }
+ }
+
+ private int GetItemsCount()
+ {
+ return this.AssociatedObject?.ItemsSource switch
+ {
+ ICollection list => list.Count,
+ IEnumerable enumerable => enumerable.Cast