How to restore minimized window without flicker - c#

I've made an expose-clone for Vista that sometimes need to restore a minimized window.
I've managed to do this with the SetWindowPlacement function.
The problem is that this also repaints the window which looks like crap after the window nicely has slided into the screen.
This is the code i use to bring a window to the top and give it focus:
private static void ActivateWindow(IntPtr windowToShow)
{
RectAPI r = new RectAPI();
Win32.GetWindowRect(windowToShow, ref r);
if (r.top == -32000) //r.top is -32000 if the window is in minimized state
{
WINDOWPLACEMENT wp = new WINDOWPLACEMENT();
Win32.GetWindowPlacement(windowToShow, ref wp);
if (wp.flags == WindowPlacementFlags.WPF_RESTORETOMAXIMIZED)
wp.showCmd = cmdShow.SW_SHOWMAXIMIZED;
else
wp.showCmd = cmdShow.SW_RESTORE;
Win32.SetWindowPlacement(windowToShow, ref wp);
}
Win32.SetForegroundWindow(windowToShow);
}
If i use it on a window that is already restored it will only call SetForegroundWindow and the window will get to the top of the z-order and get focus without any flicker.
But if i call it on a minimized window I also have to use SetWindowPlacement to bring back the window to restored state. This is what causes the window to repaint and flicker :/
There has to be a way to restore a minimized window without the flicker because the built in window manager does this.

One way to do it is to use double-buffering technique: paint to an off-screen bitmap, then restore, then blit the bitmap to the screen. But it seems like overkill if restoring a minimized window is the only scenario where it's needed. Maybe others will have better ideas?..
Also, if you paint entire window client area, you can disable WM_ERASEBKGND (or rather, say that you processed it but don't do anything) to avoid unneeded fill-with-background-then-redraw sequence.

This link on MSDN will explain how you would want to handle the window painting in your case. Window events like window refresh or minimize/maximize will require repainting of your window or a region of the window.
Happy Coding!!

I'm OP...accidentaly ate my cookie.
Studied how windows flip3d and the taskbar manages this a bit closer and they actually repaint the window before they start the animation of the thumb.
Try to minimize a window and then restore it with flip3d, you will see a small blink on the 3d-window before it get restored.
Tried the same thing with my app and it looks alot better, not perfect but acceptable :/

Related

How do I seamlessly call MoveWindow on a maximized window in Windows?

I have a C# application that is attempting to create a customizable version of Windows's Snap functionality. I primarily use the native functions MoveWindow and ShowWindowAsync. I also use GetWindowPlacement to determine maximized/normal/minimized state.
I can seamlessly snap a "normal" window around to my user definable frames. The window instantly snaps to new desired position and size.
The problem is when I transition from maximized to normal. If I only call MoveWindow then the window snaps to my desired position and size. However the window still thinks it's "maximized" which causes attempts to re-maximize to fail.
However if I call ShowWindowAsync(wnd, SW_SHOWNORMAL) followed by MoveWindow(wnd, x, y, width, height, true) it causes the maximized window to animate to it's old position then snap to its new position. This is very jarring and unpleasant. Attempting to flip the call order or use ShowWindow instead of ShowWindowAsync does not help.
The answer to this question might be to disable the animation. I have not found a clean way to do that.
Solution found!
The fix is to call SetWindowPlacement instead of MoveWindow. SetWindowPlacement takes a WINDOWPLACEMENT structure which allows setting both position/size and showCmd state at the same time.

Switching top-most form without flickering

I'm developing a magnifier in C# .NET (using WindowsForm) that shows a top-most click-able through form. This top-most window shows an specific part of the screen.
The problem I'm having is that to take the screenshot I need to Hide() and Show() the form (otherwise I would take a screenshot of the magnifier) and this creates an annoying flickering in which the magnifier disappears and rapidly appears again.
How could I take a screenshot of the Desktop without hiding/showing the form?
Is there another approach/workaround?
Thanks.
Use the form's Opacity property. Set it to 99% in the designer. When you are ready to take the screen shot, set it to 0, make the shot and set it back to 0.99.
The change is instant, no need to wait and no flicker or repainting. Do not restore it to 1.0, that flickers.
Do beware that you remove the "Hall of Mirrors" effect from the magnifier. Bit of a loss :)

Preventing Winform from being maximized?

