Sagi1981
Sagi1981

Reputation: 335

Displaying data differntly across viewmodels, without changing model data

Another problem has been bugging me lately, and I am quite sure it is my lacking WPF/MVVM skills that prevents me from seing the obvious. I am sure the solution is a simple one, however, I am unsure how to implement it.

I am developing in WPF/C# and I am using the MVVM designpattern.

For simplicity, I am boiling the question down to it's most basic components.

The scenario:

I have a Model, only containing an integer.

I have a Parent ViewModel, displaying this integer.

I have two child viewmodels, incorparated in the parent viewmodel, both displaying this integer. On one of the viewmodel, I have a Command, incrementing the value of the integer with 1. The value is changed in the model, which implements the INotifyPropertyChanged therefore making the second ViewModel aware of the change, so it can update accordingly.

So far everything works fine.

However, I am interested in a new feature, and I cannot get it to work. Say, that I on my second viewmodel want to display the integer, but I want to transform the way the data is displayed. This should be done, however, without changing the data in the model. Should the data in the model change, the transformed data will change accordingly.

As an example, lets assume that the integer is 5. On the second viewmodel, I want to display the integer + 2, meaning 7. Then the data is changed to 6 from the first viewmodel, meaning that the property on the second viewmodel changes to 8 automatically.

How is this implemented?

A few codepieces, to illustrate what the system looks like so far:

The Model:

public DataModel()
{
    data = new Data();

    data.Value = 2;
}

public Data data { get; set; }

And the data Class:

public class Data :  INotifyPropertyChanged
{
    private int m_Value;
    public int Value
    {
        get { return m_Value; }
        set
        {
            if (m_Value != value)
            {
                m_Value = value;
                OnPropertyChanged("Value");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {

        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
        {
            var e = new PropertyChangedEventArgs(propertyName);
            handler(this, e);
        }
    }

The mainviewmodel

public class MainViewModel : ViewModelBase
{
    readonly DataModel _dataModel;

    public MainViewModel()
    {
        _dataModel = new DataModel();

        ViewModel1 = new 1ViewModel(this);
        ViewModel2 = new 2ViewModel(this);
    }


    public 1ViewModel ViewModel1 { get; set; }

    public 2ViewModel ViewModel2 { get; set; }

    public Data Data
    {
        get { return _dataModel.data; }

    }



}

And here is the way the ChildViewmodels binds themselves to the Data object

public class 1ViewModel : ViewModelBase
{

    private MainViewModel _mainViewModel;

    public 1ViewModel(MainViewModel mainViewModel)
    {
        _mainViewModel = mainViewModel;

    }

    public Data Number
    {
        get { return _mainViewModel.data; }

    }

}

And on the view1, i have bound the Number property like this

<TextBlock  Text="{Binding Path=Number.Value}" />

Again, I want to be able to create a second property on the viewmodel, which displays the transformed data, based on, but without changing the original data, and which updates together with the data being updated. Preferably, it should be a kind of converter-method, which converts the data to the new data.

Hope you are able to help.

Upvotes: 0

Views: 137

Answers (2)

Troels Larsen
Troels Larsen

Reputation: 4631

Use an IValueConverter:

public class AddConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return (int)value + (int)parameter;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return (int)value - (int)parameter;            
    }
}

And in your XAML, add the resource:

And update your binding:

I used a ConverterParameter here, but you can hardcode the value if so desired. Might want to add some checks to your converter as well, as it will throw an exception if the types are not correct.

Upvotes: 0

Aaron McIver
Aaron McIver

Reputation: 24723

The ViewModel should hold the data ready for display but not knowledgeable on the way in which it will be displayed. If you want to change the way in which the data is displayed in your View, for that you would use a Converter. This would allow you to use the same ViewModel for multiple Views and have different appearances.

In addition wrapping a ViewModel inside a ViewModel is not necessarily the way you want to go. A ViewModel generally has an associated View. If you have no view for the ViewModel, treat the data as typical classes and proceed with your single ViewModel.

Upvotes: 1

Related Questions