Xamarin Forms ListView取消ItemSelected事件

时间:2019-06-27 20:41:18

标签: xamarin xamarin.forms

使用Xamarin Forms ListView,每次在列表中选择一个元素时都会触发ItemSelected事件。

是否可以取消此事件,以便不选择新项目,而仍选择旧项目?

用例是主视图/详细视图类型,在其中选择列表中的项目会更改详细信息。但是,先前选择的详细视图可能已更改,并且用户需要在更改列表的SelectedItem之前决定放弃或保存先前的更改。

1 个答案:

答案 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>