Skip to content

Commit c7ef455

Browse files
committed
added bindable layout, increased version to 2.2.0
1 parent 6186e92 commit c7ef455

File tree

3 files changed

+170
-1
lines changed

3 files changed

+170
-1
lines changed
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
using System.Collections;
2+
using System.Collections.Specialized;
3+
4+
namespace MPowerKit.VirtualizeListView;
5+
6+
public class BindableLayout
7+
{
8+
private static readonly Dictionary<IEnumerable, List<WeakReference<BindableObject>>> _bindableObjects = [];
9+
10+
#region ItemTemplate
11+
public static readonly BindableProperty ItemTemplateProperty =
12+
BindableProperty.CreateAttached(
13+
"ItemTemplate",
14+
typeof(DataTemplate),
15+
typeof(BindableLayout),
16+
null);
17+
18+
public static DataTemplate GetItemTemplate(BindableObject view) => (DataTemplate)view.GetValue(ItemTemplateProperty);
19+
20+
public static void SetItemTemplate(BindableObject view, DataTemplate value) => view.SetValue(ItemTemplateProperty, value);
21+
#endregion
22+
23+
#region ItemsSource
24+
public static readonly BindableProperty ItemsSourceProperty =
25+
BindableProperty.CreateAttached(
26+
"ItemsSource",
27+
typeof(IEnumerable),
28+
typeof(BindableLayout),
29+
null,
30+
propertyChanged: OnItemsSourcePropertyChanged,
31+
propertyChanging: OnItemsSourcePropertyChanging);
32+
33+
public static IEnumerable GetItemsSource(BindableObject view) => (IEnumerable)view.GetValue(ItemsSourceProperty);
34+
35+
public static void SetItemsSource(BindableObject view, IEnumerable value) => view.SetValue(ItemsSourceProperty, value);
36+
37+
private static void OnItemsSourcePropertyChanging(BindableObject bindable, object oldValue, object newValue)
38+
{
39+
if (oldValue is INotifyCollectionChanged collectionChanged)
40+
{
41+
collectionChanged.CollectionChanged -= CollectionChanged_CollectionChanged;
42+
}
43+
44+
if (bindable is Layout layout)
45+
{
46+
ClearItems(layout);
47+
}
48+
49+
if (oldValue is IEnumerable enumerable)
50+
{
51+
RemoveBindableObject(enumerable, bindable);
52+
}
53+
}
54+
55+
private static void RemoveBindableObject(IEnumerable itemsSource, BindableObject bindable)
56+
{
57+
if (_bindableObjects.TryGetValue(itemsSource, out var bindableList))
58+
{
59+
bindableList.RemoveAll(weakRef => !weakRef.TryGetTarget(out var target) || target == bindable);
60+
61+
if (bindableList.Count == 0) _bindableObjects.Remove(itemsSource);
62+
}
63+
}
64+
65+
private static void OnItemsSourcePropertyChanged(BindableObject bindable, object oldValue, object newValue)
66+
{
67+
if (newValue is INotifyCollectionChanged collectionChanged)
68+
{
69+
collectionChanged.CollectionChanged += CollectionChanged_CollectionChanged;
70+
}
71+
72+
if (newValue is IEnumerable enumerable && bindable is Layout layout)
73+
{
74+
AddBindableObject(enumerable, layout);
75+
76+
AddItems(layout, enumerable, 0);
77+
}
78+
}
79+
80+
private static void AddBindableObject(IEnumerable itemsSource, BindableObject bindable)
81+
{
82+
if (!_bindableObjects.TryGetValue(itemsSource, out var value))
83+
{
84+
_bindableObjects[itemsSource] = value = [];
85+
}
86+
87+
value.Add(new(bindable));
88+
}
89+
90+
private static void CollectionChanged_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
91+
{
92+
if (sender is not IEnumerable enumerable || !_bindableObjects.TryGetValue(enumerable, out var wrList) || wrList?.Count is null or 0) return;
93+
94+
var layoutList = wrList.Select(wr => wr.TryGetTarget(out var target) ? target : null).OfType<Layout>();
95+
foreach (var layout in layoutList)
96+
{
97+
switch (e.Action)
98+
{
99+
case NotifyCollectionChangedAction.Add:
100+
AddItems(layout, e.NewItems, e.NewStartingIndex);
101+
break;
102+
case NotifyCollectionChangedAction.Remove:
103+
RemoveItems(layout, e.OldItems, e.OldStartingIndex);
104+
break;
105+
case NotifyCollectionChangedAction.Replace:
106+
AddItems(layout, e.NewItems, e.NewStartingIndex);
107+
RemoveItems(layout, e.OldItems, e.OldStartingIndex);
108+
break;
109+
case NotifyCollectionChangedAction.Move:
110+
MoveItems(layout, e.OldItems, e.OldStartingIndex, e.NewStartingIndex);
111+
break;
112+
case NotifyCollectionChangedAction.Reset:
113+
ClearItems(layout);
114+
break;
115+
}
116+
}
117+
}
118+
119+
private static void ClearItems(Layout layout)
120+
{
121+
layout.Clear();
122+
}
123+
124+
private static void AddItems(Layout layout, IEnumerable? items, int index)
125+
{
126+
if (items is null) return;
127+
128+
var template = GetItemTemplate(layout);
129+
130+
if (template is null) return;
131+
132+
foreach (var item in items)
133+
{
134+
while (template is DataTemplateSelector selector)
135+
{
136+
template = selector.SelectTemplate(item, layout);
137+
}
138+
139+
if (template.CreateContent() is not View view) continue;
140+
view.BindingContext = item;
141+
layout.Insert(index++, view);
142+
}
143+
}
144+
145+
private static void RemoveItems(Layout layout, IEnumerable? items, int index)
146+
{
147+
if (items is null) return;
148+
149+
foreach (var item in items)
150+
{
151+
layout.RemoveAt(index);
152+
}
153+
}
154+
155+
private static void MoveItems(Layout layout, IEnumerable? items, int oldIndex, int newIndex)
156+
{
157+
if (items is null) return;
158+
159+
foreach (var item in items)
160+
{
161+
layout.Move(oldIndex, newIndex);
162+
}
163+
}
164+
#endregion
165+
}

MPowerKit.VirtualizeListView/MPowerKit.VirtualizeListView.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
2222
<Title>MPowerKit.VirtualizeListView</Title>
23-
<Version>2.1.1</Version>
23+
<Version>2.2.0</Version>
2424
<Authors>MPowerKit,Alex Dobrynin</Authors>
2525
<Description>MAUI Virtualize ListView with smooth scrolling and without platform-specific code</Description>
2626
<Copyright>MPowerKit</Copyright>

readme.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ To disable scroll set ```CanScroll``` property to ```false```, and do not change
136136

137137
This package brings to you fixed MAUI's RefreshView as ```FixedRefreshView```. Here, you can disable refreshing without disabling entire collection. For this you may use ```IsPullToRefreshEnabled```.
138138

139+
#### ```BindableLayout```
140+
141+
Since MAUI's ```BindableLayout``` looks like over engineering, this package brings to you another one ```BindableLayout```. It is more lightweight than original one. Can be used with all ```typeof(Layout)```
142+
139143
#### ```ObservableRangeCollection```
140144

141145
Also, this package contains ```ObservableRangeCollection``` which is an ```ObservableCollection```, but it has a bunch of useful methods to manipulate the collection with batch updates. Recommended to use with ```VirtualizeListView```. It provides few methods: ```AddRange```, ```InsertRange```, ```RemoveRange```, ```ReplaceRange```.

0 commit comments

Comments
 (0)