Skip to content

Commit

Permalink
Merge pull request #11 from Redth/dev/selecteditems-property
Browse files Browse the repository at this point in the history
Make SelectedItem/SelectedItems as bindable properties
  • Loading branch information
Redth authored Jul 28, 2023
2 parents 7fcf92d + 451e719 commit 48abd49
Show file tree
Hide file tree
Showing 25 changed files with 335 additions and 319 deletions.
37 changes: 37 additions & 0 deletions Sample/VirtualListViewSample/BindableSelectedItemPage.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="VirtualListViewSample.BindableSelectedItemPage"
xmlns:local="clr-namespace:VirtualListViewSample"
xmlns:vlv="clr-namespace:Microsoft.Maui.Controls;assembly=VirtualListView"
x:DataType="local:BindableSelectedItemViewModel"
Title="BindableSelectedItemPage">
<Grid RowDefinitions="*,Auto" ColumnDefinitions="*,Auto" Padding="20">
<vlv:VirtualListView
Grid.Row="0"
Grid.Column="0" Grid.ColumnSpan="2"
x:Name="vlv"
Adapter="{Binding Adapter}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
OnSelectedItemsChanged="vlv_SelectedItemsChanged"
SelectionMode="Single">
<vlv:VirtualListView.ItemTemplate>
<DataTemplate>
<vlv:VirtualViewCell SelectedBackground="DarkBlue" UnselectedBackground="LightBlue">
<Border
Margin="10,0,0,0"
Padding="4"
Background="Transparent"
StrokeShape="{RoundRectangle CornerRadius=10}">
<Label Margin="10,6,10,6" Text="{Binding .}" />
</Border>
</vlv:VirtualViewCell>
</DataTemplate>
</vlv:VirtualListView.ItemTemplate>
</vlv:VirtualListView>

<Entry x:Name="entryItem" Grid.Row="1" Grid.Column="0" Placeholder="Item" />
<Button Grid.Row="1" Grid.Column="1" Text="Select/Deselect" Clicked="Button_Clicked" />
</Grid>
</ContentPage>
75 changes: 75 additions & 0 deletions Sample/VirtualListViewSample/BindableSelectedItemPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.Maui.Adapters;
using System.Collections.ObjectModel;

namespace VirtualListViewSample;

public partial class BindableSelectedItemViewModel : ObservableObject
{
public BindableSelectedItemViewModel(IDispatcher dispatcher)
{
Dispatcher = dispatcher;

for (int i = 0; i < 10; i++)
{
Items.Add($"Item: {i}");
}

Adapter = new ObservableCollectionAdapter<string>(Items);
}

protected IDispatcher Dispatcher { get; }

[ObservableProperty]
ItemPosition? selectedItem;

[ObservableProperty]
ObservableCollectionAdapter<string> adapter;

public ObservableCollection<string> Items = new();

public void OnAppearing()
{
Task.Delay(1000).ContinueWith(t =>
{
Dispatcher.Dispatch(() =>
{
Items.Add("Item 11");
Items.Add("Item 12");
});
});
}
}

public partial class BindableSelectedItemPage : ContentPage
{
public BindableSelectedItemPage()
{
InitializeComponent();

ViewModel = new BindableSelectedItemViewModel(Dispatcher);

BindingContext = ViewModel;
}

public readonly BindableSelectedItemViewModel ViewModel;

private void Button_Clicked(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(entryItem.Text))
{
var index = ViewModel.Items.IndexOf(entryItem.Text);

if (index == ViewModel.SelectedItem?.ItemIndex)
ViewModel.SelectedItem = null;
else if (index >= 0)
ViewModel.SelectedItem = new ItemPosition(0, index);
}
}

private void vlv_SelectedItemsChanged(object sender, SelectedItemsChangedEventArgs e)
{
var selection = string.Join(", ", e.NewSelection.Select(i => i.ItemIndex));
System.Diagnostics.Debug.WriteLine($"SelectedItemsChanged: {selection}");
}
}
2 changes: 2 additions & 0 deletions Sample/VirtualListViewSample/MainPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
<Button Text="Observable Collection Demo" Clicked="Button_Clicked_1" />

<Button Text="Sectioned Adapter Demo" Clicked="Button_Clicked_2" />

<Button Text="Bindable Selected Item Demo" Clicked="Button_Clicked_4" />
</VerticalStackLayout>
</ScrollView>
</ContentPage>
5 changes: 5 additions & 0 deletions Sample/VirtualListViewSample/MainPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,9 @@ private void Button_Clicked_2(object sender, EventArgs e)
{
Navigation.PushAsync(new SectionedAdapterPage());
}

private void Button_Clicked_4(object sender, EventArgs e)
{
Navigation.PushAsync(new BindableSelectedItemPage());
}
}
14 changes: 5 additions & 9 deletions Sample/VirtualListViewSample/MainViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,23 @@
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.ComponentModel;

