29

I'm working with Xamarin.Forms and XAML, and I'm trying to create an application that stores a list of products. I put my list of products in a ListView. This works fine. Here is my XAML:

<ListView x:Name="listSushi"
        ItemsSource="{x:Static local:myListSushi.All}"
        SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
        RowHeight="{StaticResource rowHeight}"
        >
<ListView.ItemTemplate>
  <DataTemplate>
    <ViewCell>
      <ViewCell.View>
        <StackLayout Padding="5, 5, 0, 5"
                     Orientation="Horizontal"
                     Spacing="15">
          <StackLayout>
            <Image Source="{Binding ImageSource}" />
          </StackLayout>

          <StackLayout Padding="0, 0, 0, 0"
                       VerticalOptions="Center"
                       HorizontalOptions="FillAndExpand">                
                <Label Text="{Binding Name}"
                   Font="Bold, Medium" />
                <Label Text="{Binding Description}" 
                    Font="Small"/>
          </StackLayout>

          <StackLayout Orientation="Horizontal"
                        Padding="0, 0, 10, 0">
            <Button Text=" - " 
                    HorizontalOptions="EndAndExpand"
                    VerticalOptions="FillAndExpand"
                    Command="{Binding DeleteSushiCommand}"
                    CommandParameter="{Binding Name}"
                    />
            <Label VerticalOptions="Center" 
                   Text="{Binding Number,StringFormat='{0}'}"
                   TextColor="Black"/>
            <Button Text=" + " 
                    HorizontalOptions="EndAndExpand"
                    VerticalOptions="FillAndExpand" 
                    Command="{Binding AddSushiCommand}"
                    CommandParameter="{Binding Name}"
                    />
            </StackLayout>
        </StackLayout>
      </ViewCell.View>
    </ViewCell>
  </DataTemplate>
</ListView.ItemTemplate>

I've just the problem that if I click on a cell of my listView, the cell is highlight, and stay highlight. I've try to disable it with this code in the xaml.cs

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

But when I touch a cell, now my list is scrolling automatically. It's very strange.

Does anyone know if this is a bug, or know a fix, like if there is a property where I can disable the highlight?

wonea
  • 4,783
  • 17
  • 86
  • 139
dpfauwadel
  • 3,866
  • 3
  • 23
  • 40

6 Answers6

48

You might try using the ItemTapped event instead, i.e.

listSushi.ItemTapped += (object sender, ItemTappedEventArgs e) => {
    // don't do anything if we just de-selected the row.
    if (e.Item == null) return;

    // Optionally pause a bit to allow the preselect hint.
    Task.Delay(500);

    // Deselect the item.
    if (sender is ListView lv) lv.SelectedItem = null;

    // Do something with the selection.
    ...
};

I have tested this on a ListView (on an Android device) that has enough items to bring scrolling into the mix. I see no auto-scroll behavior, and your idea to set SelectedItem null to defeat the highlight works great.

Mark Larter
  • 2,343
  • 1
  • 27
  • 34
  • 1
    While the `ViewCell` isn't selected with this solution, this will still show a "preselect" state on the `ViewCell` while the finger is shortly tapping or holding the tap on the `ViewCell`, [as viewed in this screenshot](https://imgur.com/CGoB0w9) – Dennis Schröer Jun 25 '18 at 13:53
  • In all of the use cases I have run across, the preselect was the desired behavior. So much so that I updated my answer to include a delay that ensures the user gets a bit of feedback that they tapped the one they intended. – Mark Larter Jul 03 '18 at 21:30
  • 2
    `Task.Delay(500)` doesn't delay by itself. You have to await the task it creates: `await Task.Delay(500);`. – Edward Brey Sep 25 '19 at 19:19
23

Current we can set ListView.SelectionMode to None to do this. https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/listview/interactivity

Jesse Jiang
  • 955
  • 6
  • 8
18

I just found another method to disable the highlight effect. And i would like to share this with other users.

You can do it directly at xaml. But this method not only disable the highlight effect, it will also disable the click event.

You can set the IsEnabled attribute of ViewCell to false.

<ViewCell IsEnabled="false">
    //Your Item Layout Coding
