Create a custom CollectionEditor Form for use with the PropertyGrid?
Asked Answered
A

2

10

I am trying to incorporate a PropertyGrid control based off of the CollectionEditor class and Form, with a class that has a list/collection of another class as one of the properties. Lets call them class A and the list would be containing class B for reference.

I was wanting to incorporate a form that had two list boxes. The list box on the left would contain a list of all of class B's in my program that are not currently in the list on the right. The list on the right would contain all of the class B's that are currently associated with class A. I want buttons in between to move items between the two lists.

This would be easy to design, but I'm not sure exactly how to set up the form to be used as the collection editor.

Arianaariane answered 23/9, 2011 at 13:54 Comment(4)
Any ideas how to set a form as the collection editor form?Arianaariane
Cross-linking to a related question: Is there a PropertyGrid Collection Editor "Add" button event or override?Biotite
Another one relating to custom collection editors: Set position for custom CollectionEditor form in WinFormsBiotite
Another: How to enable Default Values for properties in a 'CollectionEditor' dialogBiotite
A
18

Okay, I was finally able to track down how to accomplish this.

I was attempting to create a custom CollectionEditor.CollectionForm which was close to what I needed to do, but it wasn't quite the right direction.

First of all, create a regular Windows Form which includes your GUI for editing your collection. Then just include button/buttons which return a DialogResult in the Form.

Now the key to accomplishing what I was looking for is not a CollectionEditor.CollectionForm as I had thought would be the correct approach, but rather a UITypeEditor.

So, I created a class that inherited from the UITypeEditor. Then you simply flesh it out as such:

public class CustomCollectionModalEditor: UITypeEditor
{
    public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
    {
        if (context ==null || context.Instance == null)                
            return base.GetEditStyle(context);

        return UITypeEditorEditStyle.Modal;
    }

    public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
    {
        IWindowsFormsEditorService editorService;

        if (context == null || context.Instance == null || provider == null)
            return value;

        editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));

        CForm CollectionEditor = new CForm();

        if (editorService.ShowDialog(CollectionEditor) == System.Windows.Forms.DialogResult.OK)
            return CollectionEditor.Programmed;

        return value;
        //return base.EditValue(context, provider, value);
    }
}

The key parts to take note of, are the functions GetEditStyle and EditValue. The part responsible for firing-off the Form you created to edit your collection, is in the EditValue override function.

CForm is the custom collection editor form I designed in this test to edit the collection. You need to fetch the IWindowsFormsEditorService associated with the IServiceProvider and simply call the .ShowDialog(formVariable) of the IWindowsFormsEditorService in order to show the form you designed to edit the collection. You can then catch the returned DialogResult value from your Form and perform any custom handling that you require.

I hope this helps someone out as it took me quite a bit of digging to determine the right way to incorporate this.

Arianaariane answered 27/9, 2011 at 13:28 Comment(5)
15 months later, I found your effort here very useful. Thanks!Eschalot
This works great for a quick and dirty toy project I was working on.Arriaga
2 and a half years later and this still helped me out. Although, how do I get my existing collection into the created form!Breeden
Looks nice, how to use this in a custom control ?Fabiano
Can you explain more why the CollectionForm or CollectionEditor were not the solutions for you? The CollectionEditor inherits directly from UITypeEditor and gives you the extra structure and functionality available in it. Microsoft even seems to encourage in the article for developers to inherit from it. This answer also delves into modifying the control directly in code, although I'd prefer it if we could edit from the Designer.Biotite
T
-1

This answers Brandon's question. I too searched long and hard on how to actually replace the default propertygrid collection editor. Nathan's answer was the final solution. Brandon here is how I was able to use Nathan's solution and use my own collection editor.

using Swfd = System.Windows.Forms.Design;
using Scm = System.ComponentModel; 
using Sdd = System.Drawing.Design;
public class CustomCollectionModalEditor : Sdd.UITypeEditor
{
public override Sdd.UITypeEditorEditStyle GetEditStyle(Scm.ITypeDescriptorContext context)
{
    if (context == null || context.Instance == null)
    return base.GetEditStyle(context);

    return Sdd.UITypeEditorEditStyle.Modal;
}

public override object EditValue(Scm.ITypeDescriptorContext context, IServiceProvider provider, object value)
{
    Swfd.IWindowsFormsEditorService editorService;

    if (context == null || context.Instance == null || provider == null)
    return value;

    editorService = (Swfd.IWindowsFormsEditorService)provider.GetService(typeof(Swfd.IWindowsFormsEditorService));

    //CForm CollectionEditor = new CForm();
    //---  Replaced the Collection from this post with mine which requires an argument that passes the collection
    Ccne.CustomCollection editgcp = new Ccne.CustomCollection();  // Ccne.CustomCollection is my collection
    editgcp = MYGCPS;  // MYGCPS is the actual instance to be edited

    Gcp_Editor.GcpEditorMain CollectionEditor = new Gcp_Editor.GcpEditorMain(editgcp);  // call my editor 

    if (editorService.ShowDialog(CollectionEditor) == System.Windows.Forms.DialogResult.OK)
    {
    MYGCPS = CollectionEditor.ReturnValue1; // update current instance of the collection with the returned edited collection
    THISPG.Refresh();  // calls a method which refreshes the property grid
    return value; // the replaces the statment in the post >> CollectionEditor.Programmed;
    }
    //---
    return value;

    //return base.EditValue(context, provider, value);
}
}


//---------- The propertygrid entry
private Ccne.CustomCollection gCPs; 

[Scm.Category("3 - Optional inputs to run gdal_translate")]
[PropertyOrder(133)]
[Scm.TypeConverter(typeof(Ccne.CustomCollectionConverter))]
[Scm.Editor(typeof(CustomCollectionModalEditor), typeof(Sdd.UITypeEditor))]
[Scm.Description("The Collection of the single or multiple Ground Control Points (Gcp)" +
" entered. \n Each gcp requires a Name, pixel, line, easting, " +
"northing, and optionally an elevation")]
[Scm.RefreshProperties(Scm.RefreshProperties.All)] // https://mcmap.net/q/827726/-updating-a-propertygrid
[Scm.DisplayName("23 Collection of Gcp's")]
[Scm.ReadOnly(true)]                   // prevents values being changed without validation provided by form
public Ccne.CustomCollection GCPs
{
get { return gCPs; }
set { gCPs = value; }
}

//-------- important code from CollectionEditor i.e. > Gcp_Editor.GcpEditorMain(editgcp)
using Swf = System.Windows.Forms;
namespace Gcp_Editor
{
    public partial class GcpEditorMain : Swf.Form
    {
        public Ccne.CustomCollection ReturnValue1 { get; set; }
        ...
        public GcpEditorMain(Ccne.CustomCollection input1)
        {
                InitializeComponent();
                formcollection = input1;
        }
        ...
        private void OkayBtn_Click(object sender, EventArgs e)
        {
            this.DialogResult = Swf.DialogResult.OK;
            ReturnValue1 = formcollection;
            return;
        }   
Tapioca answered 16/2, 2016 at 20:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.