Can anyone explain to me how I can use Func<T, T, bool>? validateValue = null) validation in the Xamarin Community Toolkit ObservableObject?

Viewed 166

I've not been able to find any examples at all for this.

Here is what I am currently doing:

public partial class RenameGroupPopupViewModel
{
    private string _newGroupName;

    public string NewGroupName
    {
        get => _newGroupName;
        set => SetProperty(ref _newGroupName, value);
    }
}

In ObservableObject.cs there is a parameter validateValue but I do not know or understand how to use it.

I would like to try using the Func<T, T, bool>? validateValue = null) to call a method called ValidateName that would check if the value is set to "default" and if so then return false so the value would not be set.

Here is the full code for the class:

ObservableObject.cs

Here is the code snippet from

    /// <summary>
    /// Sets the property.
    /// </summary>
    /// <returns><c>true</c>, if property was set, <c>false</c> otherwise.</returns>
    /// <param name="backingStore">Backing store.</param>
    /// <param name="value">Value.</param>
    /// <param name="validateValue">Validates value.</param>
    /// <param name="propertyName">Property name.</param>
    /// <param name="onChanged">On changed.</param>
    /// <typeparam name="T">The 1st type parameter.</typeparam>
    protected virtual bool SetProperty<T>(
        ref T backingStore,
        T value,
        [CallerMemberName] string propertyName = "",
        Action? onChanging = null,
        Action? onChanged = null,
        Func<T, T, bool>? validateValue = null)
    {
        // if value didn't change
        if (EqualityComparer<T>.Default.Equals(backingStore, value))
            return false;

        // if value changed but didn't validate
        if (validateValue != null && !validateValue(backingStore, value))
            return false;

        onChanging?.Invoke();
        backingStore = value;
        onChanged?.Invoke();
        OnPropertyChanged(propertyName);
        return true;
    }

I realize I have to supply a function for the validation but I am not sure how to specify this and should it be a normal kind of method or a delegate? Here is the functionality I need:

    private bool ValidateName(string groupName)
    {
        if (groupName == "default")
            return false;
        else
            return true;
    }
1 Answers

The method you're calling contains this clause:

// if value changed but didn't validate
if (validateValue != null && !validateValue(backingStore, value))
    return false;

This is invoking the validateValue delegate that's passed in. The delegate takes two parameters, both of type T for the generic SetProperty<T>() method, and returns a bool, where false means that the values passed to the delegate don't meet whatever criteria the caller has implemented for the delegate.

Note that backingStore, which is the current value of the property, and value, which is the new value being assigned to the property, are both passed to the validation delegate. So the delegate is free to use either or both as it sees fit.

Your chosen method appears to care only about the newly-assigned value. So you can pass an appropriate delegate either by changing your validation method signature to accept two parameters and ignoring the first one:

private bool ValidateName(string currentName, string newName)
{
    if (newName == "default")
        return false;
    else
        return true;
}

and

public string NewGroupName
{
    get => _newGroupName;
    set => SetProperty(ref _newGroupName, value, validateValue: ValidateName);
}

Or you can leave your method as it is now, and wrap a call to it in a lambda expression:

public string NewGroupName
{
    get => _newGroupName;
    set => SetProperty(ref _newGroupName, value, validateValue: (_, newName) => ValidateName(newValue));
}

Either one would be fine.

Note the use of the named parameter, since there are additional parameters between the value argument being passed and the delegate reference being passed which you presumably still don't want to specify. Naming the validateValue parameter allows the other parameters to still be omitted, resulting in their default values being passed as expected.

Note also that in either case, a delegate instance is what's actually passed. The C# compiler automatically translates expressions such as a "method group name", as in the first example, or a "lambda expression", as in the second example, into code that instantiates a new delegate instance, using the provided method as the target of the delegate, inferring the delegate type according to the context of the code (in this example, the actual delegate type being passed will be Func<string, string, bool>). Lambda expressions of this form are compiled as "anonymous methods". You can look those terms up for additional information if you like.

Related