Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wpf CheckedListbox - how to get selected item

Tags:

c#

wpf

xaml

I've made a CheckedListbox in xaml using this code:

                    <ListBox Height="340" ItemsSource="{Binding Sections}" SelectedItem="{Binding SelectedSection}">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Path=Item}" />
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>

And its bind to this collection:

public ObservableCollection<CheckedListItem<String>> Sections { get; set; }
private CheckedListItem<String> _selectedSection;
public CheckedListItem<String> SelectedSection
    {
        get { return _selectedSection; }
        set 
        {
            _selectedSection = value; 
            RaisePropertyChanged("SelectedSection"); 
        }
    }

The CheckedListItem class looks like this:

    public class CheckedListItem<T> : INotifyPropertyChanged
    {
    public event PropertyChangedEventHandler PropertyChanged;

    private bool isChecked;
    private T item;

    public CheckedListItem()
    { }

    public CheckedListItem(T item, bool isChecked = false)
    {
        this.item = item;
        this.isChecked = isChecked;
    }

    public T Item
    {
        get { return item; }
        set
        {
            item = value;
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Item"));
        }
    }


    public bool IsChecked
    {
        get { return isChecked; }
        set
        {
            isChecked = value;
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("IsChecked"));
        }
    }
}

I tried to set a breakpoint in the _selectedSection = value; part of the code but it never gets triggered when i select/deselect an item in the CheckedListBox.

My question is how can I get the selected item every time its selected/deselected ?

Thanks

like image 655
user1005448 Avatar asked Jan 17 '14 18:01

user1005448


3 Answers

Change your XAML to

<ListBox Height="340" ItemsSource="{Binding Sections}" SelectedItem="{Binding SelectedSection}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <ListBoxItem IsSelected="{Binding IsChecked}">
                <CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Path=Item}" />
            </ListBoxItem>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

You are probably clicking on the actual textblock control inside the checkbox or the square control which doesn't trigger selectionchanged for a listbox. If you try to click outside the bounds of the rectangle say the whitespace then it will fire.

It'll be more work if you just want the checkbox as the datatemplate since you want to select/deselect listboxitem' based on the checkbox IsChecked property. So just wrap it inside a ListBoxItem and you should be good to go.

like image 97
123 456 789 0 Avatar answered Oct 12 '22 12:10

123 456 789 0


My solution (based on Suplanus and lll solutions above):

<ListBox ItemsSource="{Binding Checkboxes}" SelectionMode="Multiple">
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="IsSelected" Value="{Binding Checked, Mode=TwoWay}" />
        </Style>
    </ListBox.ItemContainerStyle>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <CheckBox IsChecked="{Binding Checked, Mode=TwoWay}" Content="{Binding Label}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

I set ListBoxItem IsSelected property througt style (because standard lll's way not work well)! In this case, when CheckBox is checked ListBoxItem is selected and vice versa. SelectionMode in this case also works well. You can add SelectedItem (or similar property) in Single SelectionMode

<!-- xaml -->
SelectedItem="{Binding SelectedCheckbox}" SelectionMode="Single"
// cs
public CheckboxData SelectedCheckbox { get; set; }

or maybe even better, work directly with ItemsSource (Checkboxes collection in this case) in behind code (your ViewModel for example).

Behind code (for example):

public partial class MainWindow : Window
{
    public class CheckboxData
    {
        public int Id { get; set; }
        public string Label { get; set; }
        public bool Checked { get; set; }
    }

    public MainWindow()
    {
        DataContext = this;
        for (int i = 0; i < 50; i++)
            Checkboxes.Add(new CheckboxData { Id = i, Label = $"Checkbox {i}" });
    }

    public IList<CheckboxData> Checkboxes { get; set; } = new List<CheckboxData>();
}

Note:
If you want change Checkboxes collection (or selected item) from behind code (and reflect changes in UI) you have to implement INotifyPropertyChanged and notify when collection (or selected item) has been changed (literally, when object has been re created).

like image 38
honzakuzel1989 Avatar answered Oct 12 '22 11:10

honzakuzel1989


I think the better solution is to not declare in a ListboxItem, because the selection on Hover is shown on the Checkbox.

 <ListBox ItemsSource="{Binding Customers}" >
        <ListBox.ItemTemplate>
            <DataTemplate>
                <CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Path=Item.Name}" /> 
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox> 
like image 32
Suplanus Avatar answered Oct 12 '22 10:10

Suplanus