如何在WPF中实现Checkbox的ListBox?

时间:2010-12-24 16:25:21

标签: wpf listbox checkbox

虽然在编写Winforms应用程序方面有些经验,但WPF的“模糊性”在最佳实践和设计模式方面仍然无法实现。

尽管在运行时填充了我的列表,但我的列表框显示为空。

我遵循this helpful article的简单指示无效。我怀疑我错过了某种DataBind()方法,我告诉列表框我已经修改了基础列表。

在我的MainWindow.xaml中,我有:

    <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>

在我的代码隐藏中,我有:

    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 );
        }
    }

通过追踪,我知道正在填充四个项目。

修改

我已将TopicList更改为ObservableCollection。它仍然无效。

    public ObservableCollection<CheckedListItem> TopicList;

编辑#2

我做了两个有用的修改:

在.xaml文件中:

ListBox ItemsSource="{Binding}"

在填充列表后的源代码中:

listTopics.DataContext = TopicList;

我正在获取一个列表,但是当我刷新它们时,它不会自动更新复选框状态。我怀疑我的进一步阅读会解决这个问题。

5 个答案:

答案 0 :(得分:8)

假设TopicList不是ObservableCollection<T>,因此当您添加项目时,不会触发更改INotifyCollection以告知绑定引擎更新该值。

将您的TopicList更改为ObservableCollection<T>,以解决当前问题。您也可以提前填充List<T>,然后绑定将通过OneWay工作;但是ObservableCollection<T>是一种更强大的方法。

修改

您的TopicList需要是属性而不是成员变量;绑定需要属性。 需要成为DependencyProperty

编辑2:

修改您的ItemTemplate,因为它不需要是HierarchicalDataTemplate

   <ListBox.ItemTemplate>
     <DataTemplate>
       <StackPanel>
         <CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}"/>
       </StackPanel>
     </DataTemplate>
   </ListBox.ItemTemplate>

答案 1 :(得分:5)

使用ObservableCollection<Topic>代替List<Topic>

修改

它实现了INotifyCollectionChanged接口,让WPF知道你何时添加/删除/修改项目

修改2

由于您在代码中设置TopicList,它应该是依赖属性,而不是公共字段

    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));

编辑3

查看商品中的更改

  1. INotifyPropertyChanged中实施CheckedListItem界面(每个设置者应调用PropertyChanged(this, new PropertyChangedEventArgs(<property name as string>))事件)
  2. 或从CheckedListItem派生DependencyObject,并将NameIDIsChecked转换为相关属性
  3. 或完全更新它们(topicList[0] = new CheckedListItem() { Name = ..., ID = ... }

答案 2 :(得分:3)

首先,你不需要HeirarchicalDataTemplate。正如Aaron给出的常规DataTemplate就足够了。 然后,您需要在类的构造函数中的某处实例化TopicList ObservableCollection。这甚至在你向它添加数据之前使ObservableCollection还活着并且绑定系统知道集合。然后,当您添加每个Topic / CheckedListItem时,它将自动显示在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 );
    }
}

答案 3 :(得分:3)

其他人已经提出了有用的建议(使用可观察的集合来获取列表更改通知,使集合成为属性而不是字段)。这是他们没有的两个:

1)每当您遇到数据绑定问题时,请查看“输出”窗口以确保您没有收到任何绑定错误。如果你不这样做,你可以花很多时间来解决错误的问题。

2)了解角色更改通知在绑定中的作用。除非数据源实现更改通知,否则数据源中的更改不会也不会传播到UI。对于普通属性,有两种方法可以做到这一点:使数据源派生自DependencyObject并使绑定属性成为依赖属性,或者使数据源实现INotifyPropertyChanged并引发PropertyChanged财产价值变化时的事件。将ItemsControl绑定到集合时,请使用实现INotifyCollectionChanged的集合类(如ObservableCollection<T>),以便对集合的内容和顺序的更改将传播到绑定控件。 (请注意,如果您希望更改集合中 集合中的项目以传播到绑定控件,那么这些项目也需要实现更改通知。)

答案 4 :(得分:0)

将您的绑定更改为

 <ListBox ItemsSource="{Binding Path=TopicList}"