前面的答案要么建议自定义渲染器,要么要求您在数据对象或其他方式中跟踪所选项目。这并不是真正需要的,有一种方法可以以与平台无关的方式链接到ListView 的功能。然后可以使用它以任何需要的方式更改所选项目。可以修改颜色,根据所选状态显示或隐藏单元格的不同部分。
让我们将IsSelected 属性添加到我们的ViewCell。无需将其添加到数据对象中;列表视图选择单元格,而不是绑定数据。
public partial class SelectableCell : ViewCell {
public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create(nameof(IsSelected), typeof(bool), typeof(SelectableCell), false, propertyChanged: OnIsSelectedPropertyChanged);
public bool IsSelected {
get => (bool)GetValue(IsSelectedProperty);
set => SetValue(IsSelectedProperty, value);
}
// You can omit this if you only want to use IsSelected via binding in XAML
private static void OnIsSelectedPropertyChanged(BindableObject bindable, object oldValue, object newValue) {
var cell = ((SelectableCell)bindable);
// change color, visibility, whatever depending on (bool)newValue
}
// ...
}
要在列表视图中创建单元格和选择之间的缺失链接,我们需要一个转换器(最初的想法来自Xamarin Forum):
public class IsSelectedConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
value != null && value == ((ViewCell)parameter).View.BindingContext;
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
throw new NotImplementedException();
}
我们使用这个转换器将两者连接起来:
<ListView x:Name="ListViewName">
<ListView.ItemTemplate>
<DataTemplate>
<local:SelectableCell x:Name="ListViewCell"
IsSelected="{Binding SelectedItem, Source={x:Reference ListViewName}, Converter={StaticResource IsSelectedConverter}, ConverterParameter={x:Reference ListViewCell}}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
这个相对复杂的绑定用于检查当前选择了哪个实际项目。它将列表视图的SelectedItem 属性与单元格中视图的BindingContext 进行比较。该绑定上下文是我们实际绑定到的数据对象。换句话说,它检查SelectedItem指向的数据对象是否真的是单元格中的数据对象。如果它们相同,我们就有选定的单元格。我们将它绑定到IsSelected 属性中,然后可以在 XAML 或后面的代码中使用该属性来查看视图单元格是否处于选定状态。
只有一个警告:如果您想在页面显示时设置默认选中项,您需要有点聪明。不幸的是,Xamarin Forms 没有页面 Displayed 事件,我们只有 Appearing 并且设置默认值还为时过早:绑定不会被执行。所以,使用一点延迟:
protected override async void OnAppearing() {
base.OnAppearing();
Device.BeginInvokeOnMainThread(async () => {
await Task.Delay(100);
ListViewName.SelectedItem = ...;
});
}