</ViewCell>

In addition, you can also disable/enable each item highlight effect by binding:

<ViewCell IsEnabled="{Binding IsHighlightEnabled}">
    //Your Item Layout Coding
</ViewCell>

Hope that helps, thanks.

Sonny Ng
  • 2,051
  • 1
  • 17
  • 14
  • 6
    This will disable highlighting but it's worth noting it will also disable any button click events that might be in your ViewCell – Nick Peppers Jan 08 '18 at 16:00
  • Disables scroll too. – Ian Warburton Jun 05 '18 at 00:12
  • I have a property like IsHighlightEnabled bound to a variable that changes when my keyboard is shown or hidden. This means when I tap on a list item when the keyboard is showing, the keyboard disappears and my item is tappable. How can I block taps first, close the keyboard and then hide the keyboard? – Chucky Feb 05 '19 at 15:45
  • 2
    @IanWarburton It doesn't disable scroll. Settings `IsEnabled=false` on the ListView itself would, but not if used on individual cell. – masiton Jan 22 '20 at 16:39
  • Thank you. This had taken me ages of faffing to try and prevent the highlighting but this works perfectly. – Journeyman1234 Mar 19 '21 at 09:39
7
YourList.ItemSelected+=DeselectItem;

 public void DeselectItem(object sender, EventArgs e)
  {
     ((ListView)sender).SelectedItem = null;
  }

This should be helpful for your scenario. @dpfauwadel

hering
  • 1,956
  • 4
  • 28
  • 43
Riyas
  • 475
  • 1
  • 8
  • 27
6

I am assuming you are using MVVM. In these cases I assign a null to the property after using it. In your viewmodel you seem to have a SelectedItem property since you are binding it to the SelectedItem property of the ListView. So I would do something like this:

private Product _selectedItem;
public Product SelectedItem
{
  get
  {
    return _selectedItem;
  }
  set
  {
    _selectedItem = value;

    //USE THE VALUE

    _selectedItem = null;
    NotifyPropertyChanged("SelectedItem");
  }
}
valdetero
  • 4,624
  • 1
  • 31
  • 46
jgarza
  • 556
  • 5
  • 11
  • 3
    This solution worked for me. I had already been setting _selectedItem = null but that wasn't sufficient; adding the NotifyPropertyChanged was the key (or in my case, RaisePropertyChanged since I'm using MVVM Light). Note that I also had to set Mode=TwoWay in the XAML View (as a property for SelectedItem) in order for this to work - even though I believe TwoWay is supposed to be the default value for Mode, I had to explicitly set it. – Phil Seeman May 26 '17 at 12:13
  • 1
    In my case using Prism, I made it as simple as `public RecapListViewItem SelectedRecap { get { return null; } set { OnPropertyChanged("SelectedRecap"); } }` – Pierre Fournier Jul 13 '17 at 17:27
  • The other option that works for me is to use a get accessor of ```get=> null;```. The caution is you can't use SelectedItem property as the selected item. But it's quick way to prevent the item being highlighted. I then use a command binding behaviour. So also get async for the list item selection. – NevilleDastur Sep 17 '19 at 20:19
5

On iOS mark's solution didn't solve it for me, I had to create a CustomRenderer for the list view and use that instead.

NonSelectableListView.cs (In your Forms Project)

using System;
using Xamarin.Forms;

namespace YourProject
{
    public class NonSelectableListView : ListView
    {
        public NonSelectableListView()
        {
        }
    }
}

NonSelectableListViewRenderer.cs (CustomRenderer in your iOS project)

using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

using YourProject.iOS;
using YourProject;

[assembly: ExportRenderer(typeof(NonSelectableListView), typeof(NonSelectableListViewRenderer))]
namespace YourProject.iOS
{
    public class NonSelectableListViewRenderer : ListViewRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null)
            {
                // Unsubscribe from event handlers and cleanup any resources
            }

            if (e.NewElement != null)
            {
                // Configure the native control and subscribe to event handlers
                Control.AllowsSelection = false;
            }
        }
    }

}
Dolan
  • 313
  • 1
  • 4
  • 14
RobVoisey
  • 1,083
  • 15
  • 24