Reputation: 5029
I am making an extension method library to use in windows form applications. One of the methods I intend to create will make setting error states on input controls easier, e.g.
public static void SetError(this System.Windows.Forms.TextBox textBox, string errorMessage)
{
if (string.IsNullOrEmpty(errorMessage))
{
//reset control state
textBox.BackColor = System.Drawing.SystemColors.WindowText;
}
else
{
//set background colour to a nice shade of red
textBox.BackColor = System.Drawing.Color.MistyRose;
}
//try to locate an ErrorProvider on the control's containing form.
var errorProvider = LocateErrorProvider(textBox);
if (errorProvider != null)
{
//set error message on error provider (or clear it)
errorProvider.SetError(textBox, errorMessage);
}
}
I am trying to figure out the LocateErrorProvider
method. What I would like to do is check whether an ErrorProvider exists on my form and then only make use of it if it does exist.
ErrorProvider is a Component
and not a Control
, so I can't get to it via the form.Controls
property. I have tried casting the parent form into a variety of objects, to no avail.
UPDATE: I have managed to get to the ErrorProvider using reflection using the following code:
private static System.Windows.Forms.ErrorProvider GetErrorProvider(System.Windows.Forms.Control control)
{
//get the containing form of the control
var form = control.GetContainerControl();
//use reflection to get to "components" field
var componentField = form.GetType().GetField("components", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (componentField != null)
{
//get the component collection from field
var components = componentField.GetValue(form);
//locate the ErrorProvider within the collection
return (components as System.ComponentModel.IContainer).Components.OfType<System.Windows.Forms.ErrorProvider>().FirstOrDefault();
}
else
{
return null;
}
}
Personally, I'm not too fond of using the hard-coded field name to get to the field. But in this case it seems to work just fine. Does anybody have a better way to achieve the same results?
Upvotes: 3
Views: 2873
Reputation: 41
in VS2005 this works:
private static System.Windows.Forms.ErrorProvider GetErrorProvider(System.Windows.Forms.Control control)
{
try
{
//get the containing form of the control
System.Windows.Forms.IContainerControl form = control.GetContainerControl();
//use reflection to get to "components" field
System.Reflection.FieldInfo componentField = form.GetType().GetField("components", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (componentField != null)
{
//get the component collection from field
object components = componentField.GetValue(form);
object oReturn = null;
//locate the ErrorProvider within the collection
foreach (object o in ((System.ComponentModel.Container)components).Components)
{
if (o.GetType() == typeof(System.Windows.Forms.ErrorProvider))
{
oReturn = o;
break;
}
}
return (ErrorProvider)oReturn;
}
}
catch
{
return null;
}
return null;
}
Upvotes: 1
Reputation: 5029
So far, this seems to solve my problem:
private static System.Windows.Forms.ErrorProvider GetErrorProvider(System.Windows.Forms.Control control)
{
//get the containing form of the control
var form = control.GetContainerControl();
//use reflection to get to "components" field
var componentField = form.GetType().GetField("components", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (componentField != null)
{
//get the component collection from field
var components = componentField.GetValue(form);
//locate the ErrorProvider within the collection
return (components as System.ComponentModel.IContainer).Components.OfType<System.Windows.Forms.ErrorProvider>().FirstOrDefault();
}
else
{
return null;
}
}
Thanks to Hans & Cody for their excellent ideas.
Upvotes: 5
Reputation: 941227
This is what interfaces are designed to do. They enforce a class to implement behavior. The behavior you want here is for a form to have an ErrorProvider. So write an interface like this:
public interface IHasErrorProvider {
ErrorProvider Provider { get; }
}
And have the forms with an error provider implement the interface:
public partial class Form1 : Form, IHasErrorProvider {
public ErrorProvider Provider {
get { return errorProvider1; }
}
// etc..
}
Retrieving the error provider is now simple:
private static ErrorProvider GetErrorProvider(Control control) {
var impl = control.FindForm() as IHasErrorProvider;
return impl != null ? impl.Provider : null;
}
Upvotes: 1