I want to prevent my desktop application from being maximized. It should not become maximized by any means - by double clicking on title bar, or by clicking Windows + Up arrow on the keyboard, etc.
-> I disable both the MaximizeBox and MinimizeBox.
-> I also set the MaximumSize and MinimumSize for my WinForm
Still when I press Windows + Up arrow, my win form Shifts to top left of the screen, I mean it gets maximized.
So please tell me any way to prevent this thing happening...
There are actually two completely separate issues at work here. Granted, they look basically the same from a functional perspective, but from an implementation-model perspective (as Windows itself would naturally use) they are unrelated.
As others have answered, you can prevent your form from being maximized by setting its MaximizeBox property to false. This removes the WS_MAXIMIZEBOX style on the form's underlying window, which prevents the window manager from allowing the window to be maximized. It disables the maximize box on the window's caption bar (the one between the minimize box and the close box), disables the "Maximize" option on the window/system menu, and any other methods of maximizing a window that I may have forgotten.
However, this has nothing to do with the Win+↑ keyboard shortcut, which invokes Aero Snap the same as would dragging the window to the the magic position sat the edges of the screen. The window manager, whether as a result of a bug or a feature of Aero Snap, still allows you to effectively "maximize" windows that should not otherwise be maximized. Setting the MaximizeBox property doesn't affect this, so if you truly want to prevent the user from changing the window's size this way, you will need to disable Aero Snap's effect on your window.
Unfortunately, there's no method (at least, not to my knowledge) of programmatically disabling Aero Snap on a per-window or per-process basis (also see this related question). If the user has Aero Snap enabled, you can assume that they want that behavior and applications aren't supposed to tamper with it. The only thing you can do is completely disable resizing your window. In WinForms, you do that by setting the FormBorderStyle property to one of the following: FormBorderStyle.FixedSingle, FormBorderStyle.Fixed3D, or FormBorderStyle.FixedDialog. If you still want your window to be resizable in other ways, you will need to write the code to handle that manually, which is not a particularly easy task.
Thus, I encourage you to very carefully consider whether this is really necessary. All other non-maximizable windows accomplish this simply by setting the MaximizeBox property (or doing the equivalent in their UI framework), which means that they can still be effectively maximized via Aero Snap. If this works for everyone else's windows, including those that are part of Windows itself, it should probably work for you.
The form has a property called MaximizeBox - set this to false.
In regard to your second question, check out this question and it's answers for the best ways to implement keyboard shortcuts in WinForms.
this.FormBorderStyle = FormBorderStyle.FixedSingle;
That line of code will prevent the user from re-sizing the Window.
In addition to that you hide/disable the maximize box and that should do what you asked.
To disable the maximize box use this
this.MaximizeBox = false;
To hide the maximize box use this as well
this.MinimizeBox = false;
If Maximize and Minimize are set to false the buttons disappear.
Setting the MaximumSize equal to the Size (or some size) at least stops the windows from going full-screen. It still snaps to the top left corner but it's still a window at least and looks right - like it's Windows being stupid instead of your program.
You can prevent the windows snapping to the upper left corner by setting:
private void toolbox_Move(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Normal;
}
in the move event of the form.
There is a property of the Form class named "MaximumBox" you have to set False in the properties window of your form... This actually will disable the form from being maximized by any way... Also if you want to control your form sizes you can work with such properties as "MinimumSize, MaximumSize" setting their values at your discretion or creating an event handler for the MaximumSizeChanged and MinimumSizeChanged events...
You can try to RegisterHotKey Win+Up if your window or application is activated and unregister this hot key if it is deactivated. You must catch the hotkey and return appropriate value to prevent further processing.
Look at WM_ACTIVATEAPP, WM_ACTIVATE and WM_NCACTIVATE. The first can be used if you want to disable the Win+UP for all your windows.
Set formborderstyle to fixedsingle
Maximizebox=false
Set the maximumsize to the size of winform's default size
Ex: if size(646,385) then set maximumsize(646,385)
One thing you can do is set the MaximumSize and MinimumSize in the same value but not 0,0.
It's easy easy! Apply the folling code to maintain window's state to normal when a resize event is triggered.
protected override void OnResize(EventArgs e) {
base.OnResize(e);
WindowState = FormWindowState.Normal;
}

Prevent animation on form.Show() when activated from a NotifyIcon

