Search code examples
c#uitypeeditor

How to add an existing control in another on properties panel at design time using C# WindowsFormApplication


I have custom controls: CustomControlOne, CustomControlTwo.

My CustomControlOne has a List<CustomControlTwo> showed in your properties panel of my windows form application project:

Properties Panel of CustomControlOne

So when I click in the button, a window to add new items in this collection is opened:

CustomControlTwo collection

But, I want add existing CustomControlTwo items that are defined in MyForm. ps.: MyForm contains CustomControlOne and multiple CustomControlTwo.

I want this items can be added in design time, like same way that selecting an item in a comboBox (in CustomControlOne properties panel). When I change List<CustomControlTwo> to ICollection<CustomControlTwo> a comboBox is showed but the items of type CustomControlTwo not appears :(

How I can do this ? How I can say to my CustomControlOne where are the CustomControlTwo items ? Thx.


UPDATE:

I wrote my own UITypeEditor and I reached my goal with help of @Sefe and with THIS link. Bellow my code:

public class CollectionTypeEditor : UITypeEditor {

private IWindowsFormsEditorService _editorService = null;
private ICollection<Control> mControls = null;
private List<Control> mPickedControls = null;

// Editor like Modal style
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) {
  return UITypeEditorEditStyle.Modal;
}

// Opens modal and get returned data
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) {
  if (provider == null)
    return value;

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

  if (_editorService == null)
    return value;

  mControls = new List<Control>();

  // retrieve old data
  mPickedControls = value as List<Control>;
  if (mPickedControls == null)
    mPickedControls = new List<Control>();

  // getting existent controls that will be inflated in modal
  Control mContext = (Control) context.Instance;
  GetControls(mContext);

  // open form and get response
  CollectionDesign<Control> frmCollections = new CollectionDesign<Control>(mControls, ref mPickedControls);
  var response = _editorService.ShowDialog(frmCollections);

  // returning data from editor
  return response == DialogResult.OK ? mPickedControls : value;
}

Everything works well here. Now, my variable in properties panel:

[Editor(typeof(CollectionTypeEditor), typeof(UITypeEditor))]
[TypeConverter(typeof(ActionButtonConverter))]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public List<Control> ActionButtons { get; set; }

The serialization attribute was added because the file couldn't be saved. When form is closed and reopened, all data are lost.

The stranger thing is that I wrote other UITypeEditor like the same way, just changing type of data to string and I can close or reopen my form and all works fine, the data are saved.

I already added a TypeConverter but I think that isn't case here. what is wrong with my code?

My basic setup: My basic setup

In this setup, BaseForm extends Form. With string works, but with List data are lost on close form or build project...

Resumed workflow:

    1 - Open MyForm.
    2 - Click at ActionButtons ellipsis [...] (inherited by BaseForm) on MyForm properties panel.
    3 - A custom form is opened with inflated objects that I want pick.
    4 - Objects that I want are picked and I close form. So now, data is ok cause I can reopen that form and see objects that I picked.
    5 - Now when close the MyForm and reopen it, all data are lost. The same thing happens when build the project. But if I do all this steps with a string, all are Ok (data are saved).

Thanks all, and sorry for bad language :P


Solution

  • If you want to add multiple CustomControlTwo items to your control, a drop down list will do you no good, since you can only select one value there.

    If you are able to change the property to accept a single instance of CustomControlTwo (or are OK that the list you can create in your property browser has only one item), you can create a new System.ComponentModel.TypeConverter that will create the list to select from. A type converter is an abstract class and you will have to implement a couple of abstract methods. The methods that are valuable to you are GetStandardValuesSupported, GetStandardValuesExclusive and GetStandardValues. Here is the part that is interesting to you (you have to add the other methods):

    public class CustomControlOneConverter : TypeConverter {
        public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
        {
            //By returning true, you tell the property designer to add a drop down list
            return true;
        }
    
        public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
        {
            //By returning true, you tell the property designer to not allow the user to enter his own text
            return true;
        }
    
    
        public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
        {
            //Get all objects of type CustomControlTwo from the container
            CustomControlTwo[] controlsToList =
                context.Container.Components.OfType<CustomControlTwo>().ToArray;
    
            //Return a collection of the controls
            return new StandardValuesCollection(controlsToList);
        }
    
        //implement the other abstract methods
    }
    

    What you do in GetStandardValues is to search in the container of CustomControlOne, if there are instances of CustomControlTwo. Those are then added to the list of standard values to select from in the property browser.

    If you are not able to change your property to select only one CustomControlTwo, you will need to create your own UI to display when the ellipsis (...) is clicked in your property window. For that you need to create your own UITypeEditor. That, however is a more complex undertaking and is not easily explained in a nutshell.