tags:

views:

405

answers:

4

Hello. I apologize for the newbie question, but I am struggling with this problem. I have the following TextBlock defined:

<TextBlock Text="{Binding Source={x:Static local:DeviceManager.Instance},
 Path=Player.CurrentArtist}"></TextBlock>

The DeviceManager is a singleton that functions as a facade for other classes. For example, Player is a property of type IPlayer which represents an music-playing application. I would like the TextBlock to display the artist that is currently playing, which is periodically updated in the Player.CurrentArtist property.

Unfortunately, I cannot get the TextBlock to update when the CurrentArtist property updates. Both the DeviceManager and the IPlayer implement INotifyPropertyChanged, but when I step through the application, the DeviceManager does not have an event handler attached to it.

Does anyone have a suggestion for how to update the text block while preserving the singleton-facade?

Here is the code for the INotifyPropertyChanged members in both the DeviceManager and the IPlayer subclass:

public sealed class DeviceManager : INotifyPropertyChanged
{
    // Singleton members omitted

    public IPlayer Player
    {
        get { return player; }
        set
        {
            this.player = value;
            player.PropertyChanged += new PropertyChangedEventHandler(device_PropertyChanged);
        }
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    private void device_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(sender, e);
        }
    }

    #endregion
}

class MediaPlayer : IPlayer
{
    private string artist;
    private string title;

    public event PropertyChangedEventHandler PropertyChanged;

    public void Play(string artist, string title)
    {
        this.artist = artist;
        this.title = title;
        OnPropertyChanged("Player:Song");
    }

    private void OnPropertyChanged(string p)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(p));
        }
    }

    public string CurrentTitle
    {
        get { return title; }
    }

    public string CurrentArtist
    {
        get { return artist; }
    }

}
A: 

How does the UI know when you change the Player property? From that code it does not look like it raises PropertyChanged to me. Can you post a complete working sample of the problem? Otherwise we're forced to just guess.

HTH, Kent

Kent Boogaart
+1  A: 

The problem is that WPF is never notified of the value of the CurrentArtist property changing. You can either implement a private setter for the CurrentArtist property, which will trigger the PropertyChanged event, or trigger a PropertyChanged event for the CurrentArtist property in MediaPlayer.Play().

Andy
A: 

WPF only responds to PropertyChanged if the name you pass in (i.e. right now "Player:Song") is the same as the property you're bound to - change the PropertyChanged to "CurrentArtist" and you'll see it update properly.

Paul Betts
A: 

You are not raising the PropertyChanged event, what you need is:

public sealed class DeviceManager : INotifyPropertyChanged
{
    // Singleton members omitted

    public IPlayer Player
    {
        get { return player; }
        set
        {
            this.player = value;
            OnPropertyChanged(this, new PropertyChangedEventArgs("Player"));
        }
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(sender, e);
        }
    }

    #endregion
}
Nir