0
votes

I am trying to implement in WPF a way for the user to select multiple items in one box and via button click add those selected items to the other box.

I am trying to adhere to MVVM w/ minimal code behind. The solutions I find show the DataContext being manipulated via the View code behind which I am trying to avoid.

I think my issue is I do not know how to toggle the IsSelected from xaml, but not sure.

enter image description here

XAML

<ListView
                            ItemsSource="{Binding AvailableStates, Mode=TwoWay}"
                            SelectedItem="{Binding SelectedStates, Mode=TwoWay}"
                            SelectionMode="Multiple"

                            DisplayMemberPath="state"
                            Grid.Row="1" 
                            Margin="5"
                            Grid.Column="1" 
                            Height="125"
                            Name="lvAvailableStates"
                            Grid.RowSpan="6" 
                            ScrollViewer.VerticalScrollBarVisibility="Visible"
                            ScrollViewer.CanContentScroll="True">
                            <ListView.ItemContainerStyle>
                                <Style TargetType="{x:Type ListBoxItem}">
                                    <Setter Property="IsSelected" Value="{Binding IsSelected}"/>
                                </Style>
                            </ListView.ItemContainerStyle>
                        </ListView>

<Button
                        Grid.Row="2"
                        Grid.Column="2"
                        Margin="10"
                            Command="{Binding AddSelectedStatesCommand}"
                        Content=">>" />

ViewModel

 private ObservableCollection<SelectableItemWrapper<states_approved>> _selectedStates;
    public ObservableCollection<SelectableItemWrapper<states_approved>> SelectedStates
    {
        get { return _selectedStates; }
        set
        {

            _selectedStates = value;
            OnPropertyChanged();
        }
    }

    private void AddSelectedStates(object obj)
    {
        var selected = SelectedStates.Where(s => s.IsSelected)
            .Select(s => s.Item)
            .ToList();

        StatesApproved = selected;
    }

public CustomCommand AddSelectedStatesCommand
    {
        get
        {
            return new CustomCommand(AddSelectedStates, CanExecute);
        }
    } 

Selected Item Wrapper

public class SelectableItemWrapper<T>
{
    public bool IsSelected { get; set; }
    public T Item { get; set; }
}
1
Your question is a bit unclear. What is your actual issue? There is only ListView in the sample markup you have posted. How is the AddSelectedStates method supposed to be called? - mm8
By clicking the button with >> in it. ie, user selects 3 states in left listview, clicks the >> button, and it populates the right list view. I will add the button code as well. - Brian Emmerling

1 Answers

1
votes

ListView has internal property to determine which item is selected and it also has SelectedItems to determine multiple selected items. However, this plural SelectedItems of ListView is not bindable. So, the solution is to pass them as a CommandParameter.

<ListView x:Name="lvAvailableStates"
          ItemsSource="{Binding AvailableStates, Mode=TwoWay}"
          SelectedItem="{Binding SelectedStates, Mode=TwoWay}" => remove this!
          ...

<Button Command="{Binding AddSelectedStatesCommand}"
        CommandParameter="{Binding SelectedItems, Mode=OneWay, ElementName=lvAvailableStates}" => add this!
        ...

In the VM

private void AddSelectedStates(IEnumerable<SelectableItemWrapper<states_approved>> selectedItems)
{
    StatesApproved = selectedItems
        .Select(s => s.Item) // only retrieve the Item
        .ToList();
}

As you can see at this point, you don't even really need the SelectableItemWrapper to set/unset the IsSelected property to begin with. You should just remove the wrapper and life will be easier.