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.
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!