How do you create a custom collection editor form

2020-02-09 12:14发布

I am trying to incorporate a property grid control 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.

Can anyone point me in the right direction?

And also, how can I go about having setting up a drop down for a property that contains a list of id's to select from if anyone could point me in the direction for accomplishing this as well.

2条回答
beautiful°
2楼-- · 2020-02-09 12:47

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)] // http://stackoverflow.com/questions/3120496/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;
        }   
查看更多
欢心
3楼-- · 2020-02-09 12:49

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.

查看更多
登录 后发表回答