Light property grid with fluent validation

C#, .NET Core, WPF,

Hi Everyone.
And here one more PropertyGrid. This time it is a tiny mini lib. Nevertheless that allows supporting all common cases of PropertyGrid requirements. There are no details of implementation only examples of how to use and what it capable of. If you need small lib with PropertyGrid this is for you.

Existed solutions

This is list of popular implementation I am sure there are more but I didn't aim to find them all.

Syncfusion
Devexpress
PropertyGrid from CodePlex
Extended WPF Toolkit

All libraries have a lot of good functions and they allow us to do many customizations. I will not describe them or list the cons and pros.

What was implemented in this Property Grid

Common functions
Used attributes from System.ComponentModel.DataAnnotations
Automatically convert all properties of class into WPF controls
Support converting inner classes
Allow show/hide properties with attributes
Additional
Validation using FluentValidation
Allow changing properties/WPF control in real-time
Use custom DataTemplate for UI properties representation
Control of converting properties. It means converting process invoked manually, for example after UI loaded to allow to show it faster.

How it looks like

class PropertyGridTestDataProxy : ViewModelProxy<PropertyGridTestDataProxy> {
  [Visible] // not required, visible by default
  [Display(Name = "Email")]// not required, by default - name of the property
  [ReadOnly(false)] // not required, false by default
  public string Email { get; set; } 
  
  protected override FluentValidation.Results.ValidationResult OnValidate() => Validate(this);
  
  public PropertyGridTestDataProxy() {
    RuleFor(x => x.Email).EmailAddress();
  }
}
class MainViewModel : BaseNotify {
     public GroupViewModelProperties <PropertyGridTestDataProxy> PropertyGrid { get; }
     public MainViewModel() {
       PropertyGrid = new GroupViewModelProperties(new PropertyGridTestDataProxy(), "Test Property Grid");
     }
     public override void OnLoaded() {
         base.OnLoaded();
         PropertyGrid.Analyze();
         PropertyGrid.Validate();
     }
 }
<ResourceDictionary Source="/WPFLab;component/LightPropertyGrid/ViewPropertyResources.xaml"/>
...
<ContentControl Content="{Binding PropertyGrid}" /> 

How it works

Each class properties are converted to ViewModelProperty decorator based on type.

ComboBoxViewModelProperty
for enum and bool
CheckBoxViewModelProperty
for nullable bool
TextBoxViewModelProperty
for the rest primitive types
GroupViewModelProperties
for base class or inner class

Each decorator is bound to a certain DataTemplate allows full control of the representation of fields.

Property validation

Validation can be implemented anywhere it depends on your architectural decision. The example above contains validation in the constructor but it is not a strong rule.

class MainViewModel {
  public GroupViewModelProperties <PropertyGridTestDataProxy> PropertyGrid { get; }
  public void InitValidationRules(){ 
    PropertyGrid.Value.RuleFor(x => x.Email).EmailAddress();
  }
}

Validation works automatically after changing value in UI and also can be rised manually PropertyGrid.Validate(). Error message is used from FluentValidation rules or custom setting with .WithMessage()

RuleFor(x => x.Email).EmailAddress().WithMessage("...")

Handle properties on run-time

This is the reason to implement Property grid myself. I need to change UI statuses manually from the code.

class PropertyGridTestDataProxy : ViewModelProxy<PropertyGridTestDataProxy> {
  public string Email { get; set; }
  public void HideEmailField() {
    UpdateViewProperty(
      x => x.Email, // what property will be changed 
      property => property.Visible = VisibleModes.Hidden // change property
    );
  }
}

property is UI representation of the proxy class property. Here property is base interface of all UI fields.

public interface IViewProperty {
  string PropertyName { get; }
  string Title { get; }
  bool IsReadOnly { get; set; }
  VisibleModes Visible { get; set; }
  void Validate();
}

How to notify UI about new value in proxy class

There is the same approach as INotifyPropertyChanged, just add updating in property setter.

string text;
[Visible]
public string Text {
    get => text;
    set { 
        Update(ref text, value);
    }
}

Source codes

Find something strange in code ... be free to add issues.

LightPropertyGrid
Example

Conclusion

Implementation of your own libs is justified only if there are no alternatives or for learning. In my case, the reason was to have a free to change and full customization of any layers of this lib. I spent not much time to implement that is why it is a win-win :)

Thanks for reading.
Have a nice day!