7

Alright, so I've been scouring Google for a couple hours now and can't seem to find a direct answer to the problem I'm having. I have a custom window with WindowStyle = "None" and AllowsTransparency = "True" When I click on my maximize button:

    private void MaximizeButton_Click(object sender, RoutedEventArgs e)
    {
        if(this.WindowState == WindowState.Normal)
        {

            App.Current.MainWindow.WindowState = WindowState.Maximized;
        }
        else
        {
            App.Current.MainWindow.WindowState = WindowState.Normal;
        }
    }

It maximizes almost exactly the way it's supposed except it seems like there's a -6px margin on the top and left side of the window.

Here's what it looks like: enter image description here

I don't want that white space to be there (it's only white because Google Chrome is open behind it, it's actually transparent). I need the app to maximize to fit the entire screen, excluding the taskbar. So far the only fix I've found is setting the margin of the window to Margin = "6, 6, 0, 0" when the maximize button is pressed. Here is the rest of the code for reference:

StartUp.xaml

<Window x:Class="Expense_Calculator.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:Expense_Calculator"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525"
    WindowStartupLocation="CenterScreen"
    WindowStyle="None"
    AllowsTransparency="True">
<Grid Name="Container" Background="#323232">
    <Grid.RowDefinitions>
        <RowDefinition Height="33"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid>
        <DockPanel Style="{StaticResource TitleDockPanel}">
            <Label Style="{StaticResource TitleBarTitle}">App Name</Label>
            <Button Name="CloseButton" Click="CloseButton_Click" DockPanel.Dock="Right" Style="{StaticResource TitleBarButtonClose}">
                <Image Source="images/close.png"/>
            </Button>
            <Button Name="MaximizeButton" Click="MaximizeButton_Click" DockPanel.Dock="Right" Style="{StaticResource TitleBarButton}">
                <Image Source="images/maximize.png"/>
            </Button>
            <Button Name="MinimizeButton" Click="MinimizeButton_Click" DockPanel.Dock="Right" Style="{StaticResource TitleBarButton}">
                <Image Source="images/minimize.png"/>
            </Button>
        </DockPanel>
    </Grid>
    <Grid Style="{StaticResource UserArea}" Grid.Row="1">
        <Grid Name="WelcomePage">
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <Label Style="{StaticResource Label1}">Welcome to your Expense Calculator!</Label>
            <Button Cursor="Hand" Style="{StaticResource Button1}" Grid.Row="1">Get Started</Button>
        </Grid>
    </Grid>
</Grid>

StartUp.xaml.cs

using System.Windows;

namespace Expense_Calculator
{
    /// <summary>
    /// Interaction logic for StartUp.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            this.MaxHeight = SystemParameters.WorkArea.Height;
            this.MaxWidth = SystemParameters.WorkArea.Width;
            InitializeComponent();
        }

        private void CloseButton_Click(object sender, RoutedEventArgs e)
        {
            Application.Current.Shutdown();
        }

        private void MaximizeButton_Click(object sender, RoutedEventArgs e)
        {
            if(this.WindowState == WindowState.Normal)
            {
                App.Current.MainWindow.WindowState = WindowState.Maximized;
            }
            else
            {
                App.Current.MainWindow.WindowState = WindowState.Normal;
            }
        }

        private void MinimizeButton_Click(object sender, RoutedEventArgs e)
        {
            this.WindowState = WindowState.Minimized;
        }
    }
}

App.xaml

<Application x:Class="Expense_Calculator.App"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:local="clr-namespace:Expense_Calculator"
         StartupUri="StartUp.xaml">
