HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

ListView MultiSelect, MVVM and RoutedCommands

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
mvvmroutedcommandsandmultiselectlistview

Problem

As far as I know (and I don't claim to know much about this!), direct binding to ListView.SelectedItems isn't possible in WPF. I've seen work-arounds involving code-behind which I'm not too crazy about, especially since I'm having a hard time with getting a DelegateCommand to work, and decided to use RoutedCommands. For the following XAML command binding...


    


...I have the following code-behind:

public static readonly RoutedCommand AddSelectionCommand = new RoutedCommand();

private void CanExecuteAddSelectionCommand(object sender, CanExecuteRoutedEventArgs e)
{
    if (Commands != null)
    {
        Commands.SelectedClients = SearchResultsList.SelectedItems.Cast().ToList();
        e.CanExecute = Commands.CanExecuteAddSelectionCommand();
    }
    e.Handled = true;
}

private void ExecuteAddSelectionCommand(object sender, ExecutedRoutedEventArgs e)
{
    Commands.SelectedClients = SearchResultsList.SelectedItems.Cast().ToList();
    Commands.OnExecuteAddSelectionCommand();
    e.Handled = true;
}


Where Commands is a get-only private property that returns an interface implemented by the ViewModel, which defines all the CanExecuteXXXX and ExecuteXXXX methods.

Here's how I have it:

private IViewModel _viewModel;
private IClientsSearchSectionCommands Commands { get { return _viewModel as IClientsSearchSectionCommands; } }

public ClientSearchSection()
{
    InitializeComponent();
    DataContextChanged += ClientsSearchSection_DataContextChanged;
}

void ClientSearchSection_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    _viewModel = e.NewValue as IViewModel;
}


This allows me to implement the command code in the ViewModel, for example:

public bool CanExecuteAddSelectionCommand()
{
    return SelectedClients.Count > 0;
}

public void OnExecuteAddSelectionCommand()
{
    // whatever needs to happen here, I can access my model as needed
}


The trick that allows the SelectedItems to wo

Solution

Your approach looks fine to me. Except i would probably use prefix-casting, to get cast exceptions straigt away if something goes wrong, instead of using as.

This can be achieved without modifying code-behind tho. You can bind container's IsSelected property to appropriate item's viewmodel property.


    
        
    


Then you can access selected items in your viewmodel by using:

protected IEnumerable SelectedItems { get { return Items.Where(x => x.IsSelected); } }

Code Snippets

<ListView.ItemContainerStyle>
    <Style TargetType="ListViewItem" >
        <Setter Property="IsSelected" Value="{Binding IsSelected}"/>
    </Style>
</ListView.ItemContainerStyle>
protected IEnumerable<Item> SelectedItems { get { return Items.Where(x => x.IsSelected); } }

Context

StackExchange Code Review Q#31926, answer score: 3

Revisions (0)

No revisions yet.