Xamarin - 清除ListView选择

11

我正在处理这段代码

using System;
using Xamarin.Forms;
using System.Diagnostics;

namespace CryptoUI
{
    public class HomePage : Xamarin.Forms.MasterDetailPage
    {
        public HomePage()
        {
        // Set up the Master, i.e. the Menu
            Label header = new Label
            {
                Text = "MENU",
                Font = Font.SystemFontOfSize(20, FontAttributes.Bold),
                HorizontalOptions = LayoutOptions.Center
            };
        // create an array of the Page names
        string[] myPageNames = {
            "Main",
            "Page 2",
            "Page 3",
        };

        // Create ListView for the Master page.
        ListView listView = new ListView
        {
            ItemsSource = myPageNames,
        };

        // The Master page is actually the Menu page for us
        this.Master = new ContentPage
        {
            Title = "Test",
            Content = new StackLayout
            {
                Children = 
                {
                    header, 
                    listView
                },
            }
        };

        // Define a selected handler for the ListView contained in the Master (ie Menu) Page.
        listView.ItemSelected += (sender, args) =>
        {
            // Set the BindingContext of the detail page.
            this.Detail.BindingContext = args.SelectedItem;

            string currentPage = this.GetType().Name.ToString();

            // This is where you would put your “go to one of the selected pages”
            if(listView.SelectedItem.Equals("Main") && !currentPage.Equals("HomePage")){
                AsyncPush(new HomePage());
            }
            else if(listView.SelectedItem.Equals("Page 2") && !currentPage.Equals("SecondPage")){
                AsyncPush(new SecondPage());
            }
            else if(listView.SelectedItem.Equals("Page 3") && !currentPage.Equals("ThirdPage")){
                AsyncPush(new ThirdPage());
            }               

            // Show the detail page.
            this.IsPresented = false;
        };
            listView.ItemSelected += (senders, e) => {
                if (e.SelectedItem == null) return; // don't do anything if we just de-selected the row
                // do something with e.SelectedItem
                ((ListView)senders).SelectedItem = null; // de-select the row
            };

        // Set up the Detail, i.e the Home or Main page.
        Label myHomeHeader = new Label
        {
            Text = "Home Page",
            HorizontalOptions = LayoutOptions.Center
        };

        string[] homePageItems = { "Alpha", "Beta", "Gamma" };
        ListView myHomeView = new ListView {
            ItemsSource = homePageItems,
        };

        var myHomePage = new ContentPage();

        myHomePage.Content = new StackLayout
        {
            Children = 
            {
                myHomeHeader, 
                myHomeView
            } ,
        };
        this.Detail = myHomePage;
    }

        public async void AsyncPush(Page page)
        {
            await Navigation.PushAsync(page);
        }
    }
}

这段代码显示了一个简单的FlyOut菜单,使用Xamarin Forms技术实现。我正在尝试理解如何在选择要前往的页面后轻松清除ListView的选中状态!

我在Xamarin开发者网站上找到了这段代码(http://developer.xamarin.com/guides/cross-platform/xamarin-forms/working-with/listview/);

listView.ItemSelected += (sender, e) => {
    if (e.SelectedItem == null) return; // don't do anything if we just de-selected the row
    // do something with e.SelectedItem
    ((ListView)sender).SelectedItem = null; // de-select the row
};

但是我目前无法弄清楚如何将它与上面的代码集成 :)

1
首先,您不需要单独使用ItemSelected事件来完成此操作。我认为您只需调用listview.SelectedItem = null来重置listview的selecteditem属性即可。可以在推送新页面之前或之后执行。其次,最好使用"ItemTapped"事件来启动页面转换,并使用ItemSelected来处理/传递数据到下一个视图。 - Jared Reeves
你的代码:public async void AsyncPush(Page page) { await Navigation.PushAsync(page); } 引入了一个bug,使得用户可以双击链接并打开多个页面到导航堆栈中。 - Krausladen
5个回答

20

由于Jason的回答缺少一些关键信息,我想补充一下。当您将ListView的SelectedItem属性设置为null时,它会再次触发ItemSelected事件。因此,如果您没有进行null检查,它将抛出异常。

正确的写法如下:

void ItemSelected(object sender, EventArgs args)
{
    if (((ListView)sender).SelectedItem == null)
      return;
    //Do stuff here with the SelectedItem ...
    ((ListView)sender).SelectedItem = null;
}

这是正确的答案,谢谢,这里有一个依据你想法的要点 https://gist.github.com/ajonno/6ae0d2aebfae79d2ec9c - Badr Bellaj

19

你重复分配了ItemSelected处理程序,这是一个不好的做法。你只需要将这行代码添加到现有的ItemSelected处理程序中即可。

  ((ListView)sender).SelectedItem = null; 

谢谢您的快速回答!不过我之前已经尝试过了,但是每次我点击ListView中的任何元素时,都只会得到这个:http://1drv.ms/1s0K0cO - Guido Magrin
如果你将那行代码添加到你的ItemSelected处理程序的顶部,那么所有后续对SelectedItem的引用都会失效,因为它现在是null。试着将它添加到处理程序底部,在所有其他引用它的代码之后。 - Jason
嗯,如果您查看我链接的截图,我正在做您所说的事情,但仍然一切都崩溃了 :( - Guido Magrin
4
在进入那个大的 IF 代码块之前,尝试检查 SelectedItem 是否为 null。 - Jason

3

我曾经遇到过同样的问题,但其他解决方案对我不起作用。由于我需要将自定义对象传递到下一页,因此我将选定项引用设置为null,并使用项目点击引用来引用我的自定义对象。

listView.ItemTapped += async (sender, e) =>{

    await Navigation.PushAsync(new DetailPage(e.Item as CustomObject));
    ((ListView)sender).SelectedItem = null;

};

由于您在导航上使用了异步操作,这会引入一个错误,允许用户在足够快的情况下双击推送两个项目到导航堆栈。您需要点击两次返回按钮才能清除这两个页面。 - Krausladen

2

ListView.SelectedItem属性没有setter(我的意思是简单的Xamarin Android - 不是Xamarin.Forms)。我建议使用以下代码:

private void DeselectEntities()
{
    if (this.listView != null && this.listView.CheckedItemPositions != null)
    {
        this.listView.CheckedItemPositions.Clear();
    }
}

2

我尊重所有给出的答案,但在MVVM应用程序中,最好避免过多的代码。我通常的做法是:

  1. Bind ItemsSource of ListView as usual to an ObservableCollection where T is a CarViewModel in my case

  2. Set SelectionMode="None": This does avoid the selection of SelectedItem on tap

  3. Use EventToCommandBehavior (I use my own implementation; see github.com or use the one from Prism.Forms) to bind ItemTapped event of ListView to my ViewModel command SelectedCarChangedCommand.

  4. In the ViewModel's SelectedCarChangedCommand you'll receive the tabbed item as ItemTappedEventArgs object.

     <ListView
       x:Name="CarsListView"
       ItemsSource="{Binding Cars}"
       SelectionMode="None">
         <ListView.Behaviors>
             <behaviors:EventToCommandBehavior
                 Command="{Binding SelectedCarChangedCommand}"
                 EventName="ItemTapped" />
         </ListView.Behaviors>
    

通常情况下这是好的,但我发现在推送导航栈的情况下,命令不起作用,因为您可以双击、三击或连续点击10次并打开许多实例。 - Krausladen
1
可以通过在SelectedCarChangedCommand实现中设置canExecute标志来处理这种多点触控情况。我认为这就是我解决它的方法。 - thomasgalliker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接