Sign in to follow this  
Spodi

[.net] Exceptions in custom TypeConverter with PropertyGrid

Recommended Posts

I wrote a TypeConverter to handle a custom type of mine, which is basically just a specialized Int32. The TypeConverter works just fine, but the problem is that any Exception I throw (or gets thrown) during the conversion process (namely in the ConvertFrom override), while in the IDE, ends up throwing like any other exception. That is, it stops the application, breaks to the code, and brings up the exception dialog. Even when I have a near-exact copy of the Int32Converter code (as seen from Reflector), this still happens. But if I change the TypeCoverter for this custom type of mine from my own implementation to the Int32Converter, it works just fine. If an exception is thrown during the conversion, it displays the "Ok/Cancel" dialog instead of bringing down the application. Not only that, but my custom TypeConverter, too, works just fine when run from outside the IDE, behaving just like the Int32Converter or any other converter does with the PropertyGrid. So, I'm under the assumption that the exception handler is popping up because its coming from code. This is cool and all, and how I want the IDE to behave with everything except the PropertyGrid. Is there any way, without changing my solution structure or messing with the exception handling for the rest of my project, to have the PropertyGrid show the "Ok/Cancel" dialog no matter where the exception is coming from? Here is a simple example scenario. Just throw this code into the form of a new WindowsFormApplication and delete everything else.
using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows.Forms;

namespace WindowsFormsApplication2
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }

    #region Designer stuff

    partial class Form1
    {
        readonly IContainer components = null;

        PropertyGrid pg;

        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
                components.Dispose();
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        void InitializeComponent()
        {
            this.pg = new System.Windows.Forms.PropertyGrid();
            this.SuspendLayout();
            this.pg.Location = new System.Drawing.Point(12, 12);
            this.pg.Name = "pg";
            this.pg.Size = new System.Drawing.Size(260, 240);
            this.pg.TabIndex = 0;
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(284, 264);
            this.Controls.Add(this.pg);
            this.Name = "Form1";
            this.Text = "Form1";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.ResumeLayout(false);
        }

        #endregion
    }

    #endregion

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        void Form1_Load(object sender, EventArgs e)
        {
            pg.SelectedObject = new TestClass();
        }
    }

    [TypeConverter(typeof(MyCustomStructConverter))]
    public struct MyCustomStruct
    {
        readonly int _value;

        public MyCustomStruct(int i)
        {
            _value = i;
        }

        public override string ToString()
        {
            return _value.ToString();
        }

        public static implicit operator int(MyCustomStruct v)
        {
            return v._value;
        }

        public static implicit operator MyCustomStruct(int v)
        {
            return new MyCustomStruct(v);
        }
    }

    public class MyCustomStructConverter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType == typeof(string))
                return true;

            return base.CanConvertFrom(context, sourceType);
        }

        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType == typeof(string))
                return true;

            return base.CanConvertTo(context, destinationType);
        }

        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            if (value is string)
                return new MyCustomStruct(int.Parse((string)value));

            return base.ConvertFrom(context, culture, value);
        }

        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(string))
                return value.ToString();

            return base.ConvertTo(context, culture, value, destinationType);
        }
    }

    public class TestClass
    {
        public MyCustomStruct A { get; set; }
        public MyCustomStruct B { get; set; }
    }
}

Share this post


Link to post
Share on other sites
I can see two different ways of getting around this. First, simply move your type converters out into a separate DLL which you don't contain within the project you're working on. It's not the prettiest solution, but should be quick and require few code changes.

For the second option, you create your own custom exception, catch all exceptions inside your type converter, and then rethrow your custom exception instead (probably with the original as an InnerException). Then, go up to the Debug->Exceptions dialog and add your custom exception as a new filter, and uncheck all the options from it. I know you said you didn't want to mess with exception options, but if you only use this new custom exception in the one spot, it shouldn't affect anything else in your project.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this