WPF full screen on maximize - c#

I basically want to have my WPF window to go in full screen mode, when F11 is pressed or the maximize button in the right top corner of the window is pressed.
While the following works like a charm for pressing F11:
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.F11)
{
WindowStyle = WindowStyle.None;
WindowState = WindowState.Maximized;
ResizeMode = ResizeMode.NoResize;
}
}
This will still displays the Windows taskbar (tested with Windows 7):
protected override void OnStateChanged(EventArgs e)
{
if (WindowState == WindowState.Maximized)
{
WindowStyle = WindowStyle.None;
WindowState = WindowState.Maximized;
ResizeMode = ResizeMode.NoResize;
}
base.OnStateChanged(e);
}
What am I missing here? Or can I do it even more elegant?

WPF seems to be making the decision about whether to go full-screen or respect the taskbar based on the WindowStyle at the time of maximisation. So a kludgy but effective solution is to switch the window back to non-maximised, set the WindowStyle, and then set the window back to maximised again:
private bool _inStateChange;
protected override void OnStateChanged(EventArgs e)
{
if (WindowState == WindowState.Maximized && !_inStateChange)
{
_inStateChange = true;
WindowState = WindowState.Normal;
WindowStyle = WindowStyle.None;
WindowState = WindowState.Maximized;
ResizeMode = ResizeMode.NoResize;
_inStateChange = false;
}
base.OnStateChanged(e);
}
Although the code is obviously ugly, the transition to Normal and then back to Maximized doesn't seem to make the user experience any worse. On my display, I noticed flicker with both the F11 code and the kludge maximise, but not noticeably worse on the kludge maximise. But your mileage may vary!

try this
Topmost="True" and WindowState="Maximized"
you can see your window will cover all screen and hide all with windows taskbar

You need to set the Window.Topmost property.
Edit
Check this blog post Maximizing window (with WindowStyle=None) considering Taskbar

Another solution that worked for me:
You can set the MaxHeight property of that window to
SystemParameters.MaximizedPrimaryScreenHeight using the constructor.
public MainWindow()
{
InitializeComponent();
this.MaxHeight = SystemParameters.MaximizedPrimaryScreenHeight;
}
Warning: This might not work on extended desktop.
Source: Maximize window with WindowState Problem (application will hide windows taskbar)

If you happen to be using WindowChrome to create a custom chrome experience, you'll need to set the GlassFrameThickness to something other than 0 (at least that was the last thing I needed to do to get the TaskBar to be hidden behind the window). That is in addition to the steps provided in the accepted answer.

If there is still someone that need a smooth full screen of course tested only on windows 10! In windows 10 minimized do less flickering if you maintain this code order!
public bool IsFullscreen = false;
public WindowState lastWindowState;
private void player_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (IsFullscreen)
{
this.WindowStyle = WindowStyle.SingleBorderWindow;
this.WindowState = lastWindowState;
IsFullscreen = false;
}
else
{
lastWindowState = this.WindowState;
this.WindowStyle = WindowStyle.None;
if (this.WindowState == WindowState.Maximized)
this.WindowState = WindowState.Minimized;
this.WindowState = WindowState.Maximized;
IsFullscreen = true;
}
}

You can hide the taskbar if you import user32.dll...
[DllImport("user32.dll")]
private static extern int FindWindow(string className, string windowText);
[DllImport("user32.dll")]
private static extern int ShowWindow(int hwnd, int command);
private const int SW_HIDE = 0;
private const int SW_SHOW = 1;
Usage:
int hwnd = FindWindow("Shell_TrayWnd","");
ShowWindow(hwnd,SW_HIDE);

I have found easy way to achieve fullscreen in WPF:
private double LastHeight, LastWidth;
private System.Windows.WindowState LastState;
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.F11)
{
if (WindowStyle != WindowStyle.None)
{
LastHeight = Height;
LastWidth = Width;
LastState = WindowState;
Topmost = true;
Width = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width;
Height = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height;
Top = 0;
Left = 0;
WindowState = System.Windows.WindowState.Normal;
WindowStyle = WindowStyle.None;
ResizeMode = System.Windows.ResizeMode.NoResize;
}
else
{
WindowStyle = WindowStyle.SingleBorderWindow;
WindowState = LastState; ;
ResizeMode = ResizeMode.CanResizeWithGrip;
Topmost = false;
Width = LastWidth;
Height = LastHeight;
}
}
}
This works good in Windows 7 with fixed Taskbar.

