Strange/Unpredictable Transparent Background Bug In Winforms Application - c#

I've been experiencing a very strange bug with a Winforms application, where showing a hidden form may result in that form's buttons & backgrounds coming up transparent. Buttons can be subsequently revealed by moving the mouse over them, as if the form hadn't been properly invalidated/drawn. For instance, a form that looks like this:
May come up like this:
Moving the mouse around causes the buttons to draw:
Here's a short video to show exactly how it behaves: http://screencast.com/t/XmFSPfLw. Explicitly calling Invalidate() or Refresh() in the Show event doesn't fix it.
What's strange is that this issue appears only on SOME computers, and I haven't been able to discern anything that those computers have in common.
I've seen it happen in different versions of Windows 7 (Embedded, x64, and x86) - but not all instances of any of those.
All systems are running the same version of .NET, and all have been fully updated.
On systems where it happens, it only happens when showing a form that'd been previously shown & hidden; it occurs when re-showing it (i.e. never the very first time the form is created & shown).
On systems where it happens, it doesn't happen for all forms, and isn't even consistent with the forms for which it happens (example of several subsequent hides/shows, sometimes it happens, sometimes it doesn't: http://screencast.com/t/liQ53p8Sce).
On systems where it happens, it only happens if the application is scaled to the full resolution of the screen. I use Control.Scale() to scale each form up to a user-specified resolution; if that's the same as the screen resolution, the bug may happen on some systems; if it's scaled up to anything less, I've never seen it happen (example: here's the same video as the first one above; with the form scaled to less than the full screen resolution, it doesn't happen: http://screencast.com/t/k87zJDeSYPGL).
I've been tearing my hair out trying to figure out what's different about the systems that exhibit the issue, and why it's happening in the first place. I literally had to have a client ship me a laptop that shows the issue, as I couldn't reproduce it on any systems I have here. I'm really at a loss as to the cause...

Related

FromLogFont is extremely slow

I have a simple WinForms window in which the user can modify their user settings.
Sometimes (but not always) the app appears frozen while the window takes many seconds to open.
The Form contains a single TextBox.
After profiling I found that up to 19 seconds are spent in the constructor of this textbox,
specifically in System.Drawing.Font.FromLogFont.
https://learn.microsoft.com/en-us/dotnet/api/system.drawing.font.fromlogfont?view=dotnet-plat-ext-7.0
A GDI LOGFONT, or logical font, is a structure that contains 14 properties that describe a particular font.
I have tried using a different or the default font, but the problem seems very arbitrary, sometimes the window opens in less than a second, sometimes it makes you wait for half a minute.
This is about as far as I got with profiling, what are ways to further debug this problem?
I tried using different fonts, or the default fonts. The problem is sometimes there, sometimes not.
The expected result is that the window opens seemingly instantly, not making the user wait.

Promoting a NotifyIcon from overflow area without showing a balloon tip

I'm working on a WPF/.NET 4 app that lives in the system tray and periodically shows messages to the user.
I would like to have my NotifyIcon promoted from the overflow area of the system tray to the visible portion each time there is a message. This works fine if I call 'ShowBalloonTip' on my NotifyIcon; however, I don't wish to use the standard OS balloons (I have a custom control for this, which supports multiple instances and custom animations).
Is it possible? It doesn't seem to allow showing an empty/invisible balloon, and disposing/re-adding the icon does not have the intended effect. I wonder if I should look into creating a secondary tray icon each time I have a message (like the Outlook 'new mail' icon) and removing it when my message fades away.
This is not possible. A significant problem with the notification area is that every programmer thinks that his app is important enough to be next to the clock. Modesty is not a programmer's trait and that's a good thing.
The user however sets different priorities. He's liable to run more than three apps that all think they should have the exalted location. This got really out of hand, I've seen screenshots of Win98 machines where 75% of the taskbar was covered with Important Programs.
This was not sustainable and Microsoft did something about it. They added the overflow area to provide a home for notification icons that the user doesn't think are all that important. Being a computer user myself, it is very quickly populated with whatever shovelware icons come with a new machine I purchase. From there, the rate I uninstall this stuff is inversely proportional to the number of times it balloons me with completely useless or inscrutable info. The only ones that ever really survive are the ones that never show a balloon.
A core feature of the overflow area is that programs cannot do anything to elevate themselves back next to the clock. That would completely defeat the point of having it. Other than showing a balloon, the user needs to know where it came from. That better be something meaningful and relevant to the user. If it is not then your uninstaller is the part of your product that gets tested most.
You are a computer yourself and have battled annoying notify icons too. Apply the exact same logic to your own. And don't forget to ask somebody else what they think about yours. And if your notifications are useful enough, this just takes care of itself. Your user will move it back. Because that's what he can do.

Winforms application stops drawing but remains reactive to events

We have a C# .NET 3.5 UI client application that runs in a multiple monitor desktop environment (typically 4 screens) on Windows 7. Every so often, after running several of these applications, the screen stops redrawing.
Controls continue to be reactive to clicks or keypress and values can be updated programmatically, but the entire form is not redrawn to reflect any changes. For example buttons that are enabled/disabled based on state may be remain grayed out, but be reactive to clicks or vice versa. Buttons do not animate when clicked.
Workaround: minimizing and restoring the window appears to clear the problem. After this, the application begins to draw correctly.
The must frustrating aspect of this problem is that programmatically, everything appears to be running normally. No exceptions are caught in our logs. Nothing was visible in the system event logs. We have not found a way to detect this condition is happening yet.
Other miscellaneous aspects: logging uses log4net, server communication layer uses ZMQ
Update:
Calling form Invalidate() and Update() does not fix the problem.
When dragging the window between screens, it shows different values on each screen.
Minimize/restore still resolves the issue.
I can't be sure of anything without seeing the app and the code, but my best guess is someone calls .SuspendLayout() before a complicated update, and an exception (probably swallowed) prevents the code from ever reaching the corresponding .ResumeLayout(). To test this, try adding a button that calls .ResumeLayout() for the form.
It seems the solution is there:
1) http://blogs.msdn.com/b/alejacma/archive/2009/08/11/controls-won-t-get-resized-once-the-nesting-hierarchy-of-windows-exceeds-a-certain-depth-x64.aspx
2) http://support.microsoft.com/kb/2664641/en-us

