I am trying to implement a ContentView which represents a list of items, and allows for manipulating these items (delete, edit...) by clicking on a button. Now I'm trying to have it look nice and fancy so I'm using a SwipeView for the item manipulation button to show only when the "show more" of the item is clicked.
I am close to achieving what I want, but the last thing I could not quite figure out is how to bind each of the items of my list to each SwipeView control instance. Here is a trimmed version of my ContentView XAML:
<?xml version="1.0" encoding="utf-8" ?>
<CollectionView>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="local:TimerPresetListItem">
<Grid>
<SwipeView BindingContext="{Binding SwipeView}"/>
<Button Text="Show more..." Command="{Binding ShowMoreCommand}"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
And here is the code-behind:
public partial class TimerPresetList : ContentView
{
public static readonly BindableProperty TimerPresetListItemsProperty = BindableProperty.Create(nameof(TimerPresetListItems), typeof(ObservableCollection<TimerPresetListItem>), typeof(TimerPresetList));
public static readonly BindableProperty TimerPresetsProperty = BindableProperty.Create(nameof(TimerPresets), typeof(ObservableCollection<TimerPresetViewModel>), typeof(TimerPresetList));
public ObservableCollection<TimerPresetListItem> TimerPresetListItems
{
get => (ObservableCollection<TimerPresetListItem>)GetValue(TimerPresetListItemsProperty);
set => SetValue(TimerPresetListItemsProperty, value);
}
public ObservableCollection<TimerPresetViewModel> TimerPresets
{
get => (ObservableCollection<TimerPresetViewModel>)GetValue(TimerPresetsProperty);
set => SetValue(TimerPresetsProperty, value);
}
public TimerPresetList()
{
InitializeComponent();
}
protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if (propertyName == nameof(TimerPresets))
{
TimerPresetListItems = new ObservableCollection<TimerPresetListItem>();
TimerPresets.CollectionChanged += TimerPresetsCollectionChanged;
}
}
private void TimerPresetsCollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
foreach (var item in e.NewItems)
{
TimerPresetListItems.Add(new TimerPresetListItem((TimerPresetViewModel)item));
}
break;
}
}
}
public partial class TimerPresetListItem : ObservableObject
{
[ObservableProperty]
private TimerPresetViewModel _timerPresetViewModel;
[ObservableProperty]
private SwipeView _swipeView;
public TimerPresetListItem(TimerPresetViewModel timerPresetViewModel)
{
TimerPresetViewModel = timerPresetViewModel;
}
[RelayCommand]
public void ShowMore()
{
if (SwipeView != null)
{
SwipeView!.Open(OpenSwipeItem.RightItems);
}
}
}
public partial class TimerPresetList : ContentView
{
public static readonly BindableProperty TimerPresetListItemsProperty = BindableProperty.Create(nameof(TimerPresetListItems), typeof(ObservableCollection<TimerPresetListItem>), typeof(TimerPresetList));
public static readonly BindableProperty TimerPresetsProperty = BindableProperty.Create(nameof(TimerPresets), typeof(ObservableCollection<TimerPresetViewModel>), typeof(TimerPresetList));
public ObservableCollection<TimerPresetListItem> TimerPresetListItems
{
get => (ObservableCollection<TimerPresetListItem>)GetValue(TimerPresetListItemsProperty);
set => SetValue(TimerPresetListItemsProperty, value);
}
public ObservableCollection<TimerPresetViewModel> TimerPresets
{
get => (ObservableCollection<TimerPresetViewModel>)GetValue(TimerPresetsProperty);
set => SetValue(TimerPresetsProperty, value);
}
public TimerPresetList()
{
InitializeComponent();
}
protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if (propertyName == nameof(TimerPresets))
{
TimerPresetListItems = new ObservableCollection<TimerPresetListItem>();
TimerPresets.CollectionChanged += TimerPresetsCollectionChanged;
}
}
private void TimerPresetsCollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
foreach (var item in e.NewItems)
{
TimerPresetListItems.Add(new TimerPresetListItem((TimerPresetViewModel)item));
}
break;
}
}
}
public partial class TimerPresetListItem : ObservableObject
{
[ObservableProperty]
private TimerPresetViewModel _timerPresetViewModel;
[ObservableProperty]
private SwipeView _swipeView;
public TimerPresetListItem(TimerPresetViewModel timerPresetViewModel)
{
TimerPresetViewModel = timerPresetViewModel;
}
[RelayCommand]
public void ShowMore()
{
if (SwipeView != null)
{
SwipeView!.Open(OpenSwipeItem.RightItems);
}
}
}
As you can see I simply have a TimerPresetListItem which wraps a TimerPresetViewModel object and (is supposed to) bind to a SwipeView instance.
Now everything works fine except the binding to the SwipeView:
<SwipeView BindingContext="{Binding SwipeView}"/>
Indeed when the ShowMore method gets call, SwipeView is still always null. Any idea what went wrong here ? Thanks a lot for any feedback it's much appreciated.
First, you need to create a custom SwipeView which inherits SwipeView and you can define a BindableProperty
OpenFlagwhich controls the state of swipeView.Then, you can put the custom Swipeview in the xaml.
In the viewmodel you can create a data collection to control the OpenFlag.
Here is the code in the item class:
Last, you can use the code below to control the Swipeview.