Resize border NOT window in WPF - c#

This is my XAML:
<Window x:Class="IPCapture.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:IPCapture"
mc:Ignorable="d"
Title="IPCapture_GUI" Opacity="0.95" Background="Transparent" Foreground="White" FontFamily="Arial" FontSize="14" FontWeight="Bold" FontStretch="UltraExpanded" TextOptions.TextFormattingMode="Display" BorderThickness="0"
Loaded="Window_Loaded" WindowStartupLocation="CenterScreen" Height="Auto" Width="Auto" Cursor="Arrow" WindowStyle="None" AllowsTransparency="True" MouseLeftButtonDown="Window_MouseLeftButtonDown" Topmost="True" ResizeMode="CanResizeWithGrip">
<Window.OpacityMask>
<LinearGradientBrush EndPoint="0.5,1" MappingMode="RelativeToBoundingBox" StartPoint="0.5,0">
<GradientStop Color="Black"/>
<GradientStop Color="#B2420000" Offset="1"/>
</LinearGradientBrush>
</Window.OpacityMask>
<Border CornerRadius="5" Background="#FFC20C0C" HorizontalAlignment="Left" VerticalAlignment="Top" Width="Auto" Height="Auto">
<Grid x:Name="GridMain" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0">
<Grid.RowDefinitions>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="Keys" Width="Auto"/>
<ColumnDefinition x:Name="Values" Width="Auto"/>
</Grid.ColumnDefinitions>
</Grid>
<Border.Effect>
<DropShadowEffect Opacity="0.6" BlurRadius="1"/>
</Border.Effect>
</Border>
</Window>
I followed many tutorials on how to achieve the GUI I wanted and I finally succeeded! However, it does not seem to provide the functionality that I need. I want to:
Resize the width of the GUI
A visualisation of my problem:
The large faded blue area is my Window and the small GUI in the top-left corner of that is my actual widget.(That is enclosed in the Border)
As you can see from my code, I have set ResizeMode="CanResizeWithGrip" on the Window. I am able to resize the window perfectly fine BUT resizing it does not resize my actual GUI.(Because of how my XAML is laid out)
So, for this reason, I want to somehow allow resize on the width of the border instead of the Window.
Additions: (if possible)
Is it possible to remove that small black toolbar that's centered on the top of the Window?
I am also confused as to why, because I have set Height and Width of the Window to Auto, is it so large? Shouldn't it only expand as large as it's content?

