使用Xamarin Forms ListView,每次在列表中选择一个元素时都会触发ItemSelected事件。
是否可以取消此事件,以便不选择新项目,而仍选择旧项目?
用例是主视图/详细视图类型,在其中选择列表中的项目会更改详细信息。但是,先前选择的详细视图可能已更改,并且用户需要在更改列表的SelectedItem之前决定放弃或保存先前的更改。
答案 0 :(得分:0)
@SushiHangover的建议是控制SelectionMode属性并禁用/启用对ListView的选择。但是,我有一个替代解决方案,它将为可能有类似需求的任何人将ListView的选定项目还原为上一个项目。
我只会发布解决方案的摘要,但它们应该足够完整,以供其他人学习和实施。
首先,我正在使用FreshMVVM,它提供了(实质上)将View绑定到ViewModel的语法糖。同样,PropertyChanged nuget包在编译时创建INotifyPropertyChanged样板代码。这就是为什么您看不到通常通过该界面看到的熟悉的XF模式。 AddINotifyPropertyChanged处理所有这些事情。
解决我的问题的方法是专用的通用ListViewModel,它可以绑定到任何需要“回滚”选择更改事件的能力的ListView。它绑定到Items集合。另外,SelectedItem属性也绑定到控件。
构造函数使用一个Func,调用该Func来确定是否可以移动所选内容。
[AddINotifyPropertyChangedInterface]
public class ListViewModel<T>
{
private Func<bool> _beforeChangeValidator;
private Action _afterChange;
public ListViewModel(Func<bool> beforeChangeValidator, Action afterChange)
{
_beforeChangeValidator = beforeChangeValidator;
_afterChange = afterChange;
_changing = false;
}
public int SelectedIndex { get; set; }
public T SelectedItem { get; set; }
public ObservableCollection<T> Items { get; set; }
private bool _changing;
public Command SelectedItemChanged
{
get
{
return new Command((args) =>
{
if (!_changing)
{
if (_beforeChangeValidator())
{
SelectedIndex = ((SelectedItemChangedEventArgs)args).SelectedItemIndex;
}
}
_changing = false;
});
}
}
public void RevertSelectedItemChanged()
{
_changing = true;
SelectedItem = Items[SelectedIndex];
}
}
父级ViewModel中的代码具有Func(TagListBeforeChange),该函数确定是否可以移动选择。在这种情况下,我要检查上次选择的项目是否已更改,如果已更改,请提示用户要做什么。
public override void Init()
{
TagListViewModel = new ListViewModel<Tag>(TagListBeforeChange, null);
}
private bool TagListBeforeChange()
{
if (ActiveTag.HasChanged)
{
var confirmConfig = new ConfirmConfig()
{
Message = "Current tag has changed. Discard changes and continue?",
OkText = "Discard Changes",
CancelText = "Cancel",
OnAction = (result) =>
{
if (result)
{
_mapper.Map(TagListViewModel.SelectedItem, ActiveTag);
}
else
{
TagListViewModel.RevertSelectedItemChanged();
}
}
};
_userDialogs.Confirm(confirmConfig);
return false;
}
_mapper.Map(TagListViewModel.SelectedItem, ActiveTag);
return true;
}
最后,这是ListView控件声明...
<ListView ItemsSource="{Binding TagListViewModel.Items}"
SelectedItem="{Binding TagListViewModel.SelectedItem, Mode=TwoWay}">
<ListView.Behaviors>
<behaviors:EventHandlerBehavior EventName="ItemSelected">
<behaviors:InvokeCommandAction Command="{Binding TagListViewModel.SelectedItemChanged}" />
</behaviors:EventHandlerBehavior>
</ListView.Behaviors>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ContentView Padding="8">
<Label Text="{Binding DisplayValue}" />
</ContentView>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>