虽然在编写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;
我正在获取一个列表,但是当我刷新它们时,它不会自动更新复选框状态。我怀疑我的进一步阅读会解决这个问题。
答案 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
查看商品中的更改
INotifyPropertyChanged
中实施CheckedListItem
界面(每个设置者应调用PropertyChanged(this, new PropertyChangedEventArgs(<property name as string>))
事件)CheckedListItem
派生DependencyObject
,并将Name
,ID
,IsChecked
转换为相关属性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}"