Список не обновляется при добавлении или удалении элементов из ObservableCollection

У меня есть приложение типа "Hello World".
A listbox.ItemsSource = Players. Players — это ObservableCollection Player, который реализует INotifyPropertyChanged.

Когда я добавляю элементы в конструктор Players, элементы отображаются нормально. Когда я обновляю существующий элемент, изменения отражаются. Но когда я добавляю или удаляю элементы для ObserveableCollection, список не отражает добавленные/удаленные элементы.

xaml на главной странице:

    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
        <ListBox Name="lstPlayers" ItemsSource="{Binding}" Margin="12,66,13,24" Grid.Row="1">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <!--<StackPanel Background="#FFD1D1D1">-->
                    <Grid Margin="0,0,0,0" Grid.RowSpan="2">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="60"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Grid.Column="0" Text="{Binding Number}" FontSize="48"  />
                        <TextBlock Grid.Column="1" Text="{Binding Name}" FontSize="48" />
                    </Grid>
                    <!--</StackPanel>-->
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <Button Content="Button" Height="95" HorizontalAlignment="Left" Margin="183,350,0,0" Name="button1" VerticalAlignment="Top" Width="260" Click="button1_Click" />
        <Button Content="Button" Height="72" HorizontalAlignment="Left" Margin="198,472,0,0" Name="button3" VerticalAlignment="Top" Width="232" Click="button3_Click" />
    </Grid>

Список связан в коде позади:

  lstPlayers.ItemsSource = plys;

Класс игрока:

using System.ComponentModel;
namespace DatabindList
{
public class TcrPlayer : INotifyPropertyChanged
{


    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    private string _name;
    public string Name
    {
        get { return _name; }
        set
        {

            if (_name != value)
                _name = value;

            NotifyPropertyChanged("Name");

        }
    }
   }
}

Класс игроков:

using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace DatabindList
{

public class TcrPlayers : List<TcrPlayer> 
{
    public ObservableCollection<TcrPlayers> Items { get; private set; }



    public TcrPlayers()
    {
        //these are displayed
        Add(new TcrPlayer { Name = "Christine"});
        Add(new TcrPlayer { Name = "Janet"});
        Add(new TcrPlayer { Name = "Ian"});
    }


    public void AddPlayer()
    {
        //THIS HAS NO EFFECT ON THE LISTBOX
        Add(new TcrPlayer { Name = "Newbie", Number = "99" });

    }


   }
}

Я могу ОБНОВИТЬ существующий элемент в списке, используя код на главной странице с помощью

            var itm = lstPlayers.SelectedItem as TcrPlayer;
            itm.Name = "Fred";

но я не могу отразить какие-либо изменения, внесенные в количество элементов в коллекции Players.


person Ray Brennan    schedule 14.08.2013    source источник
comment
ты пробовал public class TcrPlayers : ObservableCollection<TcrPlayer> ? Насколько я вижу, вы даже не используете свойство Items и добавляете к List<TcrPlayer>   -  person dkozl    schedule 14.08.2013


Ответы (2)


TcrPlayers происходит от List<TcrPlayer> и добавляет элементы к себе. Однако свойство ObservableCollection<TcrPlayer> никак не связано с этим списком. Предполагая, что plys является TcrPlayers, вы вообще не привязываетесь к ObservableCollection — вы привязываетесь к ненаблюдаемому List.

Наследование от ObservableCollection<TcrPlayer> вместо List<TcrPlayer> и удаление неиспользуемого свойства может приблизить вас к тому, чего вы хотите.

Кроме того, вы не видите, что этот шаблон используется очень часто, потому что наследование от класса коллекции обычно не считается очень полезным, если вы не добавляете новую функциональность. Обычно вы просто имеете свойство ObservableCollection<TcrPlayer> родительской модели представления и привязываете к нему ItemsSource списка.

Говоря об этом, вы также устанавливаете ItemsSource дважды — в своем XAML на {Binding}, то есть текущий DataContext, и в коде программной части.

person Matthew Walton    schedule 14.08.2013
comment
Боже! Это кажется таким простым теперь, когда у меня есть ответ, но я потратил последние 4 с лишним часа, пытаясь это выяснить. Большое спасибо :) - person Ray Brennan; 14.08.2013
comment
Без проблем. Я делал это довольно часто, так что это довольно очевидно, если вы сделали это шестьдесят раз! - person Matthew Walton; 15.08.2013

Вы не используете свой ObservableCollection. Вместо этого ваш класс TcrPlayers представляет собой список (производный от List<T>).

Либо получите от ObservableCollection и удалите свою собственность Items, либо используйте Items.Add(..) вместо Add().

E.g.

public class TcrPlayers : ObservableCollection<TcrPlayer> 
{
..

or

public class TcrPlayers
{
    public ObservableCollection<TcrPlayers> Items { get; private set; }

    public TcrPlayers()
    {
        //these are displayed
        Items.Add(new TcrPlayer { Name = "Christine"});
        Items.Add(new TcrPlayer { Name = "Janet"});
        Items.Add(new TcrPlayer { Name = "Ian"});
    }
person SvenG    schedule 14.08.2013
comment
Я могу отметить только один ответ как правильный, и Мэтью получил его первым :/ Спасибо, Свен. - person Ray Brennan; 14.08.2013