Monday, June 27, 2016

Automatic calculation of the properties of computable representations of models in .NET

Motivating the example representations of models for WPF UI

Start a discussion and get acquainted with the issues under discussion is offered as an example approach to architecture, user interfaces in WPF.

As you know, one of the main features WPF - bayndingov is a powerful system that allows easy enough to separate the model representation (the model) from the presentation (the View) as such. Typically, a programmer creates XAML to represent, bind properties of elements to the model in the same XAML by bayndingov and, in fact, forget about the View. This is possible because most UI-logic can be realized through the impact on the model and automatically prokinut on the UI by bayndingov. With this approach, the model plays the role of the state of View, as its proxy for a layer that implements the UI-logic. For example, changing the property of the model, we thereby change the corresponding property of the View (or its components). The latter occurs automatically thanks bayndingov system which tracks changes in the model and in View, synchronizing state at both ends as required. One of the ways in which the model can notify observers (whom in this case is baynding) of its change is throwing PropertyChanged event with the name of the changed property as parameter. This event belongs interface INotifyPropertyChanged, which, accordingly, must be implemented in the model.




Consider the idea of ​​a specific example. Let's start with a simple model, which is a kind of Order and contains two properties - Price and Quantity. Both properties are variable, so each must implement the notification of the change. This is done with the following code:

public class Order : INotifyPropertyChanged { private decimal _price; private int _quantity; public decimal Price { { get { return _price; } set { if (value == _price) return; _price = _price = value; OnPropertyChanged(); } } OnPropertyChanged(); } } public int Quantity { { get { return _quantity; } set { if (value == _quantity) return; _quantity = _quantity = value; OnPropertyChanged(); } } OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { var handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); } } } }
 Now let's imagine that we have a View, which represents an instance of the order in the form of two TextBlock'ov that are tied to the price and quantity:

<TextBlock Text="{Binding Price, StringFormat='Price: {0}'}" /> <TextBlock Text="{Binding Quantity, StringFormat='Quantity: {0}'}" />

If our UI-logic will change any of the properties of the model that corresponds to baynding receive notification of a change, and change the text in the tied TextBlock'e. So far, everything is easy.

But now add in the cost of property model, calculated by the obvious formula:

public int Cost { get { return _price * _quantity; } }

Perhaps the one who only gets acquainted with a WPF, has the right to expect that when the fares or the TextBlock, representing the cost, change your text too. Naturally, this does not happen, because there was no rush to the PropertyChanged event for the property Cost. Thus, we come to the problem of implementing the notification about updates computable properties (properties, the value of which depends on the values ​​of other properties).

Possible solutions

In the case of the example considered decision, obviously, very simple. We need to throw PropertyChanged Cost of Price and Quantity setters or change the Cost of the property setters (thereby causing the desired event has raised from Cost). Here is the code for both options:

//Raise Cost PropertyChanged from both Price and Quantity setters.
 public class Order : INotifyPropertyChanged
    {
        private decimal _price;
        private int _quantity;

        public decimal Price
        {
            get { return _price; }
            set
            {
                if (value == _price) return;
                _price = value;
                OnPropertyChanged();
                OnPropertyChanged("Cost");
            }
        }

        public int Quantity
        {
            get { return _quantity; }
            set
            {
                if (value == _quantity) return;
                _quantity = value;
                OnPropertyChanged();
                OnPropertyChanged("Cost");
            }
        }
        public int Cost
        {
            get { return _price * _quantity; }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

//Update Cost from both Price and Quantity setters. public class Order : INotifyPropertyChanged { private decimal _price; private int _quantity; public decimal Price { get { return _price; } set { if (value == _price) return; _price = value; OnPropertyChanged(); Cost = _price * _quantity; } } public int Quantity { get { return _quantity; } set { if (value == _quantity) return; _quantity = value; OnPropertyChanged(); Cost = _price * _quantity; } } public int Cost { get { return _cost; } private set { if (value == _cost) return; _cost = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { var handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); } }
Perhaps the one who only gets acquainted with a WPF, has the right to expect that when the fares or the TextBlock, representing the cost, change your text too. Naturally, this does not happen, because there was no rush to the PropertyChanged event for the property Cost. Thus, we come to the problem of implementing the notification about updates computable properties (properties, the value of which depends on the values ​​of other properties). 

Possible solutions

In the case of the example considered decision, obviously, very simple. 

We need to throw PropertyChanged Cost of Price and Quantity setters or change the Cost of the property setters (thereby causing the desired event has raised from Cost). Here is the code for both options:

No comments:

Post a Comment