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...
<UserControl.CommandBindings>
<CommandBinding Command="{x:Static my:ClientSearchSection.AddSelectionCommand}"
CanExecute="CanExecuteAddSelectionCommand"
Executed="ExecuteAddSelectionCommand"/>
</UserControl.CommandBindings>
...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<ClientViewModel>().ToList();
e.CanExecute = Commands.CanExecuteAddSelectionCommand();
}
e.Handled = true;
}
private void ExecuteAddSelectionCommand(object sender, ExecutedRoutedEventArgs e)
{
Commands.SelectedClients = SearchResultsList.SelectedItems.Cast<ClientViewModel>().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 work is with this property, exposed by the IClientsSearchSectionCommands
interface implemented by the ViewModel:
public IList<ClientViewModel> SelectedClients { get; set; }
...and the fact that I'm setting them in the commands' CanExecute
and Executed
handlers.
This works beautifully... but is it weird in any way? [How] could it be done better?
I don't want to dive into behaviors at this point, firstly because I have no clue about them, second, because I'm dragging a more junior developper into WPF & MVVM, coming from WinForms and inline-SQL-in-the-form's-code-behind, so I'd like to know if this code is easy enough to follow...