Forcing Reevaluation on ICommand.CanExecute - c#

In WPF XAML, I've got a Button's Command property working with an implementation of a class implementing ICommand.
In this implementation, I don't have my CanExecuteChanged event wired up to use CommandManager.RequerySuggested - I want to have control over when CanExecute is called, and using this calls it way more often than necessary.
The only other way I can get ICommand.CanExecute to re-evaluate is to use something like:
public void InvokeCanExecute()
{
CanExecuteChanged.Invoke(this, new EventArgs());
}
In my class implementing the ICommand.
This seems really nasty - am I missing something obvious? I've tried invoking the re-evaluation using PropertyChanged but that doesn't seem to work.

It's true that - if you don't want to use CommandManager.RequerySuggested, which indeed might call CanExecute more often than necessary - you need to explicitly invoke your own InvokeCanExecute method in order to force the command to re-evaluate its CanExecute condition.
However, in most cases the CanExecute condition will depend on public (bindable) properties, meaning properties that raise the PropertyChanged event to indicate that their value has changed - it is possible to hook into this event, in order to automatically call InvokeCanExecute whenever one of the properties the command depends on has changed. For an example of how to implement such a command, see this guy's blog post (if I'm not mistaken, this approach is implemented e.g. as part of the MVVM Light toolkit).
Instantiating a command using this approach would look somewhat like the following:
SaveCommand = new RelayCommand(() => { /* do some stuff; */ },
() => !string.IsNullOrEmpty(Name),
this, () => Name);
Since the command's CanExecute condition (which checks whether Name is empty) depends on the Name property, it needs to be re-evaluated whenever Name's content changes. You simply pass a reference to the Name property to the command's constructor, and InvokeCanExecute will automatically be called whenever the value of Name changes.
In theory, it is possible to go one step further and let the command itself check on which properties it depends - if you're interested in this approach, check out
one of my blog articles, but note that this one heavily depends on reflection so it always depends on the detailed use-case whether this approach is feasible or not. A sample implementation of this solution is included in the MVVMbasics framework (disclaimer: published by me). In this case, you could reduce the command initialization code to:
SaveCommand = CreateRelayCommand(() => { /* do some stuff; */ },
() => !string.IsNullOrEmpty(Name));

No, you are not really missing anything. Here's a similar question that recommends the same approach you're taking: What is the actual task of CanExecuteChanged and CommandManager.RequerySuggested?.
You can make your method a little bit more robust though:
public void InvokeCanExecute()
{
var handler = CanExecuteChanged;
if (handler != null)
{
handler(this, new EventArgs());
}
}

Related

MVVM update of calculated properties

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.

Can I depend on event handlers being invoked in order of registration?

In the current version of the .NET framework, and under normal circumstances (i.e. without intentionally modifying the invocation list), are handlers for an event always invoked in the order in which they are registered? This would be consistent with the documented behavior of multicast delegates, with which events are implemented.
The accepted answer to this question says that invoking handlers in the order of their registration is an implementation detail that may change in some future version of the framework. I believe such a change by Microsoft is unlikely, therefore I am confining my question to the current version of the .NET framework. A comment on that same answer says that it is possible to register handlers such that they are not invoked in their registration order. If this is true then please demonstrate code that results in this out-of-order execution. Please do not include code which intentionally modifies the invocation list. What I am after here is whether or not I can depend on event handler invocation occurring in same order as registration in all current versions of the .NET framework.
You cannot be sure that an event will always be executed in a particular order. The definition of the event can always do whatever it wants, and the implementation of that event is not a part of the public API.
By default, events will use a single multicast delegate as the backing store for an event, but it is straightforward enough to use your own implementation instead. There is no way to tell (beyond looking at the source code) whether or not an event has a custom implementation or not.
One way of implementing an event to not have the described order would be:
public class Foo
{
private Stack<Action> stack = new Stack<Action>();
public event Action MyEvent
{
add
{
stack.Push(value);
}
remove { throw new NotImplementedException(); }
}
internal void OnMyEvent()
{
foreach (var action in stack)
action();
}
}
While most of the events in framework classes won't use a definition like this; most will use a multicast delegate, the only way to know is to look at the source code; you can't tell from, for example, looking at the documentation, whether an event is implemented like this or like:
public class Foo2
{
public event Action MyEvent;
}
That depends on how the event is implemented.
Ordinary (field-like) events store all of their handlers in a single multicast delegate.
Multicast delegates invoke their handlers in insertion order.
Other events are free to store their handlers in some other order. However, most non-standard implementations still use multicast delegates under the covers, stored in various ways (eg, EventHandlerList)

How to notify UI of change with readonly property?

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);
}

RelayCommand RaiseCanExecuteChanged() fails

I am using a couple of Buttons bound to RelayCommands initialized with CanExecute delegates.
RelayCommand DeleteCommand;
bool CanDelete()
{
return BoolProp1 && BoolProp2;
}
...
DeleteCommand = new RelayCommand(Delete, CanDelete);
BoolProp1 and BoolProp2 are regular properties with setters correctly raising PropertyChanged, but as we all know, this is not enough to make SL reevaluate CanExecute on commands. That's why i also call Delete.RaiseCanExecuteChanged() in both setters.
All this works fine (buttons are disabled and enabled properly) up to some point, where is all stops. At that point, calling Delete.RaiseCanExecuteChanged() no longer fires my breakpoints in CanDelete() and buttons forever stay the way they were.
I spend 2 hours trying to isolate the exact cause with no effect. I suspect multiple RaiseCanExecuteChanged() calls during single "binding iteration" somehow break the mechanism.
Any hints? I'm already considering using an additional IsExecutable field refreshed through INotifyPropertyChanged...
UPDATE
RelayCommand is actually GalaSoft.MvvmLight.Command.RelayCommand from MVVM Light Toolkit. ILSpy shows a pretty trivial implementation of ICommand:
public bool CanExecute(object parameter)
{
return this._canExecute == null || this._canExecute.Invoke();
}
public void RaiseCanExecuteChanged()
{
EventHandler canExecuteChanged = this.CanExecuteChanged;
if (canExecuteChanged != null)
{
canExecuteChanged.Invoke(this, EventArgs.Empty);
}
}
with _canExecute being a Func<bool> set once to the value passed to constructor.
I am still working to minimally reproduce the issue.
UPDATE
See my answer.
PEBKAC. My framework in certain cases ran the code
DeleteCommand = new RelayCommand(Delete, CanDelete);
more then once, overwriting commands that were actually bound to view with new instances.
If somebody has this problem - make sure you're calling RelayCommand.RaiseCanExecuteChanged() on the same instance that the view is bound to.
For anyone else who faced the same issue and the accepted answer didn't help me (and for my own record, as I spent a few hours today with it).
If you're using MVVM Light in a VSTO add-in, make sure that the Office application gets a chance to process its own messages to get this to work. For example, in my case I had my Ribbon buttons listening to CanExecuteChanged of underlying VM's command objects, which would not fire no matter what I did. After spending a few hours, I realized that I had to let Office application take a breath and process incoming message to allow CanExecuteChanged to be caught by the add-in. What I then did was to hand over my RaiseCanExecuteChanged function to DispatcherHelper to let it fire asynchronously. It was only then that my Ribbon buttons started reacting to CanExecuteChanged events. Something like this:
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
doc.Activate();
ResetVariablesCommand.RaiseCanExecuteChanged();
});

C# Event Subscription

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).

Categories

Resources