我正在尝试实现一个 ContentView,它代表一个项目列表,并允许通过单击按钮来操作这些项目(删除、编辑...)。现在我试图让它看起来漂亮又漂亮,所以我使用 SwipeView 作为项目操作按钮,仅在单击项目的“显示更多”时才显示。
我即将实现我想要的目标,但我无法弄清楚的最后一件事是如何将列表中的每个项目绑定到每个 SwipeView 控件实例。这是我的 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>
这是隐藏代码:
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);
}
}
}
如您所见,我只是有一个 TimerPresetListItem,它包装了 TimerPresetViewModel 对象并(应该)绑定到 SwipeView 实例。
现在除了绑定到 SwipeView 之外一切都工作正常:
<SwipeView BindingContext="{Binding SwipeView}"/>
事实上,当 ShowMore 方法被调用时,SwipeView 仍然始终为 null。知道这里出了什么问题吗?非常感谢您的任何反馈,非常感谢。
首先,你需要创建一个自定义的SwipeView,它继承SwipeView,你可以定义一个BindableProperty
OpenFlag
来控制swipeView的状态。
public class CustomSwipeView : SwipeView
{
public static readonly BindableProperty OpenFlagProperty =
BindableProperty.Create("OpenFlag", typeof(bool), typeof(CustomSwipeView), null, propertyChanged:OnPropertyChanged);
private static void OnPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
var flag = (bool)newValue;
SwipeView m = bindable as SwipeView;
if(m != null)
{
if (flag)
{
m.Open(OpenSwipeItem.RightItems);
}
else
{
m.Close();
}
}
}
public bool OpenFlag
{
get { return (bool)GetValue(OpenFlagProperty); }
set { SetValue(OpenFlagProperty, value); }
}
}
然后,您可以将自定义的Swipeview放入xaml中。
<local:CustomSwipeView x:Name="myview" OpenFlag="{Binding OpenFlag}" >
<SwipeView.RightItems>
...
</SwipeView.RightItems>
在视图模型中,您可以创建数据集合来控制 OpenFlag。
public ObservableCollection<Item> ItemCollection { get; set; } = new ObservableCollection<Item>();
这是项目类中的代码:
public class Item : INotifyPropertyChanged
{
private bool openFlag;
public bool OpenFlag
{
get
{
return openFlag;
}
set
{
openFlag = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(OpenFlag)));
}
}
public string MyTitle { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
最后,您可以使用下面的代码来控制Swipeview。
viewModel.ItemCollection[0].OpenFlag = true;