Unplanned
Last Updated: 29 Jul 2024 06:34 by David
David
Created on: 05 Jul 2024 07:23
Category: PropertyGrid
Type: Feature Request
2
PropertyGrid: Add the ability to add new items in the collection editor when binding to primitive types
Add the ability to add new items in the collection editor when binding to primitive types.
1 comment
David
Posted on: 29 Jul 2024 06:34

This would be really useful functionality. We often need to implement this as we have many domain classes with Lists of doubles / ints. 

 

Following Ticket 1657199 here is one way to acheive this functionality.

It will provide a value type Add command for all collections which inherit from IList.  

 

In your code behind call:

this.radPropertyGrid.AutoGeneratingPropertyDefinition += ValueTypeAddCommandProvider.AutoGeneratePropertyDefinition;

 

And add this to your codebase:

using System;
using System.Collections;
using System.Windows;
using System.Windows.Markup;
using Telerik.Windows.Controls;
using Telerik.Windows.Controls.Data.CollectionNavigator;
using Telerik.Windows.Controls.Data.PropertyGrid;

namespace _1657199;

public class ValueTypeAddCommandProvider : CollectionNavigatorBaseCommandProvider {
    public ValueTypeAddCommandProvider() : base(null) { }

    public ValueTypeAddCommandProvider(CollectionNavigatorBase collectionEditor) : base(collectionEditor) {
        this.CollectionNavigator = collectionEditor;
    }

    public override void AddNew() {
        if (CollectionNavigator.Source is IList list) {
            var t = this.CollectionNavigator.Source.GetType();
            if (t.IsGenericType && t.GenericTypeArguments.Length == 1 && t.GenericTypeArguments[0].IsValueType) {
                var listType = t.GenericTypeArguments[0];
                    
                var newItem = Activator.CreateInstance(listType);
                if (newItem != null) {
                    list.Add(newItem);
                }
            }
        }
            
    }

    public override bool CanAddNewExecute() => true;

    public static void AutoGeneratePropertyDefinition(object sender, AutoGeneratingPropertyDefinitionEventArgs e)
    {
        var descriptor = e.PropertyDefinition.PropertyDescriptor;
        var isPrimitiveList = descriptor is { PropertyType: { IsGenericType: true, GenericTypeArguments.Length: 1 } } &&
                              descriptor.PropertyType.IsAssignableTo(typeof(IList)) &&
                              descriptor.PropertyType.GenericTypeArguments[0].IsValueType;
        if (isPrimitiveList) {
            Type editorType = typeof(CollectionEditorPicker);
            Type commandType = typeof(ValueTypeAddCommandProvider);
            var parserContext = new ParserContext();
            parserContext.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
            parserContext.XmlnsDictionary.Add("myTelerik", $"clr-namespace:{editorType.Namespace};assembly={editorType.Assembly.GetName().Name}");
            parserContext.XmlnsDictionary.Add("myCommand", $"clr-namespace:{commandType.Namespace};assembly={commandType.Assembly.GetName().Name}");
            e.PropertyDefinition.EditorTemplate = XamlReader.Parse("<DataTemplate>" +
                                                                    $" <myTelerik:{nameof(CollectionEditorPicker)} {nameof(CollectionEditorPicker.Source)}=\"{{Binding Path={descriptor.Name}}}\"> " +
                                                                        $"<myTelerik:{nameof(CollectionEditorPicker)}.{nameof(CollectionEditorPicker.CommandProvider)}>" +
                                                                            $"<myCommand:{nameof(ValueTypeAddCommandProvider)}/>" +
                                                                        $"</myTelerik:{nameof(CollectionEditorPicker)}.{nameof(CollectionEditorPicker.CommandProvider)}>" +
                                                                    $"</myTelerik:{nameof(CollectionEditorPicker)}>" +
                                                                   "</DataTemplate>", parserContext) as DataTemplate;
        }
    }
}