In my case, minimizing and maximizing will make the fullscreen size to be a little bit bigger than the screen, so the alternative I found is to temporarily set the Visibility to Collapsed then back to Visible afterwards to force redraw.
Visibility = Visibility.Collapsed;
WindowStyle = WindowStyle.None;
WindowState = WindowState.Maximized;
ResizeMode = ResizeMode.NoResize;
Visibility = Visibility.Visible;

Related

Keeping base animations of window when overriding Style [duplicate]

I wanted to have a customized window so followed a few tutorials which enable this by setting the window style to none, and then adding the title-bar/restore/minimize/close buttons yourself. The minimize is achieved by simply handling the click event and setting the Window-state to minimized, but this doesn't show the minimize animation you see on Windows 7, and just instantly hides the window, which feels very odd when used with other windows that do animate, as you tend to feel the application is closing.
So, is there anyway of enabling that animation? .. it seems to be disabled when you change the WindowStyle to none.
Edit : Test code
public partial class MainWindow : Window
{
public MainWindow()
{
WindowStyle = WindowStyle.None;
InitializeComponent();
}
[DllImport("user32.dll")]
static extern int SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
// this doesnt seem to animate
SendMessage(new WindowInteropHelper(this).Handle, 0x0112, (IntPtr)0xF020, IntPtr.Zero);
}
protected override void OnMouseRightButtonDown(MouseButtonEventArgs e)
{
base.OnMouseRightButtonDown(e);
WindowStyle = WindowStyle.SingleBorderWindow;
WindowState = WindowState.Minimized;
}
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() => WindowStyle = WindowStyle.None));
}
}
A newer feature of .NET has solved this problem.
Leave your WindowStyle="SingleBorder" or "ThreeDBorder"
Leave ResizeMode="CanResize"
Then add this to the xaml inside the
<Window>
<WindowChrome.WindowChrome>
<WindowChrome GlassFrameThickness="0" CornerRadius="0" CaptionHeight="0" UseAeroCaptionButtons="False" ResizeBorderThickness="7"/>
</WindowChrome.WindowChrome>
</Window>
The window will not have any of the default border, but will still allow resizing and will not cover the task bar when maximized. It will also show the minimize animation as before.
EDIT
Unfortunately, when using WindowStyle="None" it still disables the animation and covers the taskbar. So this method does not work if you're trying to make a transparent window.
Edited the answer after experimenting a bit.
There are two options:
1. You can change the Style just before minimising and activating the window:
private void Button_OnClick(object sender, RoutedEventArgs e)
{
//change the WindowStyle to single border just before minimising it
this.WindowStyle = WindowStyle.SingleBorderWindow;
this.WindowState = WindowState.Minimized;
}
private void MainWindow_OnActivated(object sender, EventArgs e)
{
//change the WindowStyle back to None, but only after the Window has been activated
Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() => WindowStyle = WindowStyle.None));
}
This solution has one limitation - it doesn't animate the window if you minimise it from the taskbar.
2. Minimise the Window by sending it WM_SYSCOMMAND message with SC_MINIMIZE parameter and changing the border style by hooking into the message (HwndSource.FromHwnd(m_hWnd).AddHook(WindowProc)).
internal class ApiCodes
{
public const int SC_RESTORE = 0xF120;
public const int SC_MINIMIZE = 0xF020;
public const int WM_SYSCOMMAND = 0x0112;
}
private IntPtr hWnd;
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
private void Window_Loaded(object sender, RoutedEventArgs e)
{
hWnd = new WindowInteropHelper(this).Handle;
HwndSource.FromHwnd(hWnd).AddHook(WindowProc);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
SendMessage(hWnd, ApiCodes.WM_SYSCOMMAND, new IntPtr(ApiCodes.SC_MINIMIZE), IntPtr.Zero);
}
private IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == ApiCodes.WM_SYSCOMMAND)
{
if (wParam.ToInt32() == ApiCodes.SC_MINIMIZE)
{
WindowStyle = WindowStyle.SingleBorderWindow;
WindowState = WindowState.Minimized;
handled = true;
}
else if (wParam.ToInt32() == ApiCodes.SC_RESTORE)
{
WindowState = WindowState.Normal;
WindowStyle = WindowStyle.None;
handled = true;
}
}
return IntPtr.Zero;
}
Neither of the above methods are great, because they are just hacks. The biggest downside is that you can actually see the border reappearing for a moment when you click the button. I'd like to see what others come up with as I don't consider this as a good answer myself.
If you handle the WM_NCCALCSIZE message by returning 0, handle the WM_NCHITTEST message using either your own code (if you want to do manual hit-testing) or also returning 0, and set the WindowStyle to SingleBorder, the window will function like a borderless window but it will have the animations enabled.
If completely necessary, you may also need to handle the WM_GETMINMAXINFO to fix the maximize size - it clips the borders off because the window's style is SingleBorder.
I have found another solution, if you need AllowTransparency = True.
It is not beautiful, rather a bit hacky.
But it is very simple and works great. This uses a empty Window, which is shortly shown when you Minimize/Maximize/Restore your Window, and it has the same position, widht, size and height as your Window. It always has the same Window State as your Window, and it does the animations, which YourWindow lacks because of WindowStyle None and AllowTransparency True. The empty Window has a Window Style SingleBorderWindow and AllowTransparency = false. (by default, so i dont need to set it manually) This is a must or it would not animate. After it has animated, it is completely hidden. You could adjust the look of the Fake Window (BackgroundColor etc...) to YourWindow if it doesnt look good.
public partial Class YourWindowClass : Window
{
Window w;
public YourWindowClass()
{
InitializeComponent();
w = new Window();
w.Width = Width;
w.Height = Height;
w.WindowStartupLocation = this.WindowStartupLocation;
}
Then, you place this in your state changed event:
private void YourWindowClass_StateChanged(object sender, EventArgs e)
{
w.Left = Left;
w.Top = Top;
w.Width = Width;
w.Height = Height;
w.Show();
if (WindowState == WindowState.Minimized)
{
if (w.WindowState == WindowState.Minimized) w.WindowState = WindowState.Normal;
w.WindowState = WindowState.Minimized;
CloseWindow();
}
if (WindowState == WindowState.Normal)
{
w.WindowState = WindowState.Normal;
w.Left = this.Left;
Activate();
CloseWindow();
}
if (WindowState == WindowState.Maximized)
{
w.WindowState = WindowState.Maximized;
Activate();
CloseWindow();
}
}
Finally, create this async Task in YourWindowClass. It will wait shortly and then hide the extra Window.
public async Task CloseWindow()
{
await Task.Delay(600);
w.Visibility = Visibility.Hidden;
}
This will remove the hidden hack Window, so if you close the real Window, the hacky animation Window will close too. Else it wouldnt be Visible to the user because its hidden, but it will still be open and so parts of your App are open. This is a behaviour we dont want, so put this as your Closed Event:
private void YourWindowClass_Closed(object sender, EventArgs e)
{
w.Close();
}

C# WPF - Hide taskbar when maximizing application

I want to hide the taskbar when I maximize my application. It's starting in fullscreen mode with hidden taskbar (Defined in the MainWindow.xaml, defined with the following code):
WindowState="Maximized"
WindowStyle="None"
I want to be able to get the application back in normal windowed mode and then back to fullscreen with hidden taskbar.
When I click on the maximize button in the title bar, the application gets in fullscreen mode, but the taskbar stays visible. I already tried to set the ResizeMode to NoResize but it doesn't work for me.
Here is my code:
public MainWindow()
{
InitializeComponent();
StateChanged += MainWindow_StateChanged;
}
private void MainWindow_StateChanged(object sender, EventArgs e)
{
var state = ((MainWindow)sender).WindowState;
if(state == WindowState.Normal)
{
// When escaping
ResizeMode = ResizeMode.CanResize;
WindowStyle = WindowStyle.SingleBorderWindow;
}
else if(state == WindowState.Maximized)
{
// When maximizing
ResizeMode = ResizeMode.NoResize;
WindowStyle = WindowStyle.None;
Topmost = true;
}
}
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if(e.Key == Key.Escape)
{
WindowState = WindowState.Normal;
}
}
You should change the code as shown below:
Reference: this link
MaxHeight = SystemParameters.MaximizedPrimaryScreenHeight;
MaxWidth = SystemParameters.MaximizedPrimaryScreenWidth;
You can also try the win32 APIs mentioned at this thread.

