Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Implement a ListBox of Checkboxes in WPF?

Tags:

Although somewhat experienced with writing Winforms applications, the... "vagueness" of WPF still eludes me in terms of best practices and design patterns.

Despite populating my list at runtime, my listbox appears empty.

I have followed the simple instructions from this helpful article to no avail. I suspect that I'm missing some sort of DataBind() method where I tell the listbox that I'm done modifying the underlying list.

In my MainWindow.xaml, I have:

    <ListBox ItemsSource="{Binding TopicList}" Height="177" HorizontalAlignment="Left" Margin="15,173,0,0" Name="listTopics" VerticalAlignment="Top" Width="236" Background="#0B000000">         <ListBox.ItemTemplate>             <HierarchicalDataTemplate>                 <CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}"/>             </HierarchicalDataTemplate>         </ListBox.ItemTemplate>     </ListBox> 

In my code-behind, I have:

    private void InitializeTopicList( MyDataContext context )     {         List<Topic> topicList = ( from topic in context.Topics select topic ).ToList();          foreach ( Topic topic in topicList )         {             CheckedListItem item = new CheckedListItem();             item.Name = topic.DisplayName;             item.ID = topic.ID;             TopicList.Add( item );         }     } 

Which, by tracing through, I know is being populated with four items.

EDIT

I have changed TopicList to an ObservableCollection. It still doesn't work.

    public ObservableCollection<CheckedListItem> TopicList; 

EDIT #2

I have made two changes that help:

In the .xaml file:

ListBox ItemsSource="{Binding}" 

In the source code after I populate the list:

listTopics.DataContext = TopicList; 

I'm getting a list, but it's not automagically updating the checkbox states when I refresh those. I suspect a little further reading on my part will resolve this.

like image 612
Bob Kaufman Avatar asked Dec 24 '10 16:12

Bob Kaufman


2 Answers

Assuming TopicList is not an ObservableCollection<T> therefore when you add items no INotifyCollection changed is being fired to tell the binding engine to update the value.

Change your TopicList to an ObservableCollection<T> which will resolve the current issue. You could also populate the List<T> ahead of time and then the binding will work via OneWay; however ObservableCollection<T> is a more robust approach.

EDIT:

Your TopicList needs to be a property not a member variable; bindings require properties. It does not need to be a DependencyProperty.

EDIT 2:

Modify your ItemTemplate as it does not need to be a HierarchicalDataTemplate

   <ListBox.ItemTemplate>      <DataTemplate>        <StackPanel>          <CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}"/>        </StackPanel>      </DataTemplate>    </ListBox.ItemTemplate> 
like image 129
Aaron McIver Avatar answered Sep 22 '22 05:09

Aaron McIver


Use ObservableCollection<Topic> instead of List<Topic>

Edit

it implements INotifyCollectionChanged interface to let WPF know when you add/remove/modify items

Edit 2

Since you set TopicList in code, it should be a Dependency Property, not a common field

    public ObservableCollection<CheckedListItem> TopicList {         get { return (ObservableCollection<CheckedListItem>)GetValue(TopicListProperty); }         set { SetValue(TopicListProperty, value); }     }     public static readonly DependencyProperty TopicListProperty =         DependencyProperty.Register("TopicList", typeof(ObservableCollection<CheckedListItem>), typeof(MainWindow), new UIPropertyMetadata(null)); 

Edit 3

To see changes in items

  1. implement INotifyPropertyChanged interface in CheckedListItem (each setter should call PropertyChanged(this, new PropertyChangedEventArgs(<property name as string>)) event)
  2. or derive CheckedListItem from DependencyObject, and convert Name, ID, IsChecked to dependency properties
  3. or update them totally (topicList[0] = new CheckedListItem() { Name = ..., ID = ... })
like image 37
Mykola Bogdiuk Avatar answered Sep 22 '22 05:09

Mykola Bogdiuk