How to Implement a ListBox of Checkboxes in WPF?

后端 未结 5 1275
南笙
南笙 2021-02-05 06:23

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

Despite pop

相关标签:
5条回答
  • 2021-02-05 07:05

    change your binding to

     <ListBox ItemsSource="{Binding Path=TopicList}"
    
    0 讨论(0)
  • 2021-02-05 07:12

    Others have already made useful suggestions (use an observable collection to get list-change notification, make the collection a property rather than a field). Here are two they haven't:

    1) Whenever you're having a problem with data binding, look in the Output window to make sure that you're not getting any binding errors. You can spend a lot of time trying to fix the wrong problem if you don't do this.

    2) Understand the role change notification plays in binding. Changes in your data source can't and won't get propagated to the UI unless the data source implements change notification. There are two ways to do this for normal properties: make the data source derive from DependencyObject and make the bound property a dependency property, or make the data source implement INotifyPropertyChanged and raise the PropertyChanged event when the property's value changes. When binding an ItemsControl to a collection, use a collection class that implements INotifyCollectionChanged (like ObservableCollection<T>), so that changes to the contents and order of the collection will get propagated to the bound control. (Note that if you want changes to the items in the collection to get propagated to the bound controls, those items need to implement change notification too.)

    0 讨论(0)
  • 2021-02-05 07:17

    First you dont need a HeirarchicalDataTemplate for this. Just regular DataTemplate as Aaron has given is enough. Then you need to instantiate the TopicList ObservableCollection somewhere inside the constructor of the class. which makes the ObservableCollection alive even before you add data in to it And binding system knows the collection. Then when you add each and every Topic/CheckedListItem it will automatically shows up in the UI.

    TopicList = new ObservableCollection<CheckedListItem>(); //This should happen only once
    
    private void InitializeTopicList( MyDataContext context )
    {
        TopicList.Clear();
    
        foreach ( Topic topic in topicList )
        {
            CheckedListItem item = new CheckedListItem();
            item.Name = topic.DisplayName;
            item.ID = topic.ID;
            TopicList.Add( item );
        }
    }
    
    0 讨论(0)
  • 2021-02-05 07:21

    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 = ... })
    0 讨论(0)
  • 2021-02-05 07:23

    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>
    
    0 讨论(0)
提交回复
热议问题