I use a PropertyGrid to show a business object in my application. The business object throws exceptions if the user tries to enter an invalid string inside the PropertyGrid. The PropertyGrid shows two different behaviors in this case:
- If a default TypeConverter is used the PropertyGrid shows an builtin error message dialog.
- If a custom TypeConverter is used the PropertyGrid doesn't handle the exception. This happens only in Debug mode.
How can I catch these exceptions and suppress the builtin error message dialog of the PropertyGrid

Additional Infos: PropertyGrid: How to catch an exception?
sennekeennes
I used the IServiceProvider/IUIService method to show a custom error dialog to the user in a PropertyGrid in .NET 2.0. Below you will find a generic example of what I did...
1. I created MyUIService, which implements IUIService:
internal class MyUIService : IUIService
{
private PropertyGrid propertyGrid;
internal MyUIService(PropertyGrid grid)
{
this.propertyGrid = grid;
}
public bool CanShowComponentEditor(object component)
{
throw new NotImplementedException("The method or operation is not implemented.");
}
public IWin32Window GetDialogOwnerWindow()
{
throw new NotImplementedException("The method or operation is not implemented.");
}
public void SetUIDirty()
{
throw new NotImplementedException("The method or operation is not implemented.");
}
public bool ShowComponentEditor(object component, IWin32Window parent)
{
throw new NotImplementedException("The method or operation is not implemented.");
}
public DialogResult ShowDialog(Form form)
{
PropertyDescriptor property = this.propertyGrid.SelectedGridItem.PropertyDescriptor;
// extract the error details from the GridErrorDlg instance
FieldInfo detailsTextBoxField = form.GetType().GetField("details", BindingFlags.NonPublic | BindingFlags.Instance);
TextBox detailsTextBox = detailsTextBoxField.GetValue(form) as TextBox;
return MessageBox.Show(this.propertyGrid,
string.Format(CultureInfo.InvariantCulture,
"{0}{1}{1}{2}",
detailsTextBox.Text,
Environment.NewLine,
"You may select Cancel to use the previous valid value."),
property.DisplayName,
MessageBoxButtons.OKCancel,
MessageBoxIcon.Warning);
}
public void ShowError(Exception ex, string message)
{
throw new NotImplementedException("The method or operation is not implemented.");
}
public void ShowError(Exception ex)
{
throw new NotImplementedException("The method or operation is not implemented.");
}
public void ShowError(string message)
{
throw new NotImplementedException("The method or operation is not implemented.");
}
public DialogResult ShowMessage(string message, string caption, MessageBoxButtons buttons)
{
throw new NotImplementedException("The method or operation is not implemented.");
}
public void ShowMessage(string message, string caption)
{
throw new NotImplementedException("The method or operation is not implemented.");
}
public void ShowMessage(string message)
{
throw new NotImplementedException("The method or operation is not implemented.");
}
public bool ShowToolWindow(Guid toolWindow)
{
throw new NotImplementedException("The method or operation is not implemented.");
}
public IDictionary Styles
{
get
{
throw new NotImplementedException("The method or operation is not implemented.");
}
}
}
2. I created MyServiceProvider, which implements IServiceProvider:
internal class MyServiceProvider : IServiceProvider{
private MyUIService service;
internal MyServiceProvider(PropertyGrid grid)
{
this.service = new MyUIService(grid);
}
public object GetService(Type serviceType)
{
if (serviceType == typeof(IUIService))
{
return this.service;
}
return null;
}
}
3. I used reflection to set the IServiceProvider instance on a PropertyGrid:
foreach (Control c in propertyGrid.Controls)
{
if(string.Compare(c.GetType().FullName, "System.Windows.Forms.PropertyGridInternal.PropertyGridView", true, CultureInfo.InvariantCulture) == 0)
{
// add a custom service provider to give us control over the property value error dialog shown to the user
FieldInfo errorDialogField = c.GetType().GetField("serviceProvider", BindingFlags.Instance | BindingFlags.NonPublic);
errorDialogField.SetValue(c, new MyServiceProvider(propertyGrid));
}
}
I hope that helps you. If not, I'm sure someone else will find it useful.
-Jason
DevDiver
Here is the updated MyUIService class. I also forgot to mention that ShowDialog(Form) gets called to display the Collection Editor. As a result, I updated the ShowDialog(Form) method to handle those calls.
internal class MyUIService : IUIService
{
private PropertyGrid propertyGrid;
private IDictionary styles;
internal MyUIService(PropertyGrid grid)
{
this.propertyGrid = grid;
this.styles = new Hashtable();
}
public bool CanShowComponentEditor(object component)
{ // return value doesn't appear to matter
return false;
}
public IWin32Window GetDialogOwnerWindow()
{
return this.propertyGrid;
}
public void SetUIDirty()
{
throw new NotImplementedException();
}
public bool ShowComponentEditor(object component, IWin32Window parent)
{
throw new NotImplementedException();
}
public DialogResult ShowDialog(Form form)
{
if (form != null)
{
if (string.Compare(form.GetType().FullName, "System.Windows.Forms.PropertyGridInternal.GridErrorDlg", true, CultureInfo.InvariantCulture) == 0)
{ // show custom error message dialog
DynamicProperty property = this.propertyGrid.SelectedGridItem.PropertyDescriptor as DynamicProperty;
FieldInfo detailsTextBoxField = form.GetType().GetField("details", BindingFlags.NonPublic | BindingFlags.Instance);
TextBox detailsTextBox = detailsTextBoxField.GetValue(form) as TextBox;
return MessageBox.Show(this.propertyGrid,
string.Format(CultureInfo.InvariantCulture, "{0}{1}{1}{2}", detailsTextBox.Text, Environment.NewLine, "Select Cancel to revert to the previously valid value."),
property.Name.Trim(),
MessageBoxButtons.OKCancel,
MessageBoxIcon.Warning);
}
else
{ // show collection editor
return form.ShowDialog(this.propertyGrid);
}
}
return DialogResult.Cancel;
}
public void ShowError(Exception ex, string message)
{
throw new NotImplementedException();
}
public void ShowError(Exception ex)
{
throw new NotImplementedException();
}
public void ShowError(string message)
{
throw new NotImplementedException();
}
public DialogResult ShowMessage(string message, string caption, MessageBoxButtons buttons)
{
throw new NotImplementedException();
}
public void ShowMessage(string message, string caption)
{
throw new NotImplementedException();
}
public void ShowMessage(string message)
{
throw new NotImplementedException();
}
public bool ShowToolWindow(Guid toolWindow)
{
throw new NotImplementedException();
}
public IDictionary Styles
{
get
{
return this.styles;
}
}
}
Vladimir Chtepa
Will add it to the PropertyGrid Resource List.
Best regards,
Nicolas Cadilhac
Smart PropertyGrid.Net @ VisualHint
Microsoft PropertyGrid Resource List
Free PropertyGrid for MFC
Penicillin
MA2005
Labm1ce
Thanks.
Please note that this specific implementation will not work with the Collection Editor; however, it can be made to work by modifying the Styles property and the CanShowComponentEditor(object) method. MyUIService will need to return an empty Hashtable (or something else that implements IDictionary) from the Styles property and true or false (it doesn't appear to matter) from the CanShowComponentEditor(object) method.
mschelstrate
SoniqStylz
The exception thrown by the PropertyGrid looks like this:
System.Exception was unhandled by user code
"r is not a valid value for Double."Message=
Source="System"
StackTrace:
at System.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
at System.ComponentModel.TypeConverter.ConvertFromString(ITypeDescriptorContext context, String text)
at System.Windows.Forms.PropertyGridInternal.GridEntry.ConvertTextToValue(String text)
at System.Windows.Forms.PropertyGridInternal.PropertyGridView.CommitText(String text)
The PropertyGridView.CommitText method catch this exception and calls the ShowDialog(Form) method of the IUIService. I tried to set my own IUIService to the PropertyGrid.
class
MyPropertyGrid : PropertyGrid{
protected override object GetService(Type service)
{
if (service == typeof(IUIService))
{
object obj = new UIServiceTestDesigner();
return obj;
}
return base.GetService(service);
}
}
But this didn't worked. The UIServiceTestDesigner.ShowDialog(Form) was never called by the PropertyGrid.
How can I use my own custom error handling in combination with the PropertyGrid
AlterEgo
Above Code not working when you copy the value and paste in to Property Grid using Clipboard Operations.
Can you tell me why is it so
Regards
Varun Garg