How to Bind IsSelected Property in DataTemplate of ListViewItem
uwp, xaml
Solution
I don't recommend changing the ListViewItem template since you lose all the bells and whistles it provides (selection appearance, ability to be checked, etc).
Using `Mode=TemplatedParent` in the second snippet won't work because the templated parent from that context is a ListViewItemPresenter, not the ListViewItem (which is the presenter's parent).
It looks like what you're trying to do is to show additional information in the list item when it is selected.
Single selection
C# classes
public class NotifyPropertyChangedBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetProperty<T>(ref T property, T value, [CallerMemberName] string propertyName = "")
{
if (EqualityComparer<T>.Default.Equals(property, value))
{
return false;
}
property = value;
OnPropertyChanged(propertyName);
return true;
}
}
public class Item : NotifyPropertyChangedBase
{
private string text;
public string Text
{
get { return text; }
set { SetProperty(ref text, value); }
}
private bool isSelected;
public bool IsSelected
{
get { return isSelected; }
set { SetProperty(ref isSelected, value); }
}
}
public class MainPageViewModel : NotifyPropertyChangedBase
{
public List<Item> Items { get; set; }
private Item selectedItem;
public Item SelectedItem
{
get { return selectedItem; }
set
{
if (selectedItem != value)
{
if (selectedItem != null)
{
selectedItem.IsSelected = false;
}
SetProperty(ref selectedItem, value);
if (selectedItem != null)
{
selectedItem.IsSelected = true;
}
}
}
}
public MainPageViewModel()
{
Items = new List<Item>()
{
new Item() { Text = "Apple" },
new Item() { Text = "Banana" },
};
}
}
MainPage.xaml
<ListView ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Item">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Text}"/>
<!-- x:Bind doesn't require visibility converter if min SDK is targeting Anniversary update -->
<TextBlock Text="I'm selected!" Grid.Column="1" Visibility="{x:Bind IsSelected, Mode=OneWay}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
MainPage.xaml.cs
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
DataContext = new MainPageViewModel();
}
}
Multiple selection
Same as single selection but with the following changes:
MainPageViewModel
public class MainPageViewModel : NotifyPropertyChangedBase
{
public List<Item> Items { get; set; }
public MainPageViewModel()
{
Items = new List<Item>()
{
new Item() { Text = "Apple" },
new Item() { Text = "Banana" },
};
}
public void SelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (Item item in e.RemovedItems)
{
item.IsSelected = false;
}
foreach (Item item in e.AddedItems)
{
item.IsSelected = true;
}
}
}
MainPage.xaml
<ListView ItemsSource="{Binding Items}" SelectionChanged="{x:Bind ViewModel.SelectionChanged}" SelectionMode="Extended">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Item">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Text}"/>
<TextBlock Text="I'm selected!" Grid.Column="1" Visibility="{x:Bind IsSelected, Mode=OneWay}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
MainPage.xaml.cs
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
DataContext = new MainPageViewModel();
}
public MainPageViewModel ViewModel => (MainPageViewModel)DataContext;
}
Problem
Well, I want to make the `ListViewItem` in UWP ,that'll be changing his view on selecting. So I need to change the `Visibility` property of some elements of `ListViewItem` on selecting. I found some way to do this with making custom Style of `ListViewItem` and Binding `IsSelected` property like this: ``` <Style x:Key="VehicleListViewItemStyle" TargetType="ListViewItem" > <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ListViewItem"> <Grid Background="Gray" Margin="1"> <Border Margin="2" Padding="10" Background="Gray" > <StackPanel> <ContentPresenter x:Name="Presenter1" /> <StackPanel Orientation="Horizontal" Background="Transparent" Margin="-10,0,-9,-9" VerticalAlignment="Center" x:Name="infoPanel" Visibility="{Binding IsSelected, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource BooleanToVisibilityConverter}}"> <TextBlock Text="{Binding DeviceID}/> </StackPanel> </StackPanel> </Border> <Border BorderThickness="1" BorderBrush="Orange" Visibility="{Binding IsSelected, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource BooleanToVisibilityConverter}}"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> ``` Its working good, but with this way I cant bind the `DeviceID` text. Another one way is creating `DataTemplate` like this: ``` <DataTemplate x:Key="monitoringListViewItem" x:Name="item"> <Grid Background="Gray" Margin="1" Width="300" > <StackPanel> <ContentPresenter x:Name="Presenter"/> <StackPanel Orientation="Horizontal"> <Image Source="/Assets/14th_crane_stop.png" Height="50" Width="50" Stretch="Uniform"/> <StackPanel Orientation="Vertical" Margin="25,0,0,0 " Visibility="{Binding IsSelected, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource BooleanToVisibilityConverter}}" > <TextBlock Text="{Binding DeviceID}" Style="{StaticResource VehicleTextStyle}"/> <TextBlock Text="{Binding Mark}" Style="{StaticResource VehicleTextStyle}"/> </StackPanel> </StackPanel> </StackPanel > </Grid> </DataTemplate> ``` Now I can bind the text correctly, but cant bind the `IsSelected` property. I've tried to do this with different Modes, but it still doesn't work because I cant use the `TemplatedParent` key inside the DataTemplate. So I need some answers: -can I bind the text in first way and how can I do that? -how can I bind the `IsSelected` property in the second way?