CommunityToolkit / dotnet

.NET Community Toolkit is a collection of helpers and APIs that work for all .NET developers and are agnostic of any specific UI platform. The toolkit is maintained and published by Microsoft, and part of the .NET Foundation.
https://docs.microsoft.com/dotnet/communitytoolkit/?WT.mc_id=dotnet-0000-bramin
Other
2.99k stars 294 forks source link

Add source generation: "NotifyDataErrorInfoFor" #788

Open mikechristiansenvae opened 11 months ago

mikechristiansenvae commented 11 months ago

Overview

We already have the [NotifyDataErrorInfo] attribute, which adds source generation to validate this property.

But since we can use custom validation methods to perform multi-property validation, we should have a way to indicate that Property A influences the validation of Property B.

API breakdown

Add an attribute, NotifyDataErrorInfoForAttribute, which influences the source generator to add validation of other properties.

Right now, the generated setter for a property with [NotifyDataErrorInfo] looks like this:

if (!global::System.Collections.Generic.EqualityComparer<string?>.Default.Equals(path, value))
{
    OnPathChanging(value);
    OnPathChanging(default, value);
    OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Path);
    path = value;
    ValidateProperty(value, "Path");
    OnPathChanged(value);
    OnPathChanged(default, value);
    OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Path);
}

After the change, it would look like this:

if (!global::System.Collections.Generic.EqualityComparer<string?>.Default.Equals(path, value))
{
    OnPathChanging(value);
    OnPathChanging(default, value);
    OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Path);
    path = value;
    ValidateProperty(value, "Path");
        ValidateProperty(SomeOtherProperty,"SomeOtherProperty");  // <---- THIS LINE IS NEW
    OnPathChanged(value);
    OnPathChanged(default, value);
    OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Path);
}

Usage example


[NotifyDataErrorInfoFor(nameof(Path))]  // <--- NEW ATTRIBUTE
private bool isRequired;

[ObservableProperty]
[NotifyDataErrorInfo]
[CustomValidation(typeof(FileSystemLocationViewModel), nameof(ValidatePath))]
private string? path;

public static ValidationResult? ValidatePath(string? path, ValidationContext context)
{
    var instance = (FileSystemLocationViewModel)context.ObjectInstance;
    if (string.IsNullOrWhiteSpace(path))
    {
        if (instance.IsRequired)
            return new ValidationResult("Path is required");
        return ValidationResult.Success;
    }
    if(IsValidPath(path))
        return ValidationResult.Success;
    return new ValidationResult("Invalid path provided");
}

Breaking change?

No

Alternatives

Workaround (available now):

Manually implement the property

private bool isRequired;
public bool IsRequired
{
    get => this.isRequired;
    set
    {
        if (this.SetProperty(ref this.isRequired, value))
            this.ValidateProperty(this.Path, nameof(this.Path));
    }
}

Additional context

No response

Help us help you

No, just wanted to propose this