EDIT 1 . Updated answer in accordance with updates to the question. those. Add support for switching between backlight on / off.
EDIT 2 - restructure your response and add more details.
Option-1: enable / disable view cells through IsEnabled
The simplest option would be to use the IsEnabled property, which in turn enables / disables background flash behavior. The only drawback of this approach is that it will also disable the taps of the child controls, i.e. Event / Gesture Recognizer events will not be fired if the parent view of the IsEnabled cell is false .
For instance:
Xaml
<!-- Add name attribute to view-cell --> <ViewCell x:Name="deselectCell" ..> <Grid> <Grid x:Name="deselectGridLink" .. .... </ViewCell>
Code for
private void SetPageDetails() { if (App.cardCountForSelectedCategories == 0) { deselectCell.IsEnabled = false;
Recommendation 1 - Use data binding and triggers
Instead of controlling the visibility for each label in the code, you can use triggers and data binding as follows (the view model will have the IsDeselectEnabled property):
<ViewCell IsEnabled="{Binding IsDeselectEnabled}" Height="50"> <Label Margin="20,0,20,0" Style="{DynamicResource ListItemTextStyle}" HorizontalOptions="StartAndExpand" VerticalOptions="Center" Text="Deselect All"> <Label.Triggers> <DataTrigger TargetType="Label" Binding="{Binding IsDeselectEnabled}" Value="true"> <Setter Property="TextColor" Value="Blue" /> </DataTrigger> <DataTrigger TargetType="Label" Binding="{Binding IsDeselectEnabled}" Value="false"> <Setter Property="TextColor" Value="Silver" /> </DataTrigger> </Label.Triggers> </Label> </ViewCell>
Recommendation 2 - Use triggers with a view as a source
<ViewCell x:Name="deselectCell" Height="50"> <Label Margin="20,0,20,0" Style="{DynamicResource ListItemTextStyle}" HorizontalOptions="StartAndExpand" VerticalOptions="Center" Text="Deselect All"> <Label.Triggers> <DataTrigger TargetType="Label" Binding="{Binding IsEnabled, Source={x:Reference deselectCell}}" Value="true"> <Setter Property="TextColor" Value="Blue" /> </DataTrigger> <DataTrigger TargetType="Label" Binding="{Binding IsEnabled, Source={x:Reference deselectCell}}" Value="false"> <Setter Property="TextColor" Value="Silver" /> </DataTrigger> </Label.Triggers> </Label> </ViewCell>
Option-2: Turn on / off the backlight, but allow taps
To enable taps when switching ViewCell background-highlight behavior, we will need to implement platform rendering tools.
In the case of iOS, we can use SelectionStyle to switch this behavior, while in the case of android, we can use Clickable .
General control:
public class CustomViewCell : ViewCell { public static readonly BindableProperty AllowHighlightProperty = BindableProperty.Create( "AllowHighlight", typeof(bool), typeof(CustomViewCell), defaultValue: true); public bool AllowHighlight { get { return (bool)GetValue(AllowHighlightProperty); } set { SetValue(AllowHighlightProperty, value); } } }
iOS renderer:
[assembly: ExportRenderer(typeof(CustomViewCell), typeof(CustomViewCellRenderer))] namespace SampleApp.iOS { public class CustomViewCellRenderer : ViewCellRenderer { UITableViewCell _nativeCell; //get access to the associated forms-element and subscribe to property-changed public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv) { _nativeCell = base.GetCell(item, reusableCell, tv); var formsCell = item as CustomViewCell; if (formsCell != null) { formsCell.PropertyChanged -= OnPropertyChanged; formsCell.PropertyChanged += OnPropertyChanged; } //and, update the style SetStyle(formsCell); return _nativeCell; } void OnPropertyChanged(object sender, PropertyChangedEventArgs e) { var formsCell = sender as CustomViewCell; if (formsCell == null) return; //TODO: Trying to find a nicer and more robust way to dispose and unsubscribe :( if (_nativeCell == null) formsCell.PropertyChanged -= OnPropertyChanged; if (e.PropertyName == CustomViewCell.AllowHighlightProperty.PropertyName) { SetStyle(formsCell); } } private void SetStyle(CustomViewCell formsCell) { //added this code as sometimes on tap, the separator disappears, if style is updated before tap animation finishes //https://stackoverflow.com/questions/25613117/how-do-you-prevent-uitableviewcellselectionstylenone-from-removing-cell-separato Device.StartTimer(TimeSpan.FromMilliseconds(50), () => { Device.BeginInvokeOnMainThread(() => { if (formsCell.AllowHighlight) _nativeCell.SelectionStyle = UITableViewCellSelectionStyle.Default; else _nativeCell.SelectionStyle = UITableViewCellSelectionStyle.None; }); return false; }); } } }
Android rendering tool:
[assembly: ExportRenderer(typeof(CustomViewCell), typeof(CustomViewCellRenderer))] namespace SampleApp.Droid { public class CustomViewCellRenderer : ViewCellRenderer { Android.Views.View _nativeCell; protected override Android.Views.View GetCellCore(Cell item, Android.Views.View convertView, Android.Views.ViewGroup parent, Android.Content.Context context) { _nativeCell = base.GetCellCore(item, convertView, parent, context); SetStyle(); return _nativeCell; }
Case Study 1 - Through Data Binding
<local:CustomViewCell AllowHighlight="{Binding IsHighlightEnabled}" ..> <Grid> <Grid x:Name="deselectGridLink" .. ... </local:CustomViewCell>
Case Study 2 - Using Code
Xaml
<!-- Add name attribute to view-cell --> <local:CustomViewCell x:Name="deselectCell" ..> <Grid> <Grid x:Name="deselectGridLink" .. ... </local:CustomViewCell>
Code for
private void SetPageDetails() { if (App.cardCountForSelectedCategories == 0) { deselectCell.AllowHighlight= false;
Option-3: Disable selection, selection for all elements
This is especially true for ListView . The updated question now indicates that the cells are part of the TableView , so this parameter is no longer valid in the current context of the question.
You will need to implement platform rendering tools to turn off highlighted colors, and add an ItemTapped handler to the ListView to turn off the selection, setting SelectedItem to null always. Used links:
code
To get started, create a custom view cell:
public class NoSelectViewCell : ViewCell { }
Implementing the iOS renderer as:
[assembly: ExportRenderer(typeof(NoSelectViewCell), typeof(NoSelectViewCellRenderer))] namespace SampleApp.iOS { public class NoSelectViewCellRenderer : ViewCellRenderer { public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv) { var nativeCell = base.GetCell(item, reusableCell, tv); nativeCell.SelectionStyle = UITableViewCellSelectionStyle.None; return nativeCell; } } }
Implementing a renderer for Android as:
[assembly: ExportRenderer(typeof(NoSelectViewCell), typeof(NoSelectViewCellRenderer))] namespace SampleApp.Droid { public class NoSelectViewCellRenderer : ViewCellRenderer { protected override Android.Views.View GetCellCore(Cell item, Android.Views.View convertView, Android.Views.ViewGroup parent, Android.Content.Context context) { var cell = base.GetCellCore(item, convertView, parent, context); cell.Focusable = false; cell.FocusableInTouchMode = false; var listView = parent as Android.Widget.ListView; if (listView != null) { listView.SetSelector(Android.Resource.Color.Transparent); listView.CacheColorHint = Xamarin.Forms.Color.Transparent.ToAndroid(); } return cell; } } }
Sample Usage:
Xaml
<ListView ItemTapped="Handle_ItemTapped"> <ListView.ItemTemplate> <DataTemplate> <local:NoSelectViewCell Height="50"> <Grid> <Grid x:Name="deselectGridLink" VerticalOptions="CenterAndExpand" Padding="20, 0"> <Label TextColor="Blue" Style="{DynamicResource ListItemTextStyle}" x:Name="deselectLink" HorizontalOptions="StartAndExpand" VerticalOptions="Center" Text="Deselect All" /> </Grid> <Grid x:Name="deselectGridLabel" VerticalOptions="CenterAndExpand" Padding="20, 0"> <Label TextColor="Silver" Style="{DynamicResource ListItemTextStyle}" x:Name="deselectLabel" HorizontalOptions="StartAndExpand" VerticalOptions="Center" Text="Deselect All" /> </Grid> </Grid> </local:NoSelectViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView>
Code for
void Handle_ItemTapped(object sender, Xamarin.Forms.ItemTappedEventArgs e) {