<Application.Resources>

    <!--Title Bar-->
    <Style x:Key="TitleDockPanel" TargetType="DockPanel">
        <Setter Property="VerticalAlignment" Value="Top"/>
        <Setter Property="Background" Value="#323232"/>
        <Setter Property="Height" Value="33"/>
    </Style>
    <Style x:Key="TitleBarTitle" TargetType="Label">
        <Setter Property="Foreground" Value="White"/>
        <Setter Property="VerticalAlignment" Value="Center"/>
        <Setter Property="FontSize" Value="13"/>
        <Setter Property="FontWeight" Value="DemiBold"/>
        <Setter Property="Padding" Value="10, 0"/>
    </Style>
    <Style x:Key="TitleBarButton" TargetType="Button">
        <Setter Property="Cursor" Value="Hand"/>
        <Setter Property="HorizontalAlignment" Value="Right"/>
        <Setter Property="VerticalAlignment" Value="Center"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Border x:Name="border" Background="#323232" Height="33" Width="33">
                        <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" Width="15" Height="15"></ContentPresenter>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualStateGroup.Transitions>
                                    <VisualTransition GeneratedDuration="0:0:.1"/>
                                </VisualStateGroup.Transitions>
                                <VisualState x:Name="Normal"/>
                                <VisualState x:Name="MouseOver">
                                    <Storyboard>
                                        <ColorAnimation Storyboard.TargetName="border" Storyboard.TargetProperty="Background.Color" To="#464646" Duration="0"/>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <ColorAnimation Storyboard.TargetName="border" Storyboard.TargetProperty="Background.Color" To="#3774FF" Duration="0"/>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="TitleBarButtonClose" TargetType="Button">
        <Setter Property="Cursor" Value="Hand"/>
        <Setter Property="HorizontalAlignment" Value="Right"/>
        <Setter Property="VerticalAlignment" Value="Center"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Border x:Name="border" Background="#323232" Height="33" Width="33">
                        <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" Width="15" Height="15"></ContentPresenter>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualStateGroup.Transitions>
                                    <VisualTransition GeneratedDuration="0:0:.1"/>
                                </VisualStateGroup.Transitions>
                                <VisualState x:Name="Normal"/>
                                <VisualState x:Name="MouseOver">
                                    <Storyboard>
                                        <ColorAnimation Storyboard.TargetName="border" Storyboard.TargetProperty="Background.Color" To="Firebrick" Duration="0"/>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <ColorAnimation Storyboard.TargetName="border" Storyboard.TargetProperty="Background.Color" To="#781414" Duration="0"/>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <!--End - Title Bar-->

    <!--Welcome Page-->
    <Style x:Key="UserArea" TargetType="Grid">
        <Setter Property="HorizontalAlignment" Value="Center"/>
        <Setter Property="VerticalAlignment" Value="Center"/>
    </Style>
    <Style x:Key="Label1" TargetType="Label">
        <Setter Property="FontSize" Value="20"/>
        <Setter Property="Foreground" Value="White"/>
        <Setter Property="Margin" Value="0, 0, 0, 25"/>
    </Style>
    <Style x:Key="Button1" TargetType="Button">
        <Setter Property="Width" Value="Auto"/>
        <Setter Property="VerticalAlignment" Value="Center"/>
        <Setter Property="HorizontalAlignment" Value="Center"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Border x:Name="border" Background="#323232" CornerRadius="16" BorderBrush="#505050" BorderThickness="1" Padding="15, 6">
                        <ContentPresenter x:Name="content" HorizontalAlignment="Center" VerticalAlignment="Center">
                            <TextBlock.Foreground>
                                <SolidColorBrush Color="#7D7D7D"/>
                            </TextBlock.Foreground>
                            <TextBlock.FontSize>14</TextBlock.FontSize>
                        </ContentPresenter>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualStateGroup.Transitions>
                                    <VisualTransition GeneratedDuration="0:0:0.15"/>
                                </VisualStateGroup.Transitions>
                                <VisualState x:Name="Normal"/>
                                <VisualState x:Name="MouseOver">
                                    <Storyboard>
                                        <ColorAnimation Storyboard.TargetName="border" Storyboard.TargetProperty="Background.Color" To="#3C3C3C" Duration="0"/>
                                        <ColorAnimation Storyboard.TargetName="content" Storyboard.TargetProperty="(TextBlock.Foreground).Color" To="White" Duration="0"/>
                                        <ColorAnimation Storyboard.TargetName="border" Storyboard.TargetProperty="BorderBrush.Color" To="#C8C8C8" Duration="0"/>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <ColorAnimation Storyboard.TargetName="border" Storyboard.TargetProperty="Background.Color" To="#282828" Duration="0"/>
                                        <ColorAnimation Storyboard.TargetName="content" Storyboard.TargetProperty="(TextBlock.Foreground).Color" To="White" Duration="0"/>
                                        <ColorAnimation Storyboard.TargetName="border" Storyboard.TargetProperty="BorderBrush.Color" To="#C8C8C8" Duration="0"/>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                    </Border>

                    <ControlTemplate.Triggers>
                        <Trigger Property="IsEnabled" Value="False">
                            <Setter TargetName="border" Property="Opacity" Value=".25"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <!--End - Welcome Page-->
