Custom Command update CanExecute - wpf

I have to use this Command in a WPF application (i dont like it really but if i have to -> i have to ):
http://wpftutorial.net/DelegateCommand.html
But the main problem I have here is that I don t want to have in nearly every line of my code a call to the
RaiseCanExecuteChanged()
method. So what could I do to do that auto like RoutedUICommand does.
I have a lot of databindings and as example if Foo.FooProp != null Command can execute. But I want as less code as possible and so I would have to register events everywhere or update commands all over my application....

When I use a DelegateCommand, I just manually raise the CanExecuteChanged in the PropertyChange event whenever a property the command relies on changes.
Here's an example I did a few days ago where the CanExecute was based off the IsLoading and IsValid properties:
public MyViewModel()
{
this.PropertyChanged += MyViewModel_PropertyChanged;
}
void MyViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "IsLoading":
case "IsValid":
((DelegateCommand)MyCommand).RaiseCanExecuteChanged();
break;
}
}
public ICommand MyCommand
{
get
{
if (_myCommand == null)
_myCommand = new DelegateCommand(Run, CanRun);
return _myCommand;
}
}
public bool CanRun()
{
return this.IsValid && !IsLoading;
}
I find this keeps the logic easy to follow and maintain, and it only checks the CanExecuteChanged() method when the relevant properties change.