namespace VirtualListViewSample;

public partial class MainViewModel : INotifyPropertyChanged
public partial class MainViewModel : ObservableObject
{
public MainViewModel()
{
Adapter = new MusicDataAdapter();
}

public MusicDataAdapter Adapter { get; set; }

public void NotifyPropertyChanged(string propertyName)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

public event PropertyChangedEventHandler PropertyChanged;
[ObservableProperty]
MusicDataAdapter adapter;

[RelayCommand]
async Task Refresh()
{
await Task.Delay(3000);
NotifyPropertyChanged(nameof(Adapter));
}

[RelayCommand]
Expand Down
2 changes: 1 addition & 1 deletion Sample/VirtualListViewSample/MusicLibraryPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
RefreshCommand="{Binding RefreshCommand}"
Adapter="{Binding Adapter}"
SelectionMode="Multiple"
SelectedItemsChanged="VirtualListView_SelectedItemsChanged"
OnSelectedItemsChanged="VirtualListView_SelectedItemsChanged"
ItemTemplateSelector="{StaticResource itemTemplateSelector}">

<vlv:VirtualListView.SectionHeaderTemplate>
Expand Down
4 changes: 3 additions & 1 deletion Sample/VirtualListViewSample/MusicLibraryPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ public MusicLibraryPage()
{
Dispatcher.Dispatch(() =>
{
vlv.SelectItems(new ItemPosition(0, 2), new ItemPosition(0, 4));
vlv.SelectItem(new ItemPosition(0, 2));
vlv.SelectItem(new ItemPosition(0, 4));

});
});
}
Expand Down
2 changes: 1 addition & 1 deletion Sample/VirtualListViewSample/ObservableCollectionPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
Grid.Row="0"
Grid.Column="0" Grid.ColumnSpan="2"
x:Name="vlv"
SelectedItemsChanged="vlv_SelectedItemsChanged"
OnSelectedItemsChanged="vlv_SelectedItemsChanged"
SelectionMode="Multiple">
<vlv:VirtualListView.EmptyView>
<Grid>
Expand Down
15 changes: 10 additions & 5 deletions Sample/VirtualListViewSample/ObservableCollectionPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,18 @@ private void Button_Clicked(object sender, EventArgs e)

private void vlv_SelectedItemsChanged(object sender, SelectedItemsChangedEventArgs e)
{
var item = e.NewSelection?.FirstOrDefault();
var selection = string.Join(", ", e.NewSelection.Select(i => i.ItemIndex));
System.Diagnostics.Debug.WriteLine($"SelectedItemsChanged: {selection}");

if (item != null)
if (e.NewSelection.Any())
{
Items.RemoveAt(item.Value.ItemIndex);
}
var toDelete = e.NewSelection.First();

vlv.ClearSelectedItems();

(sender as IVirtualListView).ClearSelection();
var item = Adapter.GetItem(toDelete.SectionIndex, toDelete.ItemIndex);

Items.Remove(item);
}
}
}
2 changes: 1 addition & 1 deletion Sample/VirtualListViewSample/SectionedAdapterPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
Grid.Row="0"
Grid.Column="0" Grid.ColumnSpan="3"
x:Name="vlv"
SelectedItemsChanged="vlv_SelectedItemsChanged"
OnSelectedItemsChanged="vlv_SelectedItemsChanged"
SelectionMode="Single">
<vlv:VirtualListView.EmptyView>
<Label Text="Empty!" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" />
Expand Down
12 changes: 6 additions & 6 deletions Sample/VirtualListViewSample/SectionedAdapterPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ private void Button_Clicked(object sender, EventArgs e)

private void vlv_SelectedItemsChanged(object sender, SelectedItemsChangedEventArgs e)
{
var item = e.NewSelection?.FirstOrDefault();

if (item != null)
if (e.NewSelection.Any())
{
Adapter.RemoveItem(item.Value.SectionIndex, item.Value.ItemIndex);
}
var item = e.NewSelection.First();

(sender as IVirtualListView)?.ClearSelection();
Adapter.RemoveItem(item.SectionIndex, item.ItemIndex);
vlv.ClearSelectedItems();
}

}
}
2 changes: 1 addition & 1 deletion Sample/VirtualListViewSample/VirtualListViewSample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1" />
<PackageReference Include="LiteDb" Version="5.0.16" />
<PackageReference Include="LiteDb" Version="5.0.17" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="chinook.litedb" />
Expand Down
8 changes: 3 additions & 5 deletions VirtualListView/Apple/CvDataSource.ios.maccatalyst.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ public CvDataSource(VirtualListViewHandler handler)

VirtualListViewHandler Handler { get; }

public Func<int, int, bool> IsSelectedHandler { get; set; }

