Search code examples
c#listviewmvvmuwplistviewitem

UWP - MVVM - Remove ListView item using ItemTemplate button


I have a screen displaying a list of items on which the user can click a button to remove the corresponding item from the list.

I am trying to do so using MVVM.

But the item is not aware of the containing list when it gets the action. I saw some answers here and there, but none of them using out of the box MVVM features I have in my environment For example that one using PRISM (don't know if I should use that too, is it standard?):

Here is the XAML:

<ListView ItemsSource="{Binding MyItemList}" SelectionMode="None" ScrollViewer.VerticalScrollMode="Disabled" ItemContainerTransitions="{x:Null}"> 
    <ListView.ItemTemplate>
        <DataTemplate >
            <Grid Grid.Row="1" HorizontalAlignment="Stretch" >
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="2*" />
                    <ColumnDefinition Width="2*" />
                </Grid.ColumnDefinitions>
                <TextBox Grid.Column="0" Text="{Binding ItemClass.Property01, Mode=TwoWay}" />
                <Button Grid.Column="1" Command="{Binding RemoveItemCommand}" >
                    <SymbolIcon Symbol="Cancel" />
                </Button>
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

And here is the ModelView list:

private static ObservableCollection<ItemClass> _MyItemList = new ObservableCollection<ItemClass> {
    new ItemClass{ Property01 = "Sometext" }
};
public ObservableCollection<ItemClass> MyItemList { get { return _MyItemList; } }

And I want to be able to perform the following (the example of code from the main model view, I could create an item model view if necessary for solving):

public IMvxCommand RemoveItemCommand { get; private set; }
public MyViewModel(IUserDialogs dialogs)
{
    RemoveItemCommand = new MvxCommand(RemoveItem);
}
public void RemoveItem(object theItem) { MyItemList.Remove(theItem); }

Solution

  • Add x:Name="listView" attribute to your ListView, then in the template

    <Button Grid.Column="1"
        Command="{Binding ElementName=listView, Path=DataContext.RemoveItemCommand}"
        CommandParameter="{Binding}" >
    

    However, when I face problems like this, I usually just use code behind instead. The reason for that, I can use debugger for C# code in visual studio, but debugging these complex bindings is much harder. Here’s a C# version, the code is IMO cleaner, and easier to debug:

    void removeItem_Click( object sender, RoutedEventArgs e )
    {
        object i = ((FrameworkElement)sender).DataContext;
        ( this.DataContext as MyViewModel )?.RemoveItem( i );
    }
    

    Or maybe that's just my personal preference.