Reputation: 33
I have a ListView with multiple items. The ListViewItems is a template that contains details about the item from the ObservableCollection and a Button.
My goal is for the button to only be visible on the very last ListViewItem. To that end I implemented a converter and bound it to the Button's visibility, which checks ListViewItem's index vs the ListView's count and returns Visibility.Visible or Visibility.Collapsed.
This works fine when the page first loads, but when I add additional items to the ListView, it doesn't update the existing ListViewItems, it only runs the Converter for the new Items.
Is there a nice xaml (MVVM friendly) way to trigger it to run the Binding?
My XAML:
<ListView x:Name="lstBox" ItemsSource="{Binding People}" Background="Yellow" >
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBlock Text="{Binding Firstname}" />
<Button Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListView}}, Path=DataContext.AddPersonCommand}" Content="Add Person" Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListViewItem}}, Converter={StaticResource IsLastItemToVisibilityConverter}}" />
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
My Converter:
public class IsLastItemToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
ListViewItem item = value as ListViewItem;
ListView ListView = ItemsControl.ItemsControlFromItemContainer(item) as ListView;
int index = ListView.ItemContainerGenerator.IndexFromContainer(item);
if (index == ListView.Items.Count - 1)
{
return Visibility.Visible;
}
else
{
return Visibility.Collapsed;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Upvotes: 2
Views: 958
Reputation: 446
Another possibility is to pass the item as a command parameter.
<ListView x:Name="lstBox"
Background="Yellow"
ItemsSource="{Binding People}">
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBlock Text="{Binding FirstName}" />
<Button Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListView}},
Path=DataContext.AddPersonCommand}"
CommandParameter="{Binding}"
Content="Add Person"
Visibility="{Binding IsEnabled,
RelativeSource={RelativeSource Self},
Converter={StaticResource BooleanToVisibilityConverter}}" />
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The CanExecute of the command should return true only when the item is last in the collection. Something like this:
private bool CanAddPerson(object arg)
{
return _people.Last().Equals(arg);
}
Upvotes: 1
Reputation: 146
The ObservableCollection
should contain items of a ViewModel Type (like Person or whatever you want to call it). That viewmodel should contain a Visibility
value for each of the items button and you change your converter to a BoolToVisibilityConverter
.
In this sollution you just have to update the visibility of items when you change the collection. You have an event where you can do this. Check this answer for more details about the collection changed event.
Hope it helps.
Upvotes: 0