Vale
Vale

Reputation: 45

WPF ListBox not updating value of bound items when the items change

In the application there is a Listbox bound to an ObservableCollection, then the selected item is bound itself to some labels: when a property of the item is changed in the label the actual object (in this case Multimedia) is updated (as I debugged) but then the listbox doesn't update the displayed value.

The Multimedia class implements INotifyPropertyChanged but I'm not sure if I am using it correctly.

Everything else is working without any problem (the add button adds a new element to the list and it is displayed as it should).

I looked around on different forums and also on stackoverflow and tried different variants but still the property, when updated, it is not updated in the ListBox.

This is the XMAL:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="135" />
        <RowDefinition Height="*" />
        <RowDefinition Height="45" />
    </Grid.RowDefinitions>
    <ListBox Name="mediaListBox"  ItemsSource="{Binding Path=MyData}" Grid.Row="0"/>
    <Grid Grid.Row="1"  DataContext="{Binding ElementName=mediaListBox, Path=SelectedItem}">

        ...

        <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Path=Title}" />
        <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Path=Artist}" />
        <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Path=Genre}" />
        <TextBox Grid.Row="3" Grid.Column="1" Text="{Binding Path=Type}" />
    </Grid>
    <Button Name="cmdAddMedia" Grid.Row="1" Click="cmdAddMedia_Click" Height="45" Margin="0,0,0,2" Grid.RowSpan="2" VerticalAlignment="Bottom">Add Item</Button>
</Grid>

Then here there is the C# code of the main window:

public partial class MainWindow : Window
{
    public MultiMediaList MyData { get; set; }
    public void AddStuff()
    {
        MyData.Add(new Multimedia() { Title = "My Way", Artist = "Calvin Harris", Genre = "Pop", Type = Multimedia.MediaType.CD });
        MyData.Add(new Multimedia() { Title = "Inglorious Bastards", Artist = "Quentin Tarantino", Genre = "Violence", Type = Multimedia.MediaType.DVD });
    }
    public MainWindow()
    {
        MyData = new MultiMediaList();
        AddStuff();
        InitializeComponent();
        DataContext = this;            
    }
...
}

And finally the Multimedia class and the MultiMediaList class:

public class Multimedia : INotifyPropertyChanged
{
    public enum MediaType { CD, DVD };

    private string _title;
    private string _artist;
    private string _genre;
    private MediaType _type;

    public string Title
    {
        get { return _title; }
        set
        {
            _title = value;
            NotifyPropertyChanged("Title");
        }
    }
    ...
    public override string ToString()
    {
        return _title + " - " + _artist + " [" + _genre + "] - " + getTypeString();
    }

    private string getTypeString()
    {
       if(Type == MediaType.CD) { return "CD"; }
        else { return "DVD"; }
    }

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

MultimediaList is just an empty class inheriting from ObservableCollection

public class MultiMediaList: ObservableCollection<Multimedia>
{

}

If you need I can also upload the full code

Hope you can help me and tell me what I am doing wrong.

Upvotes: 2

Views: 1587

Answers (1)

Clemens
Clemens

Reputation: 128145

Apparently you are expecting that the ListBox automagically calls the Multimedia object's ToString() method whenever one if its properties changes. That's not the case.

Instead of relying on ToString, declare a proper ItemTemplate for the ListBox:

<ListBox Name="mediaListBox" ItemsSource="{Binding MyData}" Grid.Row="0">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock>
                <Run Text="{Binding Title}"/>
                <Run Text="-"/>
                <Run Text="{Binding Artist}"/>
                <Run Text="["/><Run Text="{Binding Genre}"/><Run Text="]"/>
                <Run Text="{Binding Type}"/>
            </TextBlock>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

The TextBlock might be written shorter:

<TextBlock>
    <Run Text="{Binding Title}"/> - <Run Text="{Binding Artist}"/> [<Run Text="{Binding Genre}"/>] <Run Text="{Binding Type}"/>
</TextBlock>

Upvotes: 2

Related Questions