Winform SplitContainers redraw issue

I have added a SplitContainer inside another SplitContainer's Panel. Everything redraws fine when the splitters move. But resize of inner SplitContainer doesn't work correctly if the main SplitConainer's size changed by the main form's maximize/restore buttons.
If I move the splitter it redraws everything fine. I tried Invalidating everything in each SplitPanel SizeChanged event, but no luck. Do you have any idea?
I think this is the cause. The issue was gone after simplifying the complex layout into several simple layouts.
http://social.msdn.microsoft.com/forums/en-US/windowsuidevelopment/thread/25181bd5-394d-4b94-a6ef-06e3e4287527/
A little investigation showed that Windows stops sending WM_SIZE when it reaches some certain nesting level. In other words, it won't send WM_SIZE to your child windows if you try to resize them when you process WM_SIZE in the parent ones. Depending on the USER stuff/updates/serivice packs the maximum nesting level at which it stops propagating WM_SIZE may vary from 15 to 31 and even much higher (effectively unreachable) under latest XP 32bit/sp2.
But it still too little under XP x64 and still some similar ugly things happen to other messages under some builds of Vista.
So it is certainly a Windows bug.

Animated gif on button stops after moving (redrawing) the form

I have an animated gif placed on the button. It's animating ok (most of the times :P) but when the windows is redrawn (repainted) the animation stops. I have tried to refresh the button (button.Refresh() ) while handling Paint event but it didn't solve the issue. \
Anyone knows how to fix this?
Perhaps I am mistaken, but I think the issue is that it stops animating not when the form is redrawn, but when the animated object is obscured by another window. This is intended behavior; the bug is that in Windows Vista and Windows 7, the display is composited, so even though the window was 'obscured' it was never truly obscured, and it will never receive paint messages when un-obscured which will kick the animation back in.
This bug appears to affect any ButtonBase-derived control with an animated object.
The issue is the Control.IsWindowObscured function. It will return true. You can see in the ButtonBase.cs file, at System.Windows.Forms.ButtonBase.OnFrameChanged, there is a line of code at the very end that says:
if (IsWindowObscured) {
StopAnimate();
return;
}
and therein lies the problem.
FYI, OnFrameChanged is called from the ImageAnimator thread. This is the callback that is specified in ImageAnimator.Animate(image, eventhandler). ButtonBase sets this up in the private void Animate(bool animate) function. The ImageAnimator thread polls every 50ms and checks to see if a new frame is necessary for any of the images it is monitoring; if so, it sets a flag to have the control invalidated and the new frame drawn.
Since this is inaccessible to us, I don't think there is much we can do about it. As a workaround, I implemented a timer in my form that invalidates the control every 500ms, so it will force it to restart if it had previously stopped. It is quite annoying that we can't override or even access it. I'm afraid the only solution is the hack above, or to create or use a control created by yourself or a third-party.
To clarify -- this is only a problem on Windows Vista or Windows 7 using desktop composition. The issue is that windows are never truly obscured, like they are when not using desktop composition. They are always buffered by the window manager. (There are special layered windows in windows 2000+, but ignore that for now). Previously, the parts of a window were not available if they were not on the screen or obscured by another window. When they came back into view, by changing focus or position etc, then the system will notify that area to repaint itself. However when using desktop composition, the repainting is never required, since the actual contents of the window are buffered elsewhere. This is why the window previews work in the taskbar, and Flip-3d, for example. The side effect is that code that expects to get a paint message when it is visible once again after being obscured will fail. The ButtonBase code expects to recieve a paint message once it comes back into view, which will start the animation again. And therefore, this optimization became a bug.
The issue should be reported in Microsoft Connect, though it is unlikely to be resolved.

Categories