I have a very typical hackish solution for minimizing to system tray in C#:
private void MainFormResize(object sender, EventArgs e) {
if (FormWindowState.Minimized == this.WindowState) {
this.Hide();
systemTrayIcon.Visible = true;
}
}
private void systemTrayIconMouseDoubleClick(object sender, MouseEventArgs e) {
systemTrayIcon.Visible = false;
this.Show();
this.WindowState = FormWindowState.Normal;
}
Ideally, I want my application to disappear/reappear when minimizing to or reopening from the system tray. Minimizing to the system tray works as expected -- the window disappears with no delay and there appears a new tray icon.
Double-clicking on the icon, however, has some very strange effects. The window undergoes a resize animation to its position -- the window appears to fly in from a completely random corner of the screen.
I don't want that. I just want Minimize > -Poof- Disappear and Double-click > -Poof- Appear with no animations or delays or anything of that sort.
Why does this code have an animation? If I call Form.Show() in any other context, the window automatically appears like I want, but when called from a NotifyIcon, it acts strangely. I thought it might be the WindowState = FormWindowState.Normal line, but if I remove that, the window isn't brought to the foreground.
Edit: This problem seems to be OS and theme dependent. The problem doesn't appear to exist in Windows XP, but it's hard to tell because my virtual machine is a little laggy. In Windows 7 Aero, the abitrary-offscreen position problem occurs. In Windows 7 Basic/Classic, it minimizes to the task bar, and reappears from its old position in the taskbar (as if it was actually minimized to the task bar, not the system tray). I haven't tested on Vista. Any tips?
Did you try reordering to put WindowState = FormWindowState.Normal before Show()? I believe the animation you are seeing is the standard window restore animation. Since you are calling Show() before restoring your window, it gets an off-screen position.
Edit: I see your issue now - I looked at it for a second or so, and even tried an IMessageFilter, but for some reason couldn't trap WM_SYSCOMMAND when minimizing (although it fires on restoring).
The one easy thing you could do is live with the minimize animation, though - in your resize handler, just before the Hide() call, set WindowState to Normal. You'll see the minimize animation, but not the maximize (which on most platforms is much less noticeable).
If you need to hide the window when the program runs, your best bet is to create a class that derives from ApplicationContext and shows the NotifyIcon. You then use this class instead of form in the Application.Run.
class TaskTray : ApplicationContext
{
private NotifyIcon _Icon;
public TaskTray()
{
_Icon = new NotifyIcon();
//...
)
}
static void Main()
{
Application.Run(new TaskTray());
}
At least it is possible to have the animation originate from where it should - you have to move the minimized window near the tray notification area: see my hack here
Well, this is an old question, but it's the first result I hit when googling, so I'll share my findings, maybe someone could find this useful.
My application starts with no window showing on the desktop, only a tray icon. The main window can be shown by double-clicking on the tray icon, and closing the window will hide it to the tray icon again.
When my application is hidden, the taskbar icon is hidden as well. However, when it's shown, I have the taskbar icon shown as well, so it can be switched between other windows.
It works as intended. However, I can't help but noticing the animation when showing the window feels very strange and jerky, and it's bugging me a lot. After some digging around, I found the animation behavior is affected by ShowInTaskbar property of the form.
private void ShowMainWindow(object sender, EventArgs e)
{
//ShowInTaskbar = true; // smooth animation
Show();
//ShowInTaskbar = true; // jerky animation
}
Without the ShowInTaskbar = true; line, the window would appear instantly without any animation. Putting the line below Show(); results in the "jerky" animation. Putting the line above Show() gives a smooth fading-in animation and that's the one I choose in the end.

Changing a window's restore position using SetWindowPlacement doesn't work on every window

I'm using the SetWindowPlacement function to (1) maximize and (2) change the restore position of external windows on the desktop. But when I use this command on WinForm windows, it doesn't seem to set the restore location correctly. (The WinForm window I'm testing with is just a VS2008 WinForms application run without modification.) So, for example, if the window is in a restored state located at (0, 0) and I use SetWindowPlacement to maximize it and set its restore position to (100,100), then click the window's restore button, it will restore not to (100,100) but to (0,0). It actually seems like the window first restores to the location I set, THEN moves back to its last restore location prior to being manipulated programmatically. I'm confused as to why this would happen only on WinForm windows - every non-WinForm window I try this on restores correctly to the position I indicated with SetWindowPlacement.
I know that's not much to go on, but I was wondering if anyone here had any ideas about why this is happening. Thanks.
Yes, this is by design. The Form class keeps track of the restore bounds itself, necessary so it can properly reposition the window after it was re-created. Windows Forms often recreates the window on-the-fly to implement property setters for properties that can only be specified by CreateWindowEx(). Like ShowInTaskbar.
The private RestoreWindowBoundsIfNecessary() method puts the window back, it will run when the window is restored. From what I can tell, the restore bounds are latched just before the window is minimized or maximized. If you want to modify the restore position while the window is min/maximized then you'll have to use MoveWindow to move it where you want it to go after restoring the window. Ought to produce some flicker.
I was able to avoid any flicker just by setting the window's size and location in a later spin of the dispatcher. Then, as Hans so helpfully pointed out, RestoreWindowBoundsIfNecessary will use that size and location when restoring the window.
Form window = ...
window.StartPosition = FormStartPosition.Manual
window.WindowState = savedState;
if (window.WindowState == FormWindowState.Normal)
{
window.Location = savedLocation;
window.Size = savedSize;
}
else
{
window.BeginInvoke((MethodInvoker)delegate
{
window.Location = savedLocation;
window.Size = savedSize;
});

Categories

Resources