</Application.Resources>
</Application>
Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
Benjamen Kuhman
  • 240
  • 4
  • 15
  • Try to remove this.MaxHeight = SystemParameters.WorkArea.Height and this.MaxWidth = SystemParameters.WorkArea.Width; from constructor. – Evk Sep 19 '16 at 18:07
  • When I do that, the app maximizes to fit the entire screen. So it covers the taskbar. It does get rid of all the white space though. But it also seems to overlap the sides as you can see [here](http://imgur.com/1HDswCV) – Benjamen Kuhman Sep 19 '16 at 18:12

5 Answers5

6

By design (for what reason, I don't know), when you have WindowStyle="None" and you maximize the window, it will extend beyond the actual edge of the screen by several pixels on all sides.

In your code, you are restricting the actual size of the window to the exact dimensions of the work area. Since the maximizing of the window still puts the top-left corner of the window those several pixels to the left and above the top-left corner of the work area, the visible portion of the window is necessarily less than the entire width of the work area, hence the exposed area on the right and the bottom.

As noted by commenter Evk, by removing the size restriction on the window (which you can do only when the window is maximized, if you like), the window can expand to the full size WPF wants, ensuring full coverage of the work area.

In your follow-up comment, it's not clear whether you actually want the taskbar to be covered or not. In either case, you may find these links useful to address your specific needs in that regard:
Maximize window with WindowState Problem (application will hide windows taskbar)
Maximizing window (with WindowStyle=None) considering Taskbar

Alternatively, you could still set the size restriction, but take into account the additional pixel margin that WPF insists on when the window is maximized, setting the dimensions larger than needed so that there is no exposed area.

For what it's worth, here is a simplified code example that focuses solely on the specific behavior here:

<Window x:Class="TestSO39578992MaximizeBorderless.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:p="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TestSO39578992MaximizeBorderless"
        mc:Ignorable="d" Background="Yellow" 
        WindowStyle="None" AllowsTransparency="True"
        Title="MainWindow" Height="350" Width="525">
  <Window.Style>
    <p:Style TargetType="Window">
      <Setter Property="WindowState" Value="Normal"/>
      <!-- Uncomment "Topmost" setters to experiment with its effect on the task bar visibility -->
      <!--<Setter Property="Topmost" Value="False"/>-->
      <p:Style.Triggers>
        <DataTrigger Binding="{Binding IsChecked, ElementName=checkBox1}" Value="True">
          <Setter Property="WindowState" Value="Maximized"/>
          <!--<Setter Property="Topmost" Value="True"/>-->
        </DataTrigger>
      </p:Style.Triggers>
    </p:Style>
  </Window.Style>
  <!-- set the margin here, to account for the extra space WPF is adding -->
  <!-- <Grid Margin="6"> -->
  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition/>
      <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition/>
      <RowDefinition/>
    </Grid.RowDefinitions>
    <CheckBox x:Name="checkBox1" Content="Maximized" HorizontalAlignment="Left" VerticalAlignment="Top"/>
    <TextBlock Text="Upper Right" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Top"/>
    <TextBlock Text="Lower Left" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Bottom"/>
    <TextBlock Text="Lower Right" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Bottom" Grid.Column="1"/>
  </Grid>
</Window>

And of course:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        this.MaxHeight = SystemParameters.WorkArea.Height;
        this.MaxWidth = SystemParameters.WorkArea.Width;

        // Compensate for the extra space WPF adds by increasing the max width and height here
        //this.MaxHeight = SystemParameters.WorkArea.Height + 12;
        //this.MaxWidth = SystemParameters.WorkArea.Width + 12;

        InitializeComponent();
    }
}

I've included TextBlock elements in all four corners to make it easier to see how the window size is affected by the various property values.