You could implement a form of DelegateCommand which invokes the delegates added to CanExecuteChanged everytime there is a change of possible consequence in the UI. This example uses CommandManager.RequerySuggested.
public class AutoDelegateCommand : DelegateCommand, ICommand
{
public AutoDelegateCommand(Action<object> execute)
: base(execute)
{
}
public AutoDelegateCommand(Action<object> execute, Predicate<object> canExecute)
: base(execute, canExecute)
{
}
event EventHandler ICommand.CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
I think I've seen an example like this before, perhaps in the MVVMLight toolkit?

Related

Add, rename, remove item in treeview with MVVM WPF

I refer excellent tutorial of Josh Smith to work with treeview.
https://www.codeproject.com/Articles/26288/Simplifying-the-WPF-TreeView-by-Using-the-ViewMode
I try to modified with this code to add, remove, rename item to this treeview but I don't know why it not update
Rename item command
#region RenameCommand
/// <summary>
/// Returns the command used to execute a search in the family tree.
/// </summary>
public ICommand RenameCommand
{
get { return _renameCommand; }
}
private class RenameFamilyTreeCommand : ICommand
{
readonly FamilyTreeViewModel _familyTree;
public RenameFamilyTreeCommand(FamilyTreeViewModel familyTree)
{
_familyTree = familyTree;
}
public bool CanExecute(object parameter)
{
return true;
}
event EventHandler ICommand.CanExecuteChanged
{
// I intentionally left these empty because
// this command never raises the event, and
// not using the WeakEvent pattern here can
// cause memory leaks. WeakEvent pattern is
// not simple to implement, so why bother.
add { }
remove { }
}
public void Execute(object parameter)
{
//MessageBox.Show("Rename command");
_familyTree._rootPerson.Children[0].Children[0].Header = "Hello";
if (_familyTree._rootPerson.Children[0] == null)
return;
// Ensure that this person is in view.
if (_familyTree._rootPerson.Children[0].Parent != null)
_familyTree._rootPerson.Children[0].Parent.IsExpanded = true;
_familyTree._rootPerson.Children[0].IsSelected = true;
}
}
#endregion // RenameCommand
Add item command
#region AddCommand
/// <summary>
/// Returns the command used to execute a search in the family tree.
/// </summary>
public ICommand AddCommand
{
get { return _addCommand; }
}
private class AddFamilyTreeCommand : ICommand
{
public FamilyTreeViewModel _familyTree;
public AddFamilyTreeCommand(FamilyTreeViewModel familyTree)
{
_familyTree = familyTree;
}
public bool CanExecute(object parameter)
{
return true;
}
event EventHandler ICommand.CanExecuteChanged
{
// I intentionally left these empty because
// this command never raises the event, and
// not using the WeakEvent pattern here can
// cause memory leaks. WeakEvent pattern is
// not simple to implement, so why bother.
add { }
remove { }
}
public void Execute(object parameter)
{
Person newPerson = new Person();
newPerson.Header = "New Person";
newPerson.Name = "1.1.1.75";
PersonViewModel newPersonViewModel = new PersonViewModel(newPerson);
////_rootPerson.Children.Add(newPersonViewModel);
//_rootPerson.Children.Add(newPersonViewModel);
//if (newPersonViewModel.Parent != null)
// newPersonViewModel.Parent.IsExpanded = true;
//newPersonViewModel.IsSelected = true;
_familyTree._rootPerson.Children[0].Children.Add(newPersonViewModel);
if (_familyTree._rootPerson.Children[0] == null)
return;
// Ensure that this person is in view.
if (_familyTree._rootPerson.Children[0].Parent != null)
_familyTree._rootPerson.Children[0].Parent.IsExpanded = true;
_familyTree._rootPerson.Children[0].IsSelected = true;
}
}
#endregion // AddCommand
Add command working fine but it's seem to be GUI not update. Rename command is not working but GUI is updated. I don't know reason why, And it's hard to access person class (use parent, person, children,..)
Is there anyone successfully update add, rename, remove command to Josh Smith project.
p/s: I debug by messagebox.show and see binding command for add and rename are working well, But the problem is I don't know what exactly to use Add, remove, rename person in Josh Smith project
Adding items is not reflected in the UI, because the source collection Person.Children doesn't implement INotifyCollectionChanged.
Whenever you need dynamic collections, where add, remove or move operations should update the binding target, you should use the ObservableCollection<T>, which implements INotifyCollectionChanged.
Similar applies to the Person.Name property. If you want a property's change to be reflected to the UI, then your view model must implement INotifyPropertyChanged and raise the INotifyPropertyChanged.PropertyChanged event whenever the binding source (the view model property) has changed.
Generally, when a class serves as a binding source for data binding, then this class must implement INotifyPropertyChanged (if this interface is not implemented, then the performance of data binding becomes very bad).
When the modification of a property should update the UI (binding.target) by invoking the data binding, then the modified property must raise the INotifyPropertyChanged.PropertyChanged event.
When the modification of a collection should update the UI (binding target) by invoking the data binding, then the modified collection must implement INotifyCollectionChanged and raise the INotifyCollectionChanged.CollectionChanged event. ObservableCollection provides a default implementation of INotifyCollectionChanged.
The following example follows the above rules. The changes made to the Person class should fix your issues. Changes to the data model will now be reflected in the TreeView:
public class Person : INotifyPropertyChanged
{
private ObservableCollection<Person> _children = new ObservableCollection<Person>();
public ObservableCollection<Person> Children
{
get { return _children; }
}
private string name
public string Name
{
get => this.name;
set
{
this.name = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

How to inject an action into a command using Ninject?

Actually exploring the Command Pattern and finds it pretty interesting. I'm writing a WPF Windows App following the MVVM Architectural Pattern.
I've begun with these post which explain the basics.
Basic MVVM and ICommand usuage example
Simplify Distributed System Design Using the Command Pattern, MSMQ, and .NET
Now that I was able to break user actions into commands, I thought this could be great to inject the commands that I want. I noticed that the commands are found into the ViewModel in the first referenced article, So I thought that would be great if I could use them along Ninject and actually inject my command into my view model using a binding that would look like the following:
kernel
.Bind<ICommand>()
.To<RelayCommand>()
.WithConstructorArgument("execute", new Action<object>(???));
But then, what to put in here ???. The expected answer is a method. Great! I just need a method to be put in there.
Because the first article simply initialize its commands within the ViewModel constructor, it is easy to say what method should be executed on the command execute call.
But from within the CompositionRoot? This is no place to put a method that will do anything else than bind types together through whatever DI container you're using!
So now, I've come across the Interceptor Pattern using Ninject Extensions. This looks like it could suits my requirements, and there is a bit of confusion here, if I may say. Not that the articles are confusing, they're not. I'm confused!
Using Ninject.Extensions.Interception Part 1 : The Basics
Using Ninject.Extensions.Interception Part 2 : Working With Interceptors
Also, there is this answer from BatteryBackupUnit who always sets great answers.
Ninject - How to implement Command Pattern with Ninject?
But now, I can't see how to glue it all up together! Humbly, I'm lost.
So here's my code so far.
RelayCommand
public class RelayCommand : ICommand {
public RelayCommand(Action<object> methodToExecute, Predicate<object> canExecute) {
if(methodToExecute == null)
throw new ArgumentNullException("methodToExecute");
if(canExecute == null)
throw new ArgumentNullException("canExecute");
this.canExecute = canExecute;
this.methodToExecute = methodToExecute;
}
public bool CanExecute(object parameter) {
return canExecute != null && canExecute(parameter);
}
public event EventHandler CanExecuteChanged {
add {
CommandManager.RequerySuggested += value;
canExecuteChanged += value;
}
remove {
CommandManager.RequerySuggested -= value;
canExecuteChanged -= value;
}
}
public static bool DefaultCanExecute(object parameter) { return true; }
public void Execute(object parameter) { methodToExecute(parameter); }
public void OnCanExecuteChanged() {
var handler = canExecuteChanged;
if(handler != null) handler(this, EventArgs.Empty);
}
public void Destroy() {
canExecute = _ => false;
methodToExecute = _ => { return; };
}
private Predicate<object> canExecute;
private Action<object> methodToExecute;
private event EventHandler canExecuteChanged;
}
CategoriesManagementViewModel
public class CategoriesManagementViewModel : ViewModel<IList<Category>> {
public CategoriesManagementViewModel(IList<Category> categories
, ICommand changeCommand
, ICommand createCommand
, ICommand deleteCommand) : base(categories) {
if(changeCommand == null)
throw new ArgumentNullException("changeCommand");
if(createCommand == null)
throw new ArgumentNullException("createCommand");
if(deleteCommand == null)
throw new ArgumentNullException("deleteCommand");
this.changeCommand = changeCommand;
this.createCommand = createCommand;
this.deleteCommand = deleteCommand;
}
public ICommand ChangeCommand { get { return changeCommand; } }
public ICommand CreateCommand { get { return createCommand; } }
public ICommand DeleteCommand { get { return deleteCommand; } }
private readonly ICommand changeCommand;
private readonly ICommand createCommand;
private readonly ICommand deleteCommand;
}
I wonder, would it be better off using Property Injection, though I tend not to use it all?
Let's say I have CategoriesManagementView that calls another window, let's say CreateCategoryView.Show(), and then the CreateCategoryView takes over until the user is back to the management window.
The Create Command then needs to call CreateCategoryView.Show(), and that is what I tried from within the CompositionRoot.
CompositionRoot
public class CompositionRoot {
public CompositionRoot(IKernel kernel) {
if(kernel == null) throw new ArgumentNullException("kernel");
this.kernel = kernel;
}
//
// Unrelated code suppressed for simplicity sake.
//
public IKernel ComposeObjectGraph() {
BindCommandsByConvention();
return kernel;
}
private void BindCommandsByConvention() {
//
// This is where I'm lost. I can't see any way to tell Ninject
// what I want it to inject into my RelayCommand class constructor.
//
kernel
.Bind<ICommand>()
.To<RelayCommand>()
.WithConstructorArgument("methodToExecute", new Action<object>());
//
// I have also tried:
//
kernel
.Bind<ICommand>()
.ToConstructor(ctx =>
new RelayCommand(new Action<object>(
ctx.Context.Kernel
.Get<ICreateCategoryView>().ShowSelf()), true);
//
// And this would complain that there is no implicit conversion
// between void and Action and so forth.
//
}
private readonly IKernel kernel;
}
Perhaps I am overcomplicating things, that is generally what happends when one gets confused. =)
I just wonder whether the Ninject Interception Extension could be the right tool for the job, and how to use it effectively?
I created a simple example of a command interacting with an injected service. might not compile since i'm going from memory. Maybe this can help you.
public class TestViewModel
{
private readonly IAuthenticationService _authenticationService;
public DelegateCommand SignInCommand { get; private set; }
public TestViewModel(IAuthenticationService authenticationService) //Inject auth service
{
_authenticationService = authenticationService
SignInCommand = new DelegateCommand(OnSignInRequest)
}
private void OnSignInRequest(Action<bool> isSuccessCallback)
{
var isSuccess = _authenticationService.SignIn();
isSuccessCallback(isSuccess);
}
}
}

Force reevaluate ICommand CanExecute upon context menu open

I know I can force reevalution of CanExecute in the view model, however, this requires the view model to register to all related data change events, which might not be always feasible.
Since the commands are only used in the context menu, and during the context menu is open, the data that affect CanExecute cannot be changed, it would be sufficient if CanExecute is reevaluated only when context menu is being opened.
To do this, I can hook up context menu open event and call view model to call RaiseCanExecuteChanged on each ICommand the context menu uses, but it's tedious and anti MVVM. I am wondering if there is an easier way to achieve this?
Yes there is. Use this implementation of ICommand. It reevaluates on each interaction, in your case "Context menu opening". It is not so performance efficient, but if you are not having hundreds of commands then should do the work:
public class Command<TArgs> : ICommand
{
public Command(Action<TArgs> exDelegate)
{
_exDelegate = exDelegate;
}
public Command(Action<TArgs> exDelegate, Func<TArgs, bool> canDelegate)
{
_exDelegate = exDelegate;
_canDelegate = canDelegate;
}
protected Action<TArgs> _exDelegate;
protected Func<TArgs, bool> _canDelegate;
#region ICommand Members
public bool CanExecute(TArgs parameter)
{
if (_canDelegate == null)
return true;
return _canDelegate(parameter);
}
public void Execute(TArgs parameter)
{
if (_exDelegate != null)
{
_exDelegate(parameter);
}
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
bool ICommand.CanExecute(object parameter)
{
if (parameter != null)
{
var parameterType = parameter.GetType();
if (parameterType.FullName.Equals("MS.Internal.NamedObject"))
return false;
}
return CanExecute((TArgs)parameter);
}
void ICommand.Execute(object parameter)
{
Execute((TArgs)parameter);
}
#endregion
}

MVVM-Light Toolkit -- How To Use PropertyChangedMessage

Can someone please post a working example of the PropertyChangedMessage being used? The description from the GalaSoft site states:
PropertyChangedMessage: Used to broadcast that a property changed in the sender. Fulfills the same purpose than the PropertyChanged event, but in a less tight way.
However, this doesn't seem to work:
private bool m_value = false;
public bool Value
{
get { return m_value ; }
set
{
m_value = value;
Messenger.Default.Send(new PropertyChangedMessage<bool>(m_value, true, "Value"));
}
This is related with the MVVM Light Messenger.
In your property definition yo use like this:
public string Name {
get
{
return _name;
}
set
{
if (_name == value)
{
return;
}
var oldValue = _name;
_name = value;
// Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
RaisePropertyChanged(Name, oldValue, value, true);
}
}
Then you can suscribe to any modification on the property using something like this:
Messenger.Default.Register<PropertyChangedMessage<string>>(
this, (e) => this.Name = e.NewValue
);
Look at this post and read about the MVVM Light Messenger
To broadcast:
Messenger.Default.Send<PropertyChangedMessage<string>>(oldValue, newValue, "PropertyName");
Daniel Castro commented on my question with the following question: "What do you expect from the code?"
The answer to this question prompted me to write this answer to my own question.
My expectations were, based on the badly written description for the PropertyChangedMessage class in the MVVM-Light documentation, that when I sent a PropertyChangedMessage then the RaisePropertyChanged method on the ViewModelBase class would get automatically called.
Apparently, however, it's the other way around. When you call RaisePropertyChanged, then that method has an overload where you can set a flag which determines whether or not a PropertyChangedMessage will be sent.
However, I want the functionality that I originally expected. I want to send off a new PropertyChangedMessage that automatically causes RaisePropertyChanged to be called. Here's how to do that.
Derive a new class from ViewModelBase with the following public NotifyPropertyChanged method which simply calls the protected RaisePropertyChanged method:
public abstract class MyViewModelBase : GalaSoft.MvvmLight.ViewModelBase
{
public void NotifyPropertyChanged(string propertyName)
{
RaisePropertyChanged(propertyName);
}
}
Then derive a new class from PropertyChangedMessage which calls the new NotifyPropertyChanged method:
public class MyPropertyChangedMessage<T> : PropertyChangedMessage<T>
{
public MyPropertyChangedMessage(object sender, T oldValue, T newValue, string propertyName)
: base(sender, oldValue, newValue, propertyName)
{
var viewModel = sender as MyViewModelBase;
if (viewModel != null)
{
viewModel.NotifyPropertyChanged(propertyName);
}
}
public MyPropertyChangedMessage(object sender, object target, T oldValue, T newValue, string propertyName)
: base(sender, target, oldValue, newValue, propertyName)
{
var viewModel = sender as MyViewModelBase;
if (viewModel != null)
{
viewModel.NotifyPropertyChanged(propertyName);
}
}
}
I have tested this approach and verified that I can indeed write code like the following which causes the UI to update properly:
private bool m_value = false;
public bool Value
{
get { return m_value; }
set
{
Messenger.Default.Send(new MyPropertyChangedMessage<bool>(this, m_value, value, "Value"));
m_value = value;
}
}

CollectionViewSource Filter not refreshed when Source is changed

I have a WPF ListView bound to a CollectionViewSource. The source of that is bound to a property, which can change if the user selects an option.
When the list view source is updated due to a property changed event, everything updates correctly, but the view is not refreshed to take into account any changes in the CollectionViewSource filter.
If I attach a handler to the Changed event that the Source property is bound to I can refresh the view, but this is still the old view, as the binding has not updated the list yet.
Is there a decent way to make the view refresh and re-evaluate the filters when the source changes?
Cheers
Updating the CollectionView.Filter based on a PropertyChanged event is not supported by the framework.
There are a number of solutions around this.
1) Implementing the IEditableObject interface on the objects inside your collection, and calling BeginEdit and EndEdit when changing the property on which the filter is based.
You can read more about this on the Dr.WPF's excellent blog here : Editable Collections by Dr.WPF
2) Creating the following class and using the RefreshFilter function on the changed object.
public class FilteredObservableCollection<T> : ObservableCollection<T>
{
public void RefreshFilter(T changedobject)
{
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, changedobject, changedobject));
}
}
Example:
public class TestClass : INotifyPropertyChanged
{
private string _TestProp;
public string TestProp
{
get{ return _TestProp; }
set
{
_TestProp = value;
RaisePropertyChanged("TestProp");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
var handler = this.PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
FilteredObservableCollection<TestClass> TestCollection = new FilteredObservableCollection<TestClass>();
void TestClass_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "TestProp":
TestCollection.RefreshFilter(sender as TestClass);
break;
}
}
Subscribe to the PropertyChanged event of the TestClass object when you create it, but don't forget to unhook the eventhandler when the object gets removed, otherwise this may lead to memory leaks
OR
Inject the TestCollection into the TestClass and use the RefreshFilter function inside the TestProp setter.
Anyhow, the magic here is worked by the NotifyCollectionChangedAction.Replace which updates the item entirely.
Are you changing the actual collection instance assigned to the CollectionViewSource.Source, or are you just firing PropertyChanged on the property that it's bound to?
If the Source property is set, the filter should be recalled for every item in the new source collection, so I'm thinking something else is happening. Have you tried setting Source manually instead of using a binding and seeing if you still get your behavior?
Edit:
Are you using CollectionViewSource.View.Filter property, or the CollectionViewSource.Filter event? The CollectionView will get blown away when you set a new Source, so if you had a Filter set on the CollectionView it won't be there anymore.
I found a specific solution for extending the ObservableCollection class to one that monitors changes in the properties of the objects it contains here.
Here's that code with a few modifications by me:
namespace Solution
{
public class ObservableCollectionEx<T> : ObservableCollection<T> where T : INotifyPropertyChanged
{
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (e != null) // There's been an addition or removal of items from the Collection
{
Unsubscribe(e.OldItems);
Subscribe(e.NewItems);
base.OnCollectionChanged(e);
}
else
{
// Just a property has changed, so reset the Collection.
base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
protected override void ClearItems()
{
foreach (T element in this)
element.PropertyChanged -= ContainedElementChanged;
base.ClearItems();
}
private void Subscribe(IList iList)
{
if (iList != null)
{
foreach (T element in iList)
element.PropertyChanged += ContainedElementChanged;
}
}
private void Unsubscribe(IList iList)
{
if (iList != null)
{
foreach (T element in iList)
element.PropertyChanged -= ContainedElementChanged;
}
}
private void ContainedElementChanged(object sender, PropertyChangedEventArgs e)
{
OnPropertyChanged(e);
// Tell the Collection that the property has changed
this.OnCollectionChanged(null);
}
}
}
Maybe a bit late to the party but just in case
You can also use CollectionViewSource.LiveSortingProperties
I found it through this blog post.
public class Message : INotifyPropertyChanged
{
public string Text { get; set; }
public bool Read { get; set; }
/* for simplicity left out implementation of INotifyPropertyChanged */
}
public ObservableCollection<Message> Messages {get; set}
ListCollectionView listColectionView = (ListCollectionView)CollectionViewSource.GetDefaultView(Messages);
listColectionView.IsLiveSorting = true;
listColectionView.LiveSortingProperties.Add(nameof(Message.Read));
listColectionView.SortDescriptions.Add(new SortDescription(nameof(Message.Read), ListSortDirection.Ascending));
I found a relatively simple method to do this.
I changed the readonly ICollectionView property to get/set and added the raised property event:
Property TypeFilteredCollection As ICollectionView
Get
Dim returnVal As ICollectionView = Me.TypeCollection.View
returnVal.SortDescriptions.Add(New SortDescription("KeyName", ListSortDirection.Ascending))
Return returnVal
End Get
Set(value As ICollectionView)
RaisePropertyChanged(NameOf(TypeFilteredCollection))
End Set
End Property
Then to update, i just used:
Me.TypeFilteredCollection = Me.TypeFilteredCollection
This clearly won't work if you don't have somewhere to trigger that update though.

Resources