mvvmgen icon indicating copy to clipboard operation
mvvmgen copied to clipboard

Raise CommandInvalidate when adding or removing elements on collection

Open Daimonion1980 opened this issue 1 year ago • 4 comments

Hello Thomas.

Is it possible to raise a CommandInvalidate method when changing the number of elements on an ObservableCollection?

In my code i have an ObservableCollection where i can add or remove elements via command methods. Now I want to implement a clear button which will become enabled when the ObservableCollection has more than zero elements.

[ViewModel]
[ViewModelGenerateFactory]
public partial class VM_ParameterChooser 
{
	[Property] ObservableCollection<VM_Parameter> selectedParameterList = new ObservableCollection<VM_Parameter>();

	[Command(CanExecuteMethod = nameof(SelectedListCanBeCleared))]
	public void Clear()
	{
		SelectedParameterList.Clear();
	}

	//this method is only called when SelectedParameterList is changed itself
	//but should be called if a element is added or removed from the collection
	[CommandInvalidate(nameof(SelectedParameterList))]	
	public bool SelectedListCanBeCleared() => SelectedParameterList.Count > 0;

	[Command]
	public void AddSelectedParameter(object param)
	{
		var selectedParam = param as VM_Parameter;
		if (selectedParam is null) return;
		SelectedParameterList.Add(selectedParam);
	}

	[Command]
	public void RemoveSelectedParameter(object param)
	{
		var selectedParam = param as VM_Parameter;
		if (selectedParam is null) return;
		SelectedParameterList.Remove(selectedParam);
	}
}

Daimonion1980 avatar Dec 07 '23 10:12 Daimonion1980

Hi,

Two things come to my mind what you could do here. Call 'ClearCommand.RaiseCanExecuteChanged();' at the end of your Add and Remove method or overwrite the OnInitialize method and subscribe to the 'CollectionChanged' event of your selectedParameterList and if fired call the 'ClearCommand.RaiseCanExecuteChanged();' .

Telespaz avatar Dec 07 '23 11:12 Telespaz

Hey @Telespaz

Thank you for your answer.

Call 'ClearCommand.RaiseCanExecuteChanged();' at the end of your Add and Remove method

Yep, i added a call to my Add and Remove Method and the button enables and disables as expected.

InvalidateCommands(nameof(SelectedParameterList));

Daimonion1980 avatar Dec 07 '23 11:12 Daimonion1980

@Daimonion1980 This sounds like a great approach that you took now.

Alternatively, you can call as suggested by @Telespaz

ClearCommand.RaiseCanExecuteChanged();

But in your case, your call to InvalidateCommands might be more clear from a semantical point of view. Both ways are good. 👍

Your idea is great to include this in MvvmGen, but it gets super complex very soon. The items in the ObservableCollection could be INotifyPropertyChanged objects, then you need to track these changes as well etc. I think handling it in your own code is the best way, as the generator might lead to a 90% solution.

thomasclaudiushuber avatar Dec 07 '23 16:12 thomasclaudiushuber

Btw, if you don't set the ObservableCollection to a new instance from your UI, there's no reason to use a field with the Property attribute. Instead, you can define the property directly in your code like this (I included a bit of C# 12 sugar, the [] to initialize the collection 😊):

[ViewModel]
[ViewModelGenerateFactory]
public partial class VM_ParameterChooser
{
    public ObservableCollection<VM_Parameter> SelectedParameterList = [];

    [Command(CanExecuteMethod = nameof(SelectedListCanBeCleared))]
    public void Clear()
    {
        SelectedParameterList.Clear();
    }

    [CommandInvalidate(nameof(SelectedParameterList))]
    public bool SelectedListCanBeCleared() => SelectedParameterList.Count > 0;

    [Command]
    public void AddSelectedParameter(object param)
    {
        var selectedParam = param as VM_Parameter;
        if (selectedParam is null) return;
        SelectedParameterList.Add(selectedParam);
        InvalidateCommands(nameof(SelectedParameterList));
    }

    [Command]
    public void RemoveSelectedParameter(object param)
    {
        var selectedParam = param as VM_Parameter;
        if (selectedParam is null) return;
        SelectedParameterList.Remove(selectedParam);
        InvalidateCommands(nameof(SelectedParameterList));
    }
}

thomasclaudiushuber avatar Dec 07 '23 16:12 thomasclaudiushuber