Community
  • 1
  • 1
Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • I'm not really understanding your [2nd link](https://blogs.msdn.microsoft.com/llobo/2006/08/01/maximizing-window-with-windowstylenone-considering-taskbar/). Mainly because I'm not sure how to use it. But when I use your code it still is the same result. Whenever I use `this.MaxHeight = SystemParameters.WorkArea.Height + 6;` (and the same for the width) it does cover the whole screen. But the work area still doesn't seem to be center. The top and left side are still cut off. It just seems to be that the work area is 6px up and left. Also I'm trying to not cover up the task bar. – Benjamen Kuhman Sep 20 '16 at 01:33
  • To be clear: my code above isn't a solution, it's just a way to reproduce the problem without all the extra stuff your original example shows. Note that in addition to making the window larger (by adding the compensation when you set the max height and width), you need also to set the `Margin` for the window's content element, so that the window content layout itself also accounts for the extra margin WPF is adding. I'll edit the code example with commented lines to show what I mean. – Peter Duniho Sep 20 '16 at 02:12
  • Alright my bad, I misinterpreted your answer. I appreciate your detail answer. This did solve the problem so I'm going to accept your answer. Thanks ;) – Benjamen Kuhman Sep 20 '16 at 02:37
  • Ok so these are the values I used that worked: `this.MaxHeight = SystemParameters.WorkArea.Height + 7;` `this.MaxWidth = SystemParameters.WorkArea.Width + 12;` `Container.Margin = new Thickness(6, 6, 5, 0);` <- This is the grid margin. I'm not understanding why this works. – Benjamen Kuhman Sep 20 '16 at 02:48
  • Setting the margin for your `Container` grid object tells WPF to require the specified space (in your example, 6 pixels on the left and top, 5 on the right, and 0 on the bottom) _around_ the grid object. This in turn forces the grid to be sized small enough to fit in the window with that space between it and the outside edge of the window. – Peter Duniho Sep 20 '16 at 03:16
  • Following up other solution it's probably for preventing user to accidentally resize window. Weird workaround – Avius Dec 21 '19 at 21:15
6

I had the same issue, but by turning of window resizing with

Me.ResizeMode = ResizeMode.NoResize 

upon changing the window state to maximised, removes the issue

adiga
  • 34,372
  • 9
  • 61
  • 83
Glen Howard
  • 61
  • 1
  • 1
  • Thanks for that! Also if you override event, you can change it back upon restoring window size. – Avius Dec 21 '19 at 21:16
1

Here's another simple way to solve it:

private void Window_StateChanged(object sender, EventArgs e)
        {
            if (this.WindowState == WindowState.Maximized)
            {
                this.BorderThickness = new Thickness(8);
            }
            else
            {
                this.BorderThickness = new Thickness(0);
            }
        }
Drax
  • 11
  • 3
0

This works, add on constructor of the main view and create a event on WindowState change.

    private void UpdateMarginOnWindowState()
    {
        if (this.WindowState == WindowState.Maximized)
        {
            this.MainContainer.Margin = new Thickness(6);
            return;
        }

        this.MainContainer.Margin = new Thickness(0);
    }
XzaR
  • 610
  • 1
  • 7
  • 17
0

After checking, I added a maximum size limit to my window

MaxWidth="{Binding Source={x:Static SystemParameters.WorkArea}, Path=Width}"
MaxHeight="{Binding Source={x:Static SystemParameters.WorkArea}, Path=Height}"

And then, for the function that's triggered to maximize, I turned CanResize off as Glen Howard said

    private void Maximize()
    {
        if (App.Current.MainWindow.WindowState == WindowState.Normal)
        {
            App.Current.MainWindow.ResizeMode = ResizeMode.NoResize;
            MaximizeButton.Style = (Style)App.Current.Resources["RestoreButton"];
            App.Current.MainWindow.WindowState = WindowState.Maximized;
        }
        else
        {
            App.Current.MainWindow.ResizeMode = ResizeMode.CanResize;
            MaximizeButton.Style = (Style)App.Current.Resources["MaximizeButton"];
            App.Current.MainWindow.WindowState = WindowState.Normal;
        }
    }

(Style)App.Current.Resources["RestoreButton"] changes my button icon, don't look at it if you don't want to implement it.

Pomian
  • 11
  • 2