DataBinding wpf KeyedCollection

时间:2009-06-03 10:06:27

标签: c# wpf data-binding xaml

我是WPF Databinding的初学者,我发现了一种令人困惑的行为。也许有人可以帮助我:

我的xaml代码将列表框绑定到列表:

<ListBox ItemsSource="{Binding Path=Axes}"  SelectedItem="{Binding Path = SelectedAxis}" DisplayMemberPath = "Name" Name="listboxAxes"/>

如果绑定的实际项目是List,则一切都按预期工作。

但是当我改为KeyedCollection时会出现更新问题。调用NotifyPropertychanged(“Axes”)不会整体更新ListBox。

有关于此的任何想法吗?

5 个答案:

答案 0 :(得分:4)

如果Axes正在收集的不是具有它自己的Name属性的类,那么DisplayMemberPath =“Name”属性可能会导致您看不到任何内容。

使用KeyedCollection作为ItemsSource是完全正常的。 ItemsSource属性是ItemsControl.ItemsSource属性。它只需要它实现IEnumerable所必需的任何东西。

KeyedCollection确实实现了IEnumerable,因为它实现了Collection。

以下是使用KeyedCollection的简短示例:

<Grid>
    <DockPanel x:Name="QuickListButtonsStackPanel">
        <Button DockPanel.Dock="Top"
                Content="Load Animals"
                Click="AnimalButtonClick" />
        <Button DockPanel.Dock="Top"
                Content="Load Objects"
                Click="ObjectButtonClick" />

        <TextBlock DockPanel.Dock="Bottom"
                   Background="Azure"
                   Text="{Binding SelectedExample}" />

        <ListBox x:Name="uiListBox"
                 ItemsSource="{Binding Examples}"
                 SelectedItem="{Binding SelectedExample}" />

    </DockPanel>
</Grid>

我们的Window&amp;的代码KeyedCollection:

public partial class Window1 : Window, INotifyPropertyChanged
{
    public Window1()
    {
        InitializeComponent();
        this.DataContext = this;
    }

    public KeyedCollection<char, string> Examples
    {
        get;
        set;
    }

    private string mySelectedExample;
    public string SelectedExample
    {
        get
        { return this.mySelectedExample; }
        set
        {
            this.mySelectedExample = value;
            this.NotifyPropertyChanged("SelectedExample");
        }
    }

    private void AnimalButtonClick(object sender, RoutedEventArgs e)
    {
        Examples = new AlphabetExampleCollection();
        Examples.Add("Ardvark");
        Examples.Add("Bat");
        Examples.Add("Cat");
        Examples.Add("Dingo");
        Examples.Add("Emu");

        NotifyPropertyChanged("Examples");
    }

    private void ObjectButtonClick(object sender, RoutedEventArgs e)
    {
        Examples = new AlphabetExampleCollection();
        Examples.Add("Apple");
        Examples.Add("Ball");
        Examples.Add("Chair");
        Examples.Add("Desk");
        Examples.Add("Eee PC");

        NotifyPropertyChanged("Examples");
    }



    #region INotifyPropertyChanged Members

    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

public class AlphabetExampleCollection : KeyedCollection<char, string>
{
    public AlphabetExampleCollection() : base() { }

    protected override char GetKeyForItem(string item)
    {
        return Char.ToUpper(item[0]);
    }
}

可能发生的另一个问题是,您只是添加/删除集合中的项目,而不是重新设置集合。在上面的示例中,您可以看到我们正在重新设置键控集合。如果我们不这样做,那么只调用NotifyPropertyChanged就不会做任何事情。

让我们再添加两个按钮来演示:

<Button DockPanel.Dock="Top"
        Content="Add Zebra"
        Click="AddZebraClick" />
<Button DockPanel.Dock="Top"
        Content="Add YoYo"
        Click="AddYoYoClick" />

Hanlders:

private void AddZebraClick(object sender, RoutedEventArgs e)
{
    Examples.Add("Zebra");
    NotifyPropertyChanged("Examples");
}

private void AddYoYoClick(object sender, RoutedEventArgs e)
{
    Examples.Add("YoYo");
    NotifyPropertyChanged("Examples");
}

这两个,都不起作用。当您调用NotifyPropertyChanged时,必须实际更改该属性。在这种情况下,它不是。我们修改了它的项目,但Examples集合仍然是同一个集合。为了解决这个问题,我们可以像在第一部分中那样循环收集,或者如果我们可以访问UI,我们可以调用:

uiListBox.Items.Refresh();

我们也可以循环DataSource,我们可以循环ListBox的ItemsSource,或者我们可以清除并重新分配绑定,但只是调用UpdateTarget()不会这样做。

答案 1 :(得分:2)

尝试拨打listboxAxes.Items.Refresh()。 这有时会有所帮助。

答案 2 :(得分:1)

KeyedCollection既未实施INotifyCollectionChanged也未实施INotifyPropertyChanged。要使绑定自动更新,请使用实现这些接口的集合(例如ObservableCollection)。

答案 3 :(得分:0)

答案 4 :(得分:0)

将您的属性公开为IList类型的属性,并将ItemSource绑定到此属性:

public IList MyIListKeyedCollection { get { return myKeyedCollection; } }

并在myKeyedCollection发生变化时调用NotifyPropertyChanged(“MyIListKeyedCollection”)。我认为这应该有用......