Real World
Real World

Reputation: 1719

DataBinding to Property of a property of a singleton

I would like a text field in my xaml to be bound to a property PlayerData.Instance.data.MyXP The class structure is like this

class PlayerData
{
    public static PlayerData Instance = new PlayerData();

    public UserData data {get;set;}
}

class UserData
{
    public int MyXP {get;set;}
}

Can someone explain how (if at all) I can do this. I have tried multiple methods from questions on SO and not found any that were successful. The biggest problem I have is that PlayerData.Instance.data is assigned AFTER the UI is created so I need some kind of notify event on UserData maybe but also on MyXP as I want the UI to update when the xp changes.

Upvotes: 1

Views: 1321

Answers (2)

Romasz
Romasz

Reputation: 29790

You need to implement INotifyPropertyChanged and set DataContext of the TextBlock to your instance:

class PlayerData
{
    public static PlayerData Instance = new PlayerData();

    private UserData data = new UserData();
    public UserData Data
    {
        get { return data; }
        set { data = value; }
    }
}

class UserData : INotifyPropertyChanged
{
    private int myXP = 0;
    public int MyXP 
    { 
        get { return myXP; }
        set
        {
            myXP = value;
            RaiseProperty("MyXP");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaiseProperty(string property = null)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(property));
    }
}

In XAML you can do it like this:

<TextBlock Name="myExp" Text="{Binding Data.MyXP}" Grid.Row="2"/>

And to make it work you need to set the DataContext of the TextBlock to your instance:

myExp.DataContext = PlayerData.Instance;

Then you can freely chenge your XP and you should see it it the UI:

PlayerData.Instance.Data.MyXP = 1000;

You can also make your PlayerData : INotifyPropertyChanged in case you have other data bound somewhere. Hopefully this example will show you how it works.

Upvotes: 1

Tony Vitabile
Tony Vitabile

Reputation: 8614

Usually, when you use a singleton, each object that uses it gets a copy of the Instance property. You could create a property on your View Model object that holds that reference and then you would bind to that property. For example:

public class MyViewModel : ViewModelBase {

    public PlayerData PlayerData {
        get { return iPlayerData; }
        set { 
            iPlayerData = value;
            OnPropertyChanged( "PlayerData" );
        }
    }
    private PlayerData iPlayerData;

    // Other properties & code
}

Then, in your XAML, assuming you've bound the Window object's DataContext property to the View Model object already, you would use something like this:

<TextBlock Text="{Binding Path=PlayerData.data.MyXP}" />

You may also need to specify an object that implements the IValueConverter interface to format the int MyXP property properly.

(Note that your code, as shown, is not a valid implementation of the singleton pattern if you have a multi-threading environment. See this article and look at the section title "IVth way of implementing Singleton Pattern in C#: Multithreaded Singleton Pattern" if your code is multi-threaded).

Upvotes: 5

Related Questions