【问题标题】:ObservableCollection doesn't get bound to ListBox in codebehindObservableCollection 未绑定到代码隐藏中的 ListBox
【发布时间】:2012-01-27 21:43:42
【问题描述】:

我想在后面的代码中将一个列表框绑定到一个可观察的集合。这是我用于绑定的:

Binding binding = new Binding();
binding.Source = symTable;
substanceList.SetBinding(ListBox.ItemsSourceProperty, binding);

symTable 继承自 ObservableCollection,Count 属性得到适当更新,所以我知道我添加了正确的元素,但列表框没有。我不知道将路径设置为什么,因为在 XAML 中它绑定到整个列表。

注意:将单个项目添加到 ListBox 时,它们会显示出来,因此这不是显示问题。我也试过了:

this.Resources.Add("symTable", symTable);

在窗口构造函数中,然后是这个:

但它说资源无法解析。

我也尝试将其添加为 XAML 中的资源,但它不再起作用: //在窗口的资源中。

<s:SymbolTable x:Key="symTable"/> 
...
<ListBox x:Name="substanceList" ItemsSource="{Binding Source={StaticResource symTable}}"/>

然后在后面的代码中:

symTable = (SymbolTable)this.FindResource("symTable");

有谁知道在代码隐藏或 XAML 中执行此操作的任何其他方式,我认为ElementName 指的是在代码隐藏中定义的对象。

这是 symTable 类定义的一部分:

public class SymbolTable : ObservableCollection<Substance>
{
    Dictionary<string, Substance> symbolTable;
    ...
    public Substance Insert(Substance s)
    {

        if (!symbolTable.ContainsKey(s.Name))
        {
            symbolTable.Add(s.Name, s);
            Items.Add(s);
        }

        return symbolTable[s.Name];
    }

注意好吧,所以我刚刚注意到最奇怪的事情,Items.Add 没有引发 INotifyChanged 事件。我在我的 Insert 方法中使用了 Items.Add,我猜 Items.Add 没有引发 INotifyChanged 事件,因此 ListBox 没有得到更新,但是什么时候 Add 而不是 Items.Add 然后它起作用了。不知道是不是真的这样?

【问题讨论】:

  • 我用 ObservableCollection 试过你的代码,效果很好。也许您的项目不会以某种方式显示在 ListBox 中。检查您的 DataTemplate 是否正确绑定到数据对象的属性,或发布更多代码。
  • @Clemens 当我将 ItemsSouce 直接设置为 symTable 时,会显示项目,添加单个项目也可以。我也试过&lt;ListBox x:Name="substanceList" ItemsSource="{Binding ElementName=symTable, Path=Items}",但没用。
  • 这行不通有两个原因:symTable(我猜)是在后面的代码中声明的,所以没有名为 symTable 的 XAML 元素,这使得 ElementName 分配无用。此外,它没有 Items 属性,这使得 Path 分配无用。您可以使用 x:Key=symTable 将 ObservableCollection 声明为资源,然后绑定 ItemsSource={Binding Source={StaticResource symTable}}
  • @Clemens 如何在后面的代码中使用 symTable 向其中添加项目?这在某种程度上看起来像是一种解决方法,难道没有更简单的方法吗?
  • @Clemens 我也尝试将它添加到构造函数中的资源字典中,我更新了上面的问题,但它仍然没有工作。

标签: wpf binding collections listbox observable


【解决方案1】:

好的,按照您的问题的 cmets,这里是如何在 XAML 中将 SymbolTable 声明为资源以及如何将 ListBox 绑定到它。请注意 XAML 命名空间声明“本地”,它指的是本地命名空间/程序集,在我的测试项目中命名为 ListBindingTest

<Window x:Class="ListBindingTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:ListBindingTest"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:SymbolTable x:Key="symTable"/>
    </Window.Resources>
    <Grid>
        <ListBox ItemsSource="{Binding Source={StaticResource symTable}}"/>
    </Grid>
</Window>

您可以在窗口类后面的代码中访问 SymbolTable 资源,如下所示:

SymbolTable st = (SymbolTable)Resources["symTable"];
st.Add(new Substance());

【讨论】:

  • 好吧,我刚刚注意到最奇怪的事情,Items.Add 没有引发 INotifyChanged 事件。我在我的 Insert 方法中使用了 Items.Add,我猜 Items.Add 没有引发 INotifyChanged 事件,因此 ListBox 没有得到更新,但是什么时候 Add 而不是 Items.Add 然后它起作用了。不知道真的是这样吗?
  • 啊,这也是我刚刚照顾的。只是必须在您的Insert() 方法中使用this.Add()
【解决方案2】:

DisplayMemberPath 需要是 symTable 的公共属性。

【讨论】:

  • @mihajlv 在 C# 中,当您拥有 indexed accessor 时,编译器会为您创建一个 Items 属性,以便可以从其他语言访问该属性。
  • @Bevan 我不确定你指的是什么。索引访问器来自私有字典变量。
  • 我以为你很困惑为什么 Items 属性在没有明确声明的情况下存在。也许是我误会了自己……
【解决方案3】:

您总是可以直接在列表框上设置 ItemSource。

substanceList.ItemsSource = symTable;

【讨论】:

  • 但是当集合更改时,列表框不会更新。
猜你喜欢
  • 2018-09-11
  • 1970-01-01
  • 2012-12-16
  • 1970-01-01
  • 2013-12-31
  • 1970-01-01
  • 2014-09-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多