【问题标题】:DataBinding wpf KeyedCollection数据绑定 wpf KeyedCollection
【发布时间】:2010-10-30 22:42:43
【问题描述】:

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

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

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

如果绑定到的实际项目是一个列表,那么一切都会按预期工作。

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

对此有什么想法吗?

【问题讨论】:

  • 您需要将 XAML 代码标记为代码,否则它不会出现在您的问题中。

标签: c# wpf data-binding xaml


【解决方案1】:

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

public IList MyIListKeyedCollection { get { return myKeyedCollection; } }

并在 myKeyedCollection 更改时调用 NotifyPropertyChanged("MyIListKeyedCollection")。我认为这应该可行...

【讨论】:

    【解决方案2】:

    如果 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 & 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" />
    

    还有汉德尔人:

    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() 不会这样做。

    【讨论】:

      【解决方案3】:
      【解决方案4】:

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

      【讨论】:

      • 这不是关于 KeyCollection 的元素...而是关于一个全新的 KeyCollection 对象。它的更改由 NotifyPropertyChanged(..) 事件正确通知。
      【解决方案5】:

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

      【讨论】:

      • 这可能会奏效。但是我们不想添加代码。它应该只在默认绑定机制下工作。
      • 我没有任何绑定到 KeyedCollection 的经验。所以我希望其他人能够帮助你。
      猜你喜欢
      • 2017-01-10
      • 1970-01-01
      • 1970-01-01
      • 2015-05-24
      • 2015-06-23
      • 2012-12-28
      • 2015-11-23
      • 2011-01-01
      • 2010-11-04
      相关资源
      最近更新 更多