Cannot show MainWindow after minimization

I try to avoid the XY Problem by saying immediately what I want and then what I get. 😛
So, first of all, I minimize my MainWindow and thoroguh its NotifyIcon ContextMenu I want that my MainWindow reappears.
The problem: the MainWindow doesn't appear/show as Window, but it appears as Icon in the toolbar (see figure 2).
The code:
This is the TrayIcon initializer:
private void InitializeTrayIcon()
{
KyactusTrayIcon = new NotifyIcon();
KyactusTrayIcon.Icon = AppIcon;
KyactusTrayIcon.Visible = true;
KyactusTrayIcon.ContextMenu = new ContextMenu(new []
{
new MenuItem("Chiudi", ExitApplication),
new MenuItem("Mostra", ShowMainWindow),
});
ShowNotification(#"Ciao " + Globals.CurrentUser.Name + #"!", #"Benvenuto su Kyactus");
}
This is the delegate responsible to show the minimized MainWindow (not working at all):
private void ShowMainWindow(object sender, EventArgs e)
{
WindowState = WindowState.Normal;
Topmost = true;
Show();
Activate();
}
This is what happens when the MainWindow is minimized by clicking the [-] button (ie the Hide() method):
private void MainWindow_OnStateChanged(object sender, EventArgs e)
{
switch (this.WindowState)
{
case WindowState.Maximized:
ShowNotification("Bleah!", "Questo è proprio brutto! :(");
break;
case WindowState.Minimized:
Hide();
ShowNotification("Avviso", "L'applicazione è ora minimizzata qui");
break;
case WindowState.Normal:
break;
}
}
Step one. The method MainWindow_OnStateChanged will be invoked when click on [-]:
Step two. The window disappears (ok) and the Tray icon appears (ok). Then I click on 'Mostra' (translated as 'Show') and the ShowMainWindow delegate will be invoked
Step three. This is the final step, that is, what I do not expect. The MainWindos 'lives' as an Icon in the toolbar. But I can't see it as a Window.
Please note that I have not this problem when I close the window by clicking [X] instead of [-]. So, my suspect is the MainWindow's Window.State. I tried to restore it implementing the WindowState.Normal into the ShowMainWindow, but nothing.
Update: if is use WindowState.Maximized in the ShowMainWindow method,
I can see the window again, but it is maximized and this is bad and ugly.
Just change the order of operation when showing the window
private void ShowMainWindow(object sender, EventArgs e)
{
Show();
WindowState = WindowState.Normal;
Topmost = true;
Activate();
}
Simply,create some class-level integer variables and store the height,width and positioning values there.Then use them to get back the size of your window :
int height;
int width;
double left;
double top;
private void MainWindow_SizeChanged
{
height = this.Height;
width = this.Widthl
left = this.Left;
top = this.Top;
}
private void ShowMainWindow(object sender, EventArgs e)
{
this.Height = height;
this.Width = width;
this.Left = left;
this.Top = top;
}

ToolStripDropDown loses mouse autoclose

Not sure how to explain this, but:
there is a control MyPopup, made out of ToolStripDropDown;
there are many based on MyPopup controls (call them popups);
there are no problems to open popup from the Form;
but there is is a problem to open popup from popup.
Problem is what after child popup is closed, parent popup stays on screen even when its parent Form get focus. The only way to close that stuck parent popup is to get focus to it (with the mouse) and hit Esc.
To have popup able to show another popup I have to trick Closing event:
void Popup_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{
// prevent from closing when stay
if (_stay && e.CloseReason != ToolStripDropDownCloseReason.CloseCalled )
{
e.Cancel = true;
return;
}
}
Before of after closing child popup, parent popup has:
value of _stay is False;
the value of Popup.AutoClose is True;
I tried to "bring" mouse focus back to the parent popup with the following:
TopLevel=true no luck;
Focus(); no luck;
Focused=true; no luck;
AutoClose=true; no luck;
Captured=true; no luck;
Also tried setting above value to False and then to True, still no luck.
And here is some more code, which could be useful or not:
public class MyPopup : UserControl
{
protected bool _stay = false;
private ToolStripDropDown _popup;
private ToolStripControlHost _host;
public MyPopup()
{
// create popup
_popup = new ToolStripDropDown();
_popup.Margin = _popup.Padding = Padding.Empty;
_popup.AutoSize = false;
_popup.Closing += Popup_Closing;
// add host
_host = new ToolStripControlHost(this);
_host.Margin = _host.Padding = Padding.Empty;
_host.AutoSize = false;
_popup.Items.Add(_host);
}
public void Show(Control parent, int x, int y)
{
_popup.Show(parent, x, y);
}
public new void Hide()
{
_popup.Close();
}
private void Popup_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{
// prevent from closing when stay
if (_stay && e.CloseReason != ToolStripDropDownCloseReason.CloseCalled )
{
e.Cancel = true;
return;
}
}
protected void PopupChildClosedDefaultEvent(object sender, EventArgs e)
{
// hide popup if mouse is outside of client region when closing child popup
if (!ClientRectangle.Contains(PointToClient(MousePosition)))
Hide();
else
{
// >> here I am trying different things <<
_popup.AutoClose = false;
_popup.AutoClose = true;
}
}
}
public class PopupParent: MyPopup
{
private void TestChildren()
{
_stay = true;
PopupChild popup = new PopupChild();
popup.Show(button1, 0, 0);
popup.Closed += PopupChildClosedDefaultEvent;
_stay = false;
}
}
public class PopupChild: MyPopup
{
}
Question: Is there any way to fix "broken" popup after it has lost its ability to autoclose on mouse event (clicking somewhere outside of the client area)?
Ok, morning bring some freshness to brains and I managed to solve that issue with following:
_popup.Close();
_popup.Show(_parent, _x, _y);
So I have to reshow popup to have it functioning as before. It flickers, but works.

What is the simplest method to change the desktop with one click

I have a window with WindowStyle="none" and WindowState=Maximized" and now I'd like in my contextmenu set the MenuItem to switch the application to the other desktop.
whats the simplest way to do that?
using System.Windows.Forms;
using System.Drawing;
using System.Windows.Interop;
Screen screen = Screen.FromHandle(new WindowInteropHelper(this).Handle);
int i;
for (i = 0; i < Screen.AllScreens.Length; i++)
{
if (Screen.AllScreens[i] == screen) break;
}
i++; i = i % Screen.AllScreens.Length;
this.WindowState = WindowState.Normal;
int x = 0;
for (int j = 0; j < i; j++)
{
x += Screen.AllScreens[j].Bounds.Width;
}
this.Left = x + 1;
this.WindowState = WindowState.Maximized;
This will move a maximised window to the next monitor. I didn't test it though as I have only one monitor. Moving a window that is not maximised is harder because the size of the new monitor is not necessarily the same as the size of the old monitor. You could leave out setting the WindowState and center the window on the screen, or get the x position of the window on the current monitor and add it to the new x position. When using the latter you need to check if the new position is still inside the monitor.
Also note that this only works if your monitors are set up next to each other. This will not work when monitors are stacked.
I've solve the problem
when click the maximized window with the MouseLeftButtonDown then minimized this and now can i drag this to the other screen. The MouseLeftButtonUp Methode maximized the window
private void win_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
click = new Point(e.GetPosition(this).X, e.GetPosition(this).Y);
win.WindowState = WindowState.Normal;
}
private void Window_MouseMove(object sender, MouseEventArgs e)
{
this.Left += e.GetPosition(this).X - click.X;
this.Top += e.GetPosition(this).Y - click.Y;
}
private void win_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
win.WindowState = WindowState.Maximized;
}
thx # all : )

Categories

Resources