CanExecute from Children

Topics: Questions
Jan 9, 2013 at 9:15 AM

Hello

Special Idea :-)

Have a button on the parentviewmodel with command

DeleteSomething = new Command(() => { }, OnDeleteSomethingCanExecute"DeleteSomething");

In the parentviewmodel nothing should happens only inform InterstedIn Viewmodels that the command has executed. That works.

But I need information from childs: can the command execute?

An idea is to do this with validation. But the problem is that then I have errors or warnings. Don't want that just enable or disable the button.

Developer
Jan 9, 2013 at 2:40 PM
Edited Jan 9, 2013 at 4:23 PM

I wrote about this in this thread

http://catel.codeplex.com/discussions/405927

Summary:

Probably you could solve your issue using the ValidationToViewModel attribute if you have your viewmodels sorted in a parent child way.

In a parent viewmodel you can do this:

[ValidationToViewModel(Tag = "Person", IncludeChildViewModels = true )]
IValidationSummary personValidationSummary;
....

and initialize the save command (for instance):

SaveCommand = CommandHelper.CreateCommand(OnSave, () => personValidationSummary);

Then in your child viewmodels the only thing that you have to do is tag the validation results just like this:

        protected override void ValidateFields(List<IFieldValidationResult> validationResults)
        {
            if (string.IsNullOrEmpty(Name))
            {
                validationResults.Add(FieldValidationResult.CreateErrorWithTag(NameProperty, "The name field is empty", "Person"));   
            }      
         }

-----

Here are the documentation links:

http://catel.catenalogic.com/gs_viewscontrols_nested_user_controls_problem.htm

http://catel.catenalogic.com/getting_a_summary_of_validatio.htm

http://catel.catenalogic.com/validation_hooking_a_command_to_validatio.htm

 ----

 Then you can convert the validation summary into a catel  property so, you can detect when the validation summary is changed.

Jan 10, 2013 at 7:04 AM

Yes, you wrote that. But you don't read my last sentence.

I don't wan't to have errors or warnings. That will be show in the InfobarmessageControl. Just wan't to disable the button.

Developer
Jan 10, 2013 at 1:59 PM

Yes, I read (but later, sorry for that). Then I updated the post  with a last sentence.

>> Then you can convert the validation summary into a catel property so, you can detect when the validation summary is changed.

Jan 10, 2013 at 2:48 PM

Property? Where do I have to implement the property? In the parent? And how can I set the property from a child?

Developer
Jan 10, 2013 at 3:43 PM

The value will be injected at the end of the validation sequence, if you use the ValidationToViewModelAttribute. To include child view model validation results just set IncludeChildViewModels = true. You can also filter the result with a Tag.

Here is the implementation pattern of a parent viewmodel:

    /// <summary>
    /// The parent view model.
    /// </summary>
    public class ParentViewModel : ViewModelBase
    {
        #region Static Fields

        /// <summary>Register the ValidationSummary property so it is known in the class.</summary>
        public static readonly PropertyData ValidationSummaryProperty = RegisterProperty(
            "ValidationSummary",
            typeof(IValidationSummary),
            default(IValidationSummary),
            (s, e) => ((ParentViewModel)s).OnValidationSummaryChanged(e));

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the validation summary.
        /// </summary>
        [ValidationToViewModel(Tag = "FilterHereWithATag", IncludeChildViewModels = true)]
        public IValidationSummary ValidationSummary
        {
            get { return this.GetValue<IValidationSummary>(ValidationSummaryProperty); }

            set { this.SetValue(ValidationSummaryProperty, value); }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Occurs when the value of the ValidationSummary property is changed.
        /// </summary>
        /// <param name="e">
        /// The event argument
        /// </param>
        private void OnValidationSummaryChanged(AdvancedPropertyChangedEventArgs e)
        {
            // Here you can do whatever you want (not only disable a button)
        }

        #endregion
    }

Jan 11, 2013 at 7:09 AM
Edited Jan 11, 2013 at 7:35 AM

What I have to do in the child?

Add an error to the validationResults? Then I see the errormessage in the InfoBarmessageControl.
And how to disable the button in the OnValidationSummaryChanged. Set a property?

 

And:

The Validation works not correct so its difficult to test. For one problem I oppened a issue.

The other problem is that the tag filter works not correct. I implmented the ValidationSummary Property like in your example, with a tag.

but when I add an Validationerror in a child without a tag 

validationResults.Add(BusinessRuleValidationResult.CreateError(message));

The Validation is also catched from the validationsummary with tag and my button is also disabled.

Developer
Jan 11, 2013 at 2:16 PM

>> What I have to do in the child?
>> Add an error to the validationResults?

Yes

>> Then I see the errormessage in the InfoBarmessageControl.

By default the InfoBarMessageControlGenerationMode is Inline so call the base constructor with None

>> And how to disable the button in the OnValidationSummaryChanged. Set a property?

The clean way to disable a button is hooking the Command with the ValidationSummary just like this

MyCommand = CommandHelper.CreateCommand(OnMyCommandExecute, () => MyCommandValidationSummary);
 
>>And:
>>The Validation works not correct so its difficult to test. For one problem I oppened a issue.
>>The other problem is that the tag filter works not correct. I implmented the ValidationSummary Property like in your example, with a tag.
>>but when I add an Validationerror in a child without a tag
>>validationResults.Add(BusinessRuleValidationResult.CreateError(message));
>>The Validation is also catched from the validationsummary with tag and my button is also disabled.

Could you provide a test or reproduction or sample code? We will also check this as soon as possible.


 

Jan 14, 2013 at 9:10 AM

>> By default the InfoBarMessageControlGenerationMode is Inline so call the base constructor with None

Just can set the Mode to Inline or Overlay?

<catel:InfoBarMessageControl Mode="Overlay">

 And when its possible to set None. The InfoBarMessageControl is disabled? I dont see my other errormessages. Or what do you mean?

 

>> Could you provide a test or reproduction or sample code? We will also check this as soon as possible.

Yes I have already added a repro.

http://catel.codeplex.com/workitem/7235

Here you can also set a Error with no Tag. And the Property with tag will recognize it.

Coordinator
Jan 14, 2013 at 5:52 PM

If you don't want to use validation to determine the state, then you will need to use another technique. Here are a few options:

1) implement the IAuthenticationProvider (or something like that, don't have the source with me at the moment). All commands will get through this provider if it is registered. For more info, see http://blog.catenalogic.com/post/2011/11/02/Catel-24-sneak-preview-authentication-behavior.aspx

2) use the InterestedIn attribute in combination with tags to determine the state. You probably have some special requirements here that require custom logic without validation.

Jan 25, 2013 at 10:48 AM

Ok.

So when I use the InterstedIn Attribute:

I need a Property in the childViewModel. Set this property to false when its not allowed to click the button. In the ParentViewModel I need a Property or a  field. Set this field in the method OnViewModelPropertyChanged to the value of the Property of the child. And in CanExceute Method return this value.

Hm. I there no way to set the field or the property of the parent directly in the ChildViewModel.

Coordinator
Jan 28, 2013 at 8:40 PM

No, you cannot cheat by setting (non-public) values of a parent view models. Then you cannot provide a consistent behavior as a view model developer. You should really take a look at the authentication behavior, it works really cool.

Jan 29, 2013 at 8:47 AM
Edited Jan 29, 2013 at 10:31 AM

Ok. I tought authentication behavior you need only if you have different users.

Coordinator
Jan 30, 2013 at 8:11 AM

Nope :-)

We probably should have called it CommandVerification or something like that, but it does more than that.