Plump Worm Plump Worm - 2 months ago 12
C# Question

Displaying only selected items from ListBox in new List

I'm relatively fresh to WPF and discovering XAML.

I've got one

ListBox Name="EmployeeTitles"
in XAML (shown below). For the purpose of demonstrating the problem
DataContext = employees
which is
ObservableCollection<Employee>
.

<ListBox Name="EmployeeTitles"
ItemsSource="{Binding}"
SelectionMode="Extended">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ToggleButton IsChecked="{Binding IsSelected, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}">
<!--StackPanel will have more items-->
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Title}"/>
</StackPanel>
</ToggleButton>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>


My "Code Behind" class snippet looks as follows:

private string _title;
public string Title
{
get { return _title; }
set
{
_title = value;
OnPropertyChanged();
}
}

private bool _isSelected;
public bool IsSelected
{
get
{
return _isSelected;
}
set
{
_isSelected = value;
OnPropertyChanged();
}
}


I would like to show the selected items in a different control. For example have a list that shows only selected items. Can I somehow mark in XAML that I only only want to display items with
IsChecked="True"
? I know I could have another ObservableCollection storing only selected items and updating it in "Code Behind" whenever property
IsSelected
changes, but that seems like an overhead and I suppose there should be a way to do it in XAML?

Answer

You can bind the other listbox with the selecteditems of the original listbox. Try the below code.

<Grid>
    <StackPanel Orientation="Horizontal">
        <ListBox x:Name="Emp" ItemsSource="{Binding EmpCollection}" SelectionMode="Extended">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <ToggleButton IsChecked="{Binding IsSelected, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}">
                            <!--StackPanel will have more items-->
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="{Binding Title}"/>
                            </StackPanel>
                        </ToggleButton>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <ListBox x:Name="SelectedEmp" ItemsSource="{Binding ElementName=Emp,Path=SelectedItems}" DisplayMemberPath="Title"/>
    </StackPanel>
</Grid>
public partial class Window2 : Window
{
    public Window2()
    {
        InitializeComponent();
        this.DataContext = new ViewModel();
    }
}


class ViewModel
{
    public ObservableCollection<Emp> EmpCollection { get; set; }

    public ViewModel()
    {
        EmpCollection = new ObservableCollection<Emp>();
        for (int i = 0; i < 10; i++)
        {
            EmpCollection.Add(new Emp() {Title = "Title"+i});
        }
    }

}

class Emp:INotifyPropertyChanged
{
    private string _title;
    public string Title
    {
        get { return _title; }
        set
        {
            _title = value;
            OnPropertyChanged();
        }
    }

    private bool _isSelected;
    public bool IsSelected
    {
        get
        {
            return _isSelected;
        }
        set
        {
            _isSelected = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    }
}