I'm just learning MVVM, and I'm trying to work how to display changes to a calculated property as a result of changes to the values from which it's calculated. All of the solutions I've seen so far seriously violate encapsulation, and I'm wondering whether there's anything better.
Suppose one of the things I need to display is the results of a complex tax calculation. The calculation (and possibly its dependencies) will change from time to time, so I would like to keep it strictly encapsulated.
The solution most often offered here seems to be to get all of the properties on which the tax value depends to invoke PropertyChanged in the ModelView for the property itself and for every property that depends on it. That means that every property needs to know everything that uses or might use it. When my tax rules change in a way that makes the calculation dependent on things it was not previously dependent on, I will need to touch all those new properties that go into my calculation (possibly in other classes, possibly not under my control), to get them to invoke PropertyChanged for the tax value. That completely trashes any hope of encapsulation.
The best solution I can think of is to make the class that does the calculation receive PropertyChanged events, and raise a new PropertyChanged event for the tax value when anything changes that goes into the calculation. That at least preserves encapsulation at class level, but it still breaches method encapsulation: the class shouldn't have to know about how a method does its work.
So, my question is, is there a better way (and if so, what is it)? Or does encapsulation of presentation (MVVM) prevent encapsulation of the business logic? Am I faced with an either/or choice?
The solution most often offered here seems to be to get all of the
properties on which the tax value depends to invoke PropertyChanged in
the ModelView for the property itself and for every property that
depends on it.
No the supporting properties do not need their own change notification unless they are being displayed. But each property will need to call the tax value's OnPropertyChanged("TaxValue") in their setter(s) either directly; or indirectly as per the example below. That way the UI gets updated because a supporting property has changed.
With that said, let us consider an example. One way is to create a method which will do the value calculation. When the ultimate value is set (TaxValue below) it will call OnNotifyPropertyChange. That operation will inform the user of the TaxValue change to the whole world; regardless of what value triggers it (Deduction|Rate|Income):
public class MainpageVM : INotifyPropertyChanged
{
public decimal TaxValue
{
get { return _taxValue; }
set { _taxValue = value; OnPropertyChanged(); } // Using .Net 4.5 caller member method.
}
public decimal Deduction
{
get { return _deduction; }
set { _deduction = value; FigureTax(); }
}
public decimal Rate
{
get { return _rate; }
set { _rate = value; FigureTax(); }
}
public decimal Income
{
get { return _income; }
set { _income = value; FigureTax(); }
}
// Something has changed figure the tax and update the user.
private void FigureTax()
{
TaxValue = (Income - Deduction) * Rate;
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>Raises the PropertyChanged event.</summary>
/// <param name="propertyName">The name of the property that has changed, only needed
/// if called from a different source.</param>
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endif
}
Edit
To use CallerMemberName (and other items) in .Net 4 install the Nuget package:
Microsoft.BCL.
or if not use the standard OnPropetyChanged("TaxValue") instead.
Check out Stephen Cleary's Calculated Properties: https://github.com/StephenCleary/CalculatedProperties
It's very simple and does just this: propagates notifications of dependant properties without polluting the trigger property setter.
Primitive example:
public string Name
{
get { return Property.Get(string.Empty); }
set { Property.Set(value); }
}
public string Greeting => Property.Calculated(() => "Hello, " + Name + "!");
It is incredibly powerful for its size: think Excel-like formula engine for View Model properties.
I used it in several projects both in domain and view model classes, it helped me to eliminate most of imperative control flow (a major source of errors) and make code much more declarative and clear.
The best thing about it is that dependent properties can belong to different view models and dependency graph can change dramatically during runtime and it still just works.
The solution most often offered here seems to be to get all of the properties on which the tax value depends to invoke PropertyChanged in the ModelView for the property itself and for every property that depends on it. ....
Yes, but only for that object: Each property should fire its own property change event in the setter. Additionally the setter should somehow trigger properties that depend on that value on itself. You should not try to trigger updates on other objects proactively: they should listen to this objects PropertyChanged.
The best solution I can think of is to make the class that does the calculation receive PropertyChanged events, and raise a new PropertyChanged event for the tax value when anything changes that goes into the calculation. That at least preserves encapsulation at class level, but it still breaches method encapsulation: the class shouldn't have to know about how a method does its work.
This is indeed the standard way. Each class has the responsibility to monitor the properties that it depends on, and fire property change events for the properties it.
There are probably frameworks that will help to do this for you, but it is worthwhile to know what should happen.
There is an addin called Fody/PropertyChanged that works at compile-time to automatically implement PropertyChanged. It will automatically see what properties in the same class make use of your property and raise all appropriate PropertyChanged events when that one complex tax calculation changes.
You can decompile the compiled code with ILSpy to see what it did and verify that it's raising all appropriate events.
The best solution I can think of is to make the class that does the
calculation receive PropertyChanged events, and raise a new
PropertyChanged event for the tax value when anything changes that
goes into the calculation. That at least preserves encapsulation at
class level, but it still breaches method encapsulation: the class shouldn't have to know about how a method does its work.
I think you're extending the term "encapsulation" to the point of quibbling about syntax. There is no issue here, for instance:
private int _methodXCalls;
public void MethodX() {
Console.WriteLine("MethodX called {0} times", ++_methodXCalls);
}
The field is relevant only within MethodX, but just because the declaration is not syntactically inside MethodX does not mean it breaks method encapsulation.
Likewise, there is no issue with setting up event handlers for each of your properties in the class initialization. As long as it only appears once at initialization, and nothing else is required to "know" that those particular handlers were added, your properties are still logically self-contained. You could probably somehow use attributes on the properties, e.g. [DependsOn(property1, property2)], but this is really just a code readability concern.
Related
I'm not sure what keywords to search for...lost in a sea of Google.
I have a two-way databinding specified between a visual element (slider bar) and a numeric value in my ViewModel. I want to differentiate between when a value change is user-initiated vs ViewModel-based, so that I can selectively trigger an event elsewhere in my application. How can I do this in the code-behind of the XAML file?
Update 2015-02-26: In reply to Amit's question, WHY I need this capability is that I actually have more than one visual element set up for 2-way databinding to the same ViewModel source, so not differentiating leads to an infinite loop (stack overflow) in callbacks to dependent code that itself has the ability update the same values.
Aside - shouldn't there be reputation points for the first time one appropriately ues "stack overflow" on SO?
Your best bet is not to have two different behaviors. You need to fire the same notifications and recalculate the same dependent properties either way. But I've run into cases where, say, sometimes I want to fire off an animation and sometimes I don't, so different behaviors can be necessary.
If you really do need two different behaviors, I would just make two different properties (or a property and a method). Bind one property to the UI, and use the other when you're setting the value programmatically. Give each one the side effects it needs to have.
Not only does this keep things simple, it also means you can write unit tests for both sets of behaviors.
I think the short answer is: not really.
When you bind to a ViewModel property from your XAML element, ultimately the WPF binding system will call the property setter in the ViewModel. Once inside the setter method you have no context as to how you got there. You could possibly check the stack to see where you came from but that would be very brittle code and presumably quite slow as well.
If the property was only being set by either the XAML binding or by the ViewModel, then you could set some kind of Boolean flag in your ViewModel like so:
bool _isBeingSetByVM;
public int Number
{
get { return _number; }
set
{
if (_isBeingSetByVM)
{
// ViewModel has set the property
// Do whatever you need to do...
_isBeingSetByVM = false;
}
if (_number != value)
{
_number = value;
OnPropertyChanged("Number"); // generate PropertyChanged event
}
}
}
int _number;
void SomeMethodInVM()
{
_isBeingSetByVM = true;
Number = 42;
}
But again, this is very brittle code that is hard to maintain. As #Amit says in his comment, the better question might be why you need to do this.
Beeing new at MVVM and WPF, I found myself writing tons of code almost identical in my ViewModel to expose properties and then bind on my WPF controls. Something like this:
private Vendedores _vendedorsel;
public Vendedores VendedorSel
{
get
{
return _vendedorsel;
}
set
{
this._vendedorsel = value;
OnPropertyChanged("VendedorSel");
}
}
Is there a better way to do this, without having so much similar code? maybe something that involves inheritance? Thank you.
You can trim this down a little by using CallerMemberName in your base method, which also make refactoring easier if you ever rename the property:
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChangedEventArgs ea = new PropertyChangedEventArgs(propertyName);
if (PropertyChanged != null)
PropertyChanged(this, ea);
}
This cuts your property code down to:
public Vendedores VendedorSel
{
get
{
return _vendedorsel;
}
set
{
this._vendedorsel = value;
OnPropertyChanged();
}
}
You can get similar gains by using frameworks as mentioned by Geek's answer but still need some amount of the boilerplate in most cases. Aspect oriented programming can be used to inject all this stuff for you onto even auto-properties but that can also be a lot to take on if you're not doing anything else with AOP.
Usually the best thing to make this less painful is some good snippets to generate the boilerplate for you.
I Found an excelent answer to this problem in this great Blog.
I Couldn't understand why I need to fire OnPropertyChanged from every property on every setter and why I can't use an auto-implemented property like this on my ViewModel:
public Vendedores VendedorSel {get; set;}
And the point show in the blog above is that in 95% of cases you can!!!
Why?: Because The only reason to fire OnPropertyChanged is if the property is modify OUTSIDE the scope of the view and to inform to it
"hey! this property change! please update yourself"
But in the majority on cases the property is only Modify within the view! in this case is OnPropertyChange is not need!!
Even more! I could even set a default value for the property on the ViewModel Contructor and still don't need to fire OnPropertyChanged because the contructor is executed BEFORE the binding is made. This whille drastically reduce my code of repetitive unneeded manual defined properties! So Thanks to anybody!
In WPF, I have a property with only a get{}. The value is coming from the return of method. NotifyPropertyChanged is often used within a property set{}. It can then notify the UI and the updated value is displayed. But with a get{} only, there isn't a way of detecting if a new or different value is available since you have to execute the method to check.
Is there some way to update the UI without having to keep a local value that contains the last value from the method, in which case a compare would need to be done?
But with a get{} only, there isn't a way of detecting if a new or different value is available since you have to execute the method to check.
The problem boils down to this: What is changing the property? The method that changes the property should call your NotifyPropertyChanged with the name of the property, which will, in turn, cause WPF to refetch the value and update the user interface.
WPF doesn't care where the PropertyChanged event gets raised - it just listens for it, and refreshes the binding as needed.
Edit in response to comment:
It sounds like this may be the result of performing some operation upon your Model class. In this case, it's common that you know that one or more properties may change, but not necessarily which ones. If your Model implements INotifyPropertyChanged, you can subscribe to that and "bubble up" the notifications to the UI via your NotifyPropertyChanged method. If it does not, however, there is another option.
If you know that one or more properties may change, you can raise a PropertyChanged event with string.Empty as the PropertyName in the EventArgs. This will cause all bound properties to get refreshed by WPF. This is likely just a matter of putting something like this in your code:
this.Model.DoSomething(); // This will change 1+ properties
this.NotifyPropertyChanged(string.Empty); // Refresh our entire UI
I wouldn't recommend doing this everywhere, however, as it does add overhead - but it's often the cleanest solution if you don't know which properties will change when you perform an operation.
Yes. Where you change the source data you would need to fire the INotify on the property. Here is an example.
private int _myvalue = 3;
public bool MyProperty
{
get { return IsAProperty(); }
}
public bool IsAProperty()
{
return _myvalue + 1 == 4;
}
public void SetValue(int value)
{
_myvalue = value;
NotifyPropertyChanged(MyProperty);
}
I have a situation where I have a couple of variables who's values depend on each other like this:
A is a function of B and C
B is a function of A and C
C is a function of A and B
Either value can change on the UI. I'm doing the calculation and change notification like this:
private string _valA;
private string _valB;
private string _valC;
public string ValA
{
get { return _valA; }
set
{
if (_valA != value)
{
_valA = value;
RecalculateValues("ValA"); //Here ValB and ValC are calculated
OnPropertyChanged("ValA");
}
}
}
public string ValB
{
get { return _valB; }
set
{
if (_valB != value)
{
_valB = value;
RecalculateValues("ValB"); //Here ValA and ValC are calculated
OnPropertyChanged("ValB");
}
}
}
(...)
private void RecalculateValues(string PropName)
{
if (PropName == "ValA")
{
_valB = TotalValue * _valA;
OnPropertyChanged("ValB");
_valC = something * _valA
OnPropertyChanged("ValC");
}
else
(...)
}
I'm calling the calculation method on the setter of the changed variable, calculating the values for _valB, _valC (for example) and then calling PropertyChanged for these ones.
I do it like this because of the dependencies between the variables, like this i can control which variable gets calculated with the correct values. I also thought about triggering the PropertyChanged for the other variables and perform the calculation on the getter of the variables but i would have to know which property changed before and use that value...not sure if it's the best/simplest solution.
Is this a good way to do this? I don't like the idea of performing this on the setter block, but at the time I can't see any better way to do it.do you see any other (better or cleaner solution)?
Another issue I have is using IdataErrorInfo for validation/presenting error info to the UI.The thing is the this[columnName] indexer gets called at the end of the setter and I needed to validate the values before the calculation, so that if the value inputted is not valid the calculation would not happen.I'm seriously considering abandoning IDataErrorInfo and simply calling my validation method before the calculation(s) occurs. Is there any way to explicitly calling it or right after the value attribution?
NOTE: ValidationRules are not an option because I need to call validation logic on another object from my ViewModel.
Its alright to call your Validation and Calculation in Setter, as long as it does not block the thread and goes into heavy cpu intensive calculations. If you have simple 5 to 10 math based statements without involving complex loops, its alright.
For databinding and WPF, this is the only way, However there is one more implementation called IEditableObject which has BeginEdit, CancelEdit and EndEdit, where you can do your calculation and validation on "EndEdit" function.
In BeginEdit, you can save your all values in temp storage, in CancelEdit you can bring back all values from temp and fire PropertyChaged event for all values those were modified and in EndEdit, you can finally update all variables and fire PropertyChanged for all those are updated.
IEditableObject will be best for performance wise, but it may not display new values until it was cancelled or ended, however to display instantly the only way to do is the way you are doing it.
In case of heavy cpu usage, you can invoke another thread to do calculation and set variables and at the end you can fire PropertyChanged, but yes technicaly you are just doing same thing while setting value in setter but asynchronously.
Since you can evoke NotifyPropertyChanged from anywhere in the class, one way to simplify this is to have your Calculate method fire the NotifyPropertyChanged for all three variables. I use this trick when I have complex calculations with multi-dependencies. Sometimes you'll still want to fire the event in the Setter: in that case I use a flag field to disable the event when I am updating the property from within the Calculations so that the event is not fired twice.
In C# what is the advantage of
public class blah
{
public event EventHandler Blahevent;
}
versus
public class blah
{
private event EventHandler blahevent;
public event EventHandler Blahevent
{
add
{
blahevent+=value;
}
remove
{
blahevent-=value
}
}
}
or vice versa.
does the first one open you up to blahinstance.Blahevent = null, or blahinstance.Blahevent(obj,even)
There is no advantage to explicit implementation of the add/remove methods unless you want to do something different. Possible reasons:
Perhaps take control of the event backing code yourself (to directly link to some other event rather than going though a pointless cascade for example)
do something else in addition on add or remove
Change security demands on the add or remove
expose the underlying delegate
What the default implementation does is maintain a private hidden delegate field which is replaced each time a delegate is added or removed. For most cases there is no need to do any of the above but the flexibility is there.
The second one has the option of controlling exactly what happens when the specified event is subscribed to or unsubscribed from if there is specific logic that needs to run in addition to adding or removing the pointer.
You can exclude the delegate from serialization by using the [field: NonSerialized()] attribute on the private field.
You can place a breakpoint on the latter for debugging purposes. Sometimes this can be really useful (although after debugging I switch it back to the former).