readonly ReusableIdManager itemIdManager = new ReusableIdManager("Item");
readonly ReusableIdManager globalIdManager = new ReusableIdManager("Global");
readonly ReusableIdManager sectionHeaderIdManager = new ReusableIdManager("SectionHeader", new NSString("SectionHeader"));
Expand Down Expand Up @@ -52,7 +50,7 @@ public override UICollectionViewCell GetCell(UICollectionView collectionView, NS
if (info.SectionIndex < 0 || info.ItemIndex < 0)
info.IsSelected = false;
else
info.IsSelected = IsSelectedHandler?.Invoke(info.SectionIndex, info.ItemIndex) ?? false;
info.IsSelected = Handler?.IsItemSelected(info.SectionIndex, info.ItemIndex) ?? false;

if (cell.NeedsView)
{
Expand All @@ -79,9 +77,9 @@ void TapCellHandler(CvCell cell)
cell.PositionInfo.IsSelected = !cell.PositionInfo.IsSelected;

if (cell.PositionInfo.IsSelected)
Handler.VirtualView?.SelectItems(p);
Handler?.VirtualView?.SelectItem(p);
else
Handler.VirtualView?.DeselectItems(p);
Handler?.VirtualView?.DeselectItem(p);
}

public override nint GetItemsCount(UICollectionView collectionView, nint section)
Expand Down
4 changes: 2 additions & 2 deletions VirtualListView/Apple/CvDelegate.ios.maccatalyst.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ void HandleSelection(UICollectionView collectionView, NSIndexPath indexPath, boo
selectedCell.PositionInfo.ItemIndex);

if (selected)
Handler?.VirtualView?.SelectItems(itemPos);
Handler?.VirtualView?.SelectItem(itemPos);
else
Handler?.VirtualView?.DeselectItems(itemPos);
Handler?.VirtualView?.DeselectItem(itemPos);
}
}

Expand Down
49 changes: 15 additions & 34 deletions VirtualListView/Apple/VirtualListViewHandler.ios.maccatalyst.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,10 @@ protected override void ConnectHandler(UICollectionView nativeView)
PositionalViewSelector = new PositionalViewSelector(VirtualView);

dataSource = new CvDataSource(this);
dataSource.IsSelectedHandler = (realSection, realIndex) =>
VirtualView?.IsItemSelected(realSection, realIndex) ?? false;


cvdelegate = new CvDelegate(this, collectionView);
cvdelegate.ScrollHandler = (x, y) =>
VirtualView?.Scrolled(new ScrolledEventArgs(x, y));
VirtualView?.Scrolled(x, y);

collectionView.DataSource = dataSource;
collectionView.Delegate = cvdelegate;
Expand Down Expand Up @@ -117,44 +115,27 @@ public static void MapSelectionMode(VirtualListViewHandler handler, IVirtualList
public static void MapInvalidateData(VirtualListViewHandler handler, IVirtualListView virtualListView, object? parameter)
=> handler?.InvalidateData();

public static void MapSelectItems(VirtualListViewHandler handler, IVirtualListView virtualListView, object parameter)
void PlatformUpdateItemSelection(ItemPosition itemPosition, bool selected)
{
if (parameter is ItemPosition[] items)
{
UpdateSelection(handler, items, true);
}
}
var realIndex = PositionalViewSelector?.GetPosition(itemPosition.SectionIndex, itemPosition.ItemIndex) ?? -1;

public static void MapDeselectItems(VirtualListViewHandler handler, IVirtualListView virtualListView, object parameter)
{
if (parameter is ItemPosition[] items)
{
UpdateSelection(handler, items, false);
}
}
if (realIndex < 0)
return;

static void UpdateSelection(VirtualListViewHandler handler, ItemPosition[] itemPositions, bool selected)
{
foreach (var itemPosition in itemPositions)
{
var realIndex = handler.PositionalViewSelector.GetPosition(itemPosition.SectionIndex, itemPosition.ItemIndex);
var cell = collectionView.CellForItem(NSIndexPath.FromItemSection(realIndex, 0));

var cell = handler.collectionView.CellForItem(NSIndexPath.FromItemSection(realIndex, 0));
if (cell is CvCell cvcell)
{
cvcell.PositionInfo.IsSelected = selected;

if (cell is CvCell cvcell)
if (cvcell.VirtualView is IPositionInfo positionInfo)
{
cvcell.PositionInfo.IsSelected = selected;

if (cvcell.VirtualView is IPositionInfo positionInfo)
{
handler.collectionView.InvokeOnMainThread(() =>
{
positionInfo.IsSelected = selected;
});
}
collectionView.InvokeOnMainThread(() =>
{
positionInfo.IsSelected = selected;
});
}
}

}

public static void MapOrientation(VirtualListViewHandler handler, IVirtualListView virtualListView)
Expand Down
Loading

0 comments on commit 48abd49

Please sign in to comment.