Introduction
To better understand the problem, run the demo app included as a download to this post. When you hover over the Microsoft error provider, the error message is displayed. Next, click the mouse and the error message goes away. When you move the mouse off the error provider icon and return it will not re-appear.
I have discovered that setting a control's error message to "" and then resetting it, will allow the error message to be re-displayed (the trick*).
The ErrorProviderFixed
implementation, which follows, is a simple extension of the ErrorProvider
. It looks at the ErrorProvider
’s private
member Windows
and registers it with our own NativeWindow
implementation, allowing us monitor its WinProc
messages. When we need to, we reset the error provider messages (re: *the trick).
Note: “*the trick” as explained above re-enables the messages so that they display, but causes a slight flicker. I would much prefer it if Microsoft could fix this bug.
Usage
To replace the Microsoft ErrorProvider
with ErrorProviderFixed
, all you need to do is include the following code in your project in a file such as ErrorProviderFixed.cs.
Then, replace all instances of System.Windows.Forms.ErrorProvider
with ErrorProviderFixed
.
ErrorProviderFixed Code
public class ErrorProviderFixed : ErrorProvider
{
ErrorProviderFixManager mToolTipFix = null;
public ErrorProviderFixed()
: base()
{
mToolTipFix = new ErrorProviderFixManager(this);
}
public ErrorProviderFixed(ContainerControl parentControl)
: base(parentControl)
{
mToolTipFix = new ErrorProviderFixManager(this);
}
public ErrorProviderFixed(IContainer container)
: base(container)
{
mToolTipFix = new ErrorProviderFixManager(this);
}
protected override void Dispose(bool disposing)
{
mToolTipFix.Dispose();
base.Dispose(disposing);
}
}
public class ErrorProviderFixManager : IDisposable
{
private ErrorProvider mTheErrorProvider = null;
private Timer mTmrCheckHandelsProc = null;
private Hashtable mHashOfNativeWindows = new Hashtable();
public void Dispose()
{
mTmrCheckHandelsProc.Stop();
mTmrCheckHandelsProc.Dispose();
mTmrCheckHandelsProc = null;
}
public ErrorProviderFixManager(ErrorProvider ep)
{
mTheErrorProvider = ep;
mTmrCheckHandelsProc = new Timer();
mTmrCheckHandelsProc.Enabled = true;
mTmrCheckHandelsProc.Interval = 1000;
mTmrCheckHandelsProc.Tick += new EventHandler(tmr_CheckHandels);
}
private void RefreshProviderErrors()
{
Hashtable hashRes = (Hashtable)GetFieldValue(mTheErrorProvider, "items");
foreach (Control control in hashRes.Keys)
{
if (hashRes[control] == null)
{
break;
}
if (!(bool)GetFieldValue(hashRes[control], "toolTipShown"))
{
if (mTheErrorProvider.GetError(control) != null &&
mTheErrorProvider.GetError(control).Length > 0)
{
string str = mTheErrorProvider.GetError(control);
ErrorBlinkStyle prev = mTheErrorProvider.BlinkStyle;
mTheErrorProvider.BlinkStyle = ErrorBlinkStyle.NeverBlink;
mTheErrorProvider.SetError(control, "");
mTheErrorProvider.SetError(control, str);
mTheErrorProvider.BlinkStyle = prev;
}
}
}
}
void tmr_CheckHandels(object sender, EventArgs e)
{
if (mTheErrorProvider.ContainerControl == null)
{
return;
}
if (mTheErrorProvider.ContainerControl.Visible)
{
Hashtable hashRes =
(Hashtable)GetFieldValue(mTheErrorProvider, "windows");
if (hashRes.Count > 0)
{
foreach (Object obj in hashRes.Keys)
{
ErrorProviderNativeWindowHook hook = null;
if (mHashOfNativeWindows.Contains(obj))
{
hook = (ErrorProviderNativeWindowHook)
mHashOfNativeWindows[obj];
}
else
{
hook = new ErrorProviderNativeWindowHook();
mHashOfNativeWindows[obj] = hook;
}
NativeWindow nativeWindow = GetFieldValue(hashRes[obj],
"tipWindow") as NativeWindow;
if (nativeWindow != null && hook.Handle == IntPtr.Zero)
{
hook.AssignHandle(nativeWindow.Handle);
}
}
}
foreach (ErrorProviderNativeWindowHook hook
in mHashOfNativeWindows.Values)
{
if (hook.mBlnTrigerRefresh)
{
hook.mBlnTrigerRefresh = false;
RefreshProviderErrors();
}
}
}
}
private object GetFieldValue(object instance, string name)
{
if (instance == null) return null;
FieldInfo fInfo = null;
Type type = instance.GetType();
while (fInfo == null && type != null)
{
fInfo = type.GetField(name,
System.Reflection.BindingFlags.FlattenHierarchy |
System.Reflection.BindingFlags.NonPublic |
BindingFlags.Instance);
type = type.BaseType;
}
if (fInfo == null)
{
}
return fInfo.GetValue(instance);
}
}
public class ErrorProviderNativeWindowHook : NativeWindow
{
private int mInt407Count = 0;
internal bool mBlnTrigerRefresh = false;
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x407)
{
mInt407Count++;
if (mInt407Count > 3)
{
this.ReleaseHandle();
mBlnTrigerRefresh = true;
}
}
else
{
mInt407Count = 0;
}
base.WndProc(ref m);
}
}
}
History
- 10th January, 2007: Initial post
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.