How to Control Xamarin Forms ListView SelectedItem ViewCell Visibility?

yoyokitsyoyokits USMember

In Xamarin Forms XAML, I want to hide part of ViewCell if it is not selected. For example the second label with text="Show only if selected". How to do that?

<ListView x:Name="listView"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <StackLayout> <Label Text="Always Show it"/> <Label Text="Show only if selected" IsVisible={Binding somewhere?}/> </StackLayout> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView>

Answers

  • AlessandroCaliaroAlessandroCaliaro ✭✭✭✭✭ ITMember ✭✭✭✭✭

    Binding is correct. When you select an Item, set "somewhere" property to True and set to False the old selected

  • yoyokitsyoyokits USMember

    @AlessandroCaliaro,
    binding with what? I want to Bind like with ListView.SelectedItem, or maybe IsSelected like in WPF.

  • AlessandroCaliaroAlessandroCaliaro ✭✭✭✭✭ ITMember ✭✭✭✭✭

    in your ListView you should have an ItemSource property.
    This ItemSource should be set to a List, or a ObservableColletcion, right? (here... listView.ItemSource = mylist;)

    in your Model you should have a "somewhere" (ok, call it "Selected" as bool so it's clearer).
    When you select your item on the listView, set Selected to true.
    something like

    listView.ItemSelected += async (sender, e) => {
    
            if (e.SelectedItem == null) return; // don't do anything if we just de-selected the row
    
         await DisplayAlert("Tapped", (e.SelectedItem as YourDataType).Name + " row was selected", "OK");
    
        // Search the current (last) selected item
    
        int lastIdx = mylist.FindIndex(o=>o.Selected == true);
    
        if(lastIdx >=0)
            mylist[lastIdx].Selected = false; // De-select the last selected because now I have another selected item
    
        // Search on your list the selectedItem
        int idx = mylist.FindIndex(o=>o.Name == (e.SelectedItem as YourDataType).Name);
    
        // Set "Selected" to selected item
        mylist[idx].Selected = true;
    
    
    
        ((ListView)sender).SelectedItem = null; // de-select the row
    };
    
  • yoyokitsyoyokits USMember

    Thank you Alessandro, I think your code will work, but I prefer pure XAML if possible and without code behind.
    With your code, the View has direct connection with Model that should be avoided, should be with Data Binding (MVVM concept).

    If possible I want something like:

    <ListView x:Name="listView"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <StackLayout> <Label Text="Always Show it"/> <Label Text="Show only if selected" IsVisible={Binding Source={x:Reference listView}, Path=SelectedItem, Converter={StaticResource SelectedItemToVisibleConverter }, ConverterParameter={Binding} /> </StackLayout> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView>

    And the implementation of Converter is more and less:

    class SelectedItemToVisibleConverter:IValueConverter { public object Convert(object value, ...., object parameter) { return value == parameter; } }

    But It doen't work because converter cannot be bound.

  • AlessandroCaliaroAlessandroCaliaro ✭✭✭✭✭ ITMember ✭✭✭✭✭

    Sorry, I don't use MVVM

  • huangjinshehuangjinshe ✭✭✭ USMember ✭✭✭

    @yoyokits said:
    Thank you Alessandro, I think your code will work, but I prefer pure XAML if possible and without code behind.
    With your code, the View has direct connection with Model that should be avoided, should be with Data Binding (MVVM concept).

    If possible I want something like:

    <ListView x:Name="listView"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <StackLayout> <Label Text="Always Show it"/> <Label Text="Show only if selected" IsVisible={Binding Source={x:Reference listView}, Path=SelectedItem, Converter={StaticResource SelectedItemToVisibleConverter }, ConverterParameter={Binding} /> </StackLayout> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView>

    And the implementation of Converter is more and less:

    class SelectedItemToVisibleConverter:IValueConverter { public object Convert(object value, ...., object parameter) { return value == parameter; } }

    But It doen't work because converter cannot be bound.

    So, do you have a good solution now?

  • HeinziATHeinziAT ATMember

    Yoyokits, I had the same problem and got it to work by modifying your code. It's true that a converter parameter cannot be bound, but we can use x:Reference in the converter parameter and extract the BindingContext.

    XAML:

    <ListView x:Name="listView">
         <ListView.ItemTemplate>
             <DataTemplate>
                 <ViewCell>
                     <StackLayout x:Name="cell">
                         <Label Text="Always Show it"/>
                         <Label Text="Show only if selected"
                                IsVisible={Binding Source={x:Reference listView}, Path=SelectedItem, 
                                                   Converter={StaticResource EqualsParameterContextConverter}, 
                                                   ConverterParameter={x:Reference cell}} />
                     </StackLayout>
                 </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    

    Converter:

    class EqualsParameterContextConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return value == ((View)parameter).BindingContext;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    
  • djgtramdjgtram ✭✭ HUMember ✭✭
    edited October 2018

    @HeinziAT: Almost, the idea is indeed very nice but you need the converter a bit differently because ViewCell isn't actually a View:

    return (value == ((ViewCell)parameter).View.BindingContext);
    

    Besides, if you want to handle the situation when none of the items is selected initially, it pays to add an extra check:

    return (value != null && value == ((ViewCell)parameter).View.BindingContext);
    
Sign In or Register to comment.