Question

I have a class Foo defined in a library which is used in the GUI project. The GUI project allows graphical editing of an instance of Foo with the help of a System.Windows.Forms.PropertyGrid.

To make editing of an instance of class Foo in a PropertyGrid comfortable, I have to set several attributes to Foo's properties, Browsable for example.

However, I do not want to set up these attributes in Foo because the library it's in should have only the required things needed to use Foo in code (not in GUI).

How can I get a PropertyGrid-friendly version of Foo?

I already tried inheriting from it (naming it FooDesignable) and shadowing its properties with the wanted attributes. However, that didn't work well very long until I discovered that Foo is using other custom classes of the library project which I then also had to shadow, and change the existing properties in Foo to return the XxxDesignable types.

Am I in a dead end here? Or am I just thinking bad about it?

Was it helpful?

Solution

What you could do is reuse the DynamicTypeDescriptor class described in my answer to this question here on SO: PropertyGrid Browsable not found for entity framework created property, how to find it?

like this for example:

public Form1()
{
    InitializeComponent();

    DynamicTypeDescriptor dt = new DynamicTypeDescriptor(typeof(MyBeautifulClass));

    // initialize the class the way you want
    MyBeautifulClass c = new MyBeautifulClass();
    c.MyProperty = "hello world";

    // we need to replace a property by another version, so let's remove the existing one
    dt.RemoveProperty("MyProperty");

    // create a new similar property with a new editor and the current value
    dt.AddProperty(
        typeof(string),            // type
        "MyProperty",              // name
        c.MyProperty,              // value
        "My Property",             // display name 
        "My Property Description", // description
        "My Category",             // category
        false,                     // has default value?
        null,                      // default value
        false,                     // readonly?
        typeof(MyEditor));         // editor 

    // create a wrapped object from the original one.
    // unchanged properties will keep their current value
    var newObject = dt.FromComponent(c);

    // hook on value change
    newObject.PropertyChanged += (sender, e) =>
    {
        // update the original object
        // note: the code could be made more generic
        c.MyProperty = newObject.GetPropertyValue<string>(e.PropertyName, null);
    };

    propertyGrid1.SelectedObject = newObject;
}

public class MyBeautifulClass
{
    public string MyProperty { get; set; }
}

// this stupid sample editor puts a current string in upper case... :-)
public class MyEditor : UITypeEditor
{
    public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
    {
        return UITypeEditorEditStyle.Modal;
    }

    public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
    {
        return value == null ? value : value.ToString().ToUpper();
    }
}

OTHER TIPS

I think you have the right idea to make another type, but FooDesigner should be a wrapper, not inherit from Foo. That way you will be able to wrap the complex objects in their own wrapper types. This may get tedious if you have a lot classes to wrap. You may want to look at T4 Templates to help generating skeletons for the wrapper classes. Here's an example:

class FooDesigner
{
     private Foo foo;

     public FooDesigner(Foo foo)
     {
         this.foo = foo;
     }

     public int Prop1 
     { 
         get { return foo.Prop1; } 
         set { foo.Prop1 = value; } 
     }

     public BarDesigner Bar { get { return new BarDesigner(foo.Bar); } }
}

class BarDesigner
{
     private Bar bar;
     public BarDesigner(Bar bar) 
     { 
         this.bar = bar;
     }

     public string Prop2 
     { 
         get { return bar.Prop2; } 
         set { bar.Prop2 = value; } 
     }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top