Let's take it one at a time:
The resize issue is because of HorizontalAlignment="Left" VerticalAlignment="Top" you've set on the Grid and the Border. It means the element will measure its minimum required width & height and align to the top left. If you remove this, the element will (assuming there are no other layout issues) resize to contain the entire window.
Setting Auto for Width and Height (which is the default, by the way) behaves differently on a window - it tells the OS - not WPF - to determine the initial size (using an undisclosed algorithm, so don't rely on it). If you want WPF to resize the window to the minimum required by its content, set SizeToContent="WidthAndHeight".
The small black toolbar is a new VS 2015 feature and only appears during debugging. You can turn it off in the Live Visual Tree panel in VS.
Bonus tips:
I strongly discourage you from applying an Effect on the entire visual tree. It's a huge performance hit. You should look into using SystemDropShadowChrome.
Same goes for OpacityMask. Just use a uniform Opacity unless you really need that gradient... Even then you may be better off using a uniform opacity and a gradient brush as the background.

Related

DropShadowEffect with Semi Transparent Grid

I am trying to create a grid (with 30% opacity) and drop shadow from it. I have done a mock up in photoshop and this is what I want to achieve:
This is how I tried to implement it in xaml:
<Grid Background="#808080">
<Grid Width="100"
Height="100"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Grid Background="White"
Opacity="0.3">
<Grid.Effect>
<DropShadowEffect />
</Grid.Effect>
</Grid>
</Grid>
</Grid>
Unfortunately, this is how it turned out:
As you can see from the image above, the shadow effect can seen underneath the 30% grid. How do I remove the shadow effect within the grid and only make the shadow appear outside the grid (on the bottom right)?
Easy solution, drop the opacity. But I guess that would not be acceptable, so another solution which is more of a workaround.
Add a Border inside your inner grid and drop shadow on that border, also make the border thickness disappear on 2 sides on which you do not want the shadow. Something like this:
<Grid Background="White" Opacity="0.3">
<Border BorderBrush="White" BorderThickness="0,0,1,1">
<Border.Effect>
<DropShadowEffect />
</Border.Effect>
</Border>
</Grid>

Fitting Page and Contents to a Window and Form c#

I have a window that has a a frame in which I add pages two. So far I have Page1 and Page2. By using the NavigationService I can move between the two pages within the same window, something I have spent some time trying to implement.
The issue now however is that whilst the Window is maximised (which I want) the page's content is only displayed in the top-left hand corner of the Window.
I understand this is purely a matter of choosing the correct containers however I am a bit stuck in what I should go for, this is the layout of each section;
Window - Contains a form
Pages (added to the form) - Contain a dock panel - Contains a canvas - Contains elements (buttons etc)
As I say the issue is that the page is only displayed in the top-left hand corner, I would like the page to "grow" with the Window.
Code for the Window:
<Window x:Name="window" x:Class="WPFNavigation.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:WPFNavigation"
mc:Ignorable="d"
Title="Test1" Height="500" Width="500" ResizeMode="CanResizeWithGrip" WindowState="Maximized">
<Frame x:Name="frame" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" NavigationUIVisibility="Hidden"/>
</Window>
Code for a Page:
<Page x:Class="WPFNavigation.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WPFNavigation"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="Page1" WindowTitle="Page 1">
<DockPanel HorizontalAlignment="Left" Height="280" LastChildFill="False" Margin="10,10,0,0" VerticalAlignment="Top" Width="280">
<Canvas HorizontalAlignment="Stretch" Width="280">
<Button x:Name="button_Page1" Content="Page 1" Canvas.Left="19" Canvas.Top="235" Width="75"/>
<Button x:Name="button_Page2" Content="Page 2" Canvas.Left="99" Canvas.Top="235" Width="75" Click="button_Copy_Click"/>
<Button x:Name="button_Page3" Content="Page 3" Canvas.Left="179" Canvas.Top="235" Width="75"/>
</Canvas>
</DockPanel>
</Page>
The main problem here is that you are using absolute positioning to position your elements on a Canvas and you are also explicitly setting the Width of elements. This doesn't play well with dynamic window sizes.
By setting the Canvas.Left and Canvas.Top you are making the assumption that every device that this application runs on can render the view in exactly the same way. Imagine what your application would look like on a phone, or a screen with a lower resolution.
Instead, consider using a Grid, or make better use of your DockPanel, here's an example:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Content="Hello"/>
<Button Content="World" Grid.Column="1"/>
<TextBox Text="Le toucan has arrived" Grid.Column="2"/>
</Grid>
This is obviously a very simple example however it showcases relative sizes and positioning of elements instead of explicitly setting the Canvas.Left, Canvas.Top and setting the Width.
The above example plays well with dynamic window sizing, if you were to resize the window, then the TextBox will resize as the column it sits inside is set to a * width, which basically means "fill all available space".
If you're in a scenario where you want the content of a page to scale up so that it fills all available space, then you can use a ViewBox, you can find a tutorial here. These are tricky to get right, however I would recommend that you get to grips with other layout panels before implementing a ViewBox, they should be used with care as it's very easy to screw up the user experience where content can become either too small or too large.
Explicitly setting the Width and/or Height of an element should be an absolute last resort. Allowing your application to transition nicely when the application is resized is what makes any user experience more delightful, and the way of which to achieve that is to use relative sizes and positions.
I would recommend reading up on this topic here and here.

layout which allows controls to scale properly

For my WPF project in C#, I have to create a menu state with a layout. Here is an image sample of how menu state should look like this.
So, my question is, which layouts should I use to make my components scalable when I resize the window and with components arranged like in prototype? I have used so far gridlayout, but I'm not sure if it is the way to go with components arranged like in prototype image.
Ideally for components that are stacked identical you use a stack panel resizing automatically depends on what the default behaviours for the panels are.
With that said horizontal stack panels auto expand only vertically and vertical stack panels expand horizontally.
Some sample code of it expanding horizontally.
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<TextBlock Margin="5,0,5,60" HorizontalAlignment="Center">Title</TextBlock>
<Button>State</Button>
<Button>State</Button>
<Button>State</Button>
<Button>State</Button>
</StackPanel>
</Window>
If you want for them to grow both ways the easiest way is to use a grid and set them to proportional sizes.
Note the text inside the component won't auto grow. If you need that you have to use a viewbox.
How to grow/shrink a TextBlock (Font Size) to the available space in WPF?
I figured out myself how to do this. A trick is to use the properties for Horizontal and Vertical Alignment with value of Stretch and to not use width and height.
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
Example:
<Grid Background="White" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="4*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0">
<Viewbox>
<TextBlock>1</TextBlock>
</Viewbox>
</Button>
<Label Grid.Row="0" Grid.Column="1">
<Viewbox>
<TextBlock>2</TextBlock>
</Viewbox>
</Label>
<Button Grid.Row="0" Grid.Column="2">
<Viewbox>
<TextBlock>3</TextBlock>
</Viewbox>
</Button>
</Grid>

How to rotate a WPF Window?

Is it possible to rotate a WPF Window by 45 degree, using xaml?
First question: Why do you want to rotate the whole window?
If you really need it:
You can't rotate the normal WPF window. See: Rotate Window
You will have to create a borderless window and provide a UI to it. See: WPF Non-Client Area Design Techniques For Custom Window Frames
For rotated window look:
Set:
AllowTransparency property to
true.
WindowStyle to None to
remove window chrome
Background
to Transparent
Include a border (or anything meaningful like rectangle, circle, ellipse, etc.) as content of the window and following properties of border:
white background (or any non-transparent color)
rotate transformation, and
smaller size (so as to fit when rotated within the window).
Border will provide the UI to your window.
Be aware of cavaets of creating own borderless window, as it requires you to provide the window interface like minimise, maximise, close buttons; and may require some unmanaged code.
Also, in sample code below, the border when rotated has to be kept within the bounds of the window, otherwise it (and your custom window) will be trimmed.
Sample code
<Window x:Class="CustomWindowStyle.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
AllowsTransparency="True" WindowStyle="None" Background="Transparent"
Title="MainWindow" Height="600" Width="600">
<Border BorderBrush="Green" BorderThickness="2" Background="White" Width="360" Height="360">
<Border.RenderTransform>
<RotateTransform Angle="-45" CenterX="180" CenterY="180"/>
</Border.RenderTransform>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="23" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="X" Height="23" Width="23" Name="button1" HorizontalAlignment="Right" VerticalAlignment="Top" Click="button1_Click"/>
<Grid Grid.Row="1">
<!--Main window content goes here-->
<TextBlock Text="Main window content goes here" HorizontalAlignment="Center" />
</Grid>
</Grid>
</Border>
</Window>
As far as I know you can't rotate an entire window, but you could put everything inside the window into a custom control and apply apply a RenderTransform object to the custom control.
Example (somewhat simple):
http://www.codeproject.com/KB/WPF/TransformationsIntro.aspx
-- Dan

WPF: Order of stretch sizing

I'm creating a modal dialog window which contains three essential parts: a TextBlock containing instructions, a ContentControl for the dialog panel, and a ContentControl for the dialog buttons. Each of these parts are contained in a separate Grid row.
I have some specific constraints when it comes to how the dialog should be sized. The issue I'm having is with the instructions TextBlock. I want the instructions to be as wide as the ContentControl for the dialog panel. The instructions should then wrap and grow vertically as needed. Should the instructions not be able to grow vertically, then it should begin to grow horizontally.
Getting the instructions to be the width of the ContentControl and grow vertically was simple. The part I can't seem to figure out is how to get it to grow horizontally when out of vertical space. My initial thought was to create a class that extends TextBlock and override MeasureOverride. However, that method is sealed. Currently, I'm playing with the idea of have the dialog Window override MeasureOverride to calculate the available size for the instructions block.
Am I missing a much simpler way of accomplishing this? Does anyone have any better ideas than this? Messing with MeasureOverride seems like it will be a lot of work.
Here is some sample code to give you a general idea of how the dialog is laid out:
<Window
x:Class="Dialogs.DialogWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="dialogWindow"
ShowInTaskbar="False"
WindowStyle="None"
AllowsTransparency="True"
Background="Transparent"
ResizeMode="NoResize"
SizeToContent="WidthAndHeight"
WindowStartupLocation="CenterScreen">
<Border Style="{StaticResource WindowBorderStyle}" Margin="15">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock
Margin="25,5"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Text="{Binding Instructions}"
TextWrapping="Wrap"
Width="{Binding ElementName=panelContentControl, Path=ActualWidth, Mode=OneWay}"/>
<ContentControl
x:Name="panelContentControl"
Grid.Row="1"
Margin="25,5"
Content="{Binding PanelContent}"/>
<ContentControl
x:Name="buttonsContentControl"
Grid.Row="2"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Margin="25,5"
Content="{Binding ButtonsContent}"/>
</Grid>
</Border>
</Window>
It appears as if what you really want to create a new Panel or derive from an existing one which would take place of what is currently your Grid. Panel is responsible for laying out your content so you should go that way instead of messing with Window.MeasureOverride.
How exactly do you want your TextBlock to grow horizontally and why do you want this? By growing it horizontally do you want it to grow the Window too?

Categories