I am a beginner in using WPF and try to create a responsive application. I read many blogs and websites about the responsive design possibilities in WPF. Now I try to create a sample form. Please see the below image to find element structure in my form.
In this image first red box layout was maximized window and the second one was the resized or small screen layout
Red box is main container grid and it have to column (column definition)
Blue Boxes are two children of the main grid ( first blue box is a grid and second is wrappanel )
Green boxes in side the second blue box are the child elements of the wrap panel.
I am try to when I resize the window I need to change wrap panel contents like above image. I mean wrappanel orientation is horizontal, child contents are arranged in newline if the space not available on the right side.
please see the sample code below.
<Window x:Class="ResponsiveWPFApp.Responsive"
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:ResponsiveWPFApp"
mc:Ignorable="d"
Title="Responsive" Height="450" Width="800">
<Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200*"/>
<ColumnDefinition Width="400*"/>
</Grid.ColumnDefinitions>
<Grid Background="Yellow">
</Grid>
<WrapPanel x:Name="wrPanel" Background="Aqua" Grid.Column="1" Orientation="Horizontal" ItemWidth="Auto">
<WrapPanel.Children>
<Grid x:Name="gd1" Height="400" Width="Auto" HorizontalAlignment="Stretch" Background="Black" >
<TextBlock>terdf</TextBlock>
</Grid>
<Grid x:Name="gd2" Height="400" Width="Auto" Background="Green" >
<TextBlock >sdfdf</TextBlock>
</Grid>
</WrapPanel.Children>
</WrapPanel>
</Grid>
</Grid>
</Window>
In my code wrap panel contains two child elements, it's not filled the wrap panel available space.
You must decide: either you need to stretch the children, or you need WrapPanel. These are mutually exclusive options. The main purpose of the WrapPanel is to transfer the children to the next line (column) if they do not fit in the current line. If each child is stretched horizontally (vertically) to the limit, then each line will always have one child, and the functionality of the WrapPanel will lose its meaning. If you need to stretch children, you should use a Grid or UniformGrid. Here is an example of code with Grid in which children are stretched:
<Window x:Class="ResponsiveWPFApp.Responsive"
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:ResponsiveWPFApp"
mc:Ignorable="d"
Title="Responsive" Height="450" Width="800">
<Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200*"/>
<ColumnDefinition Width="400*"/>
</Grid.ColumnDefinitions>
<Grid Background="Yellow">
</Grid>
<Grid x:Name="grid" Background="Aqua" Grid.Column="1" VerticalAlignment="Top" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" x:Name="gd1" Height="400" HorizontalAlignment="Stretch" Background="Black" >
<TextBlock>terdf</TextBlock>
</Grid>
<Grid Grid.Column="1" x:Name="gd2" Height="400" Background="Green" >
<TextBlock >sdfdf</TextBlock>
</Grid>
</Grid>
</Grid>
</Grid>
</Window>
UniformGrid is a hybrid WrapPanel and Grid. Here is code snipet with UniformGrid:
<Window x:Class="ResponsiveWPFApp.Responsive"
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:ResponsiveWPFApp"
mc:Ignorable="d"
Title="Responsive" Height="450" Width="800">
<Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200*"/>
<ColumnDefinition Width="400*"/>
</Grid.ColumnDefinitions>
<Grid Background="Yellow">
</Grid>
<UniformGrid x:Name="grid" Background="Aqua" Grid.Column="1" Rows="1" VerticalAlignment="Top" >
<Grid x:Name="gd1" Height="400" HorizontalAlignment="Stretch" Background="Black" >
<TextBlock>terdf</TextBlock>
</Grid>
<Grid x:Name="gd2" Height="400" Background="Green" >
<TextBlock >sdfdf</TextBlock>
</Grid>
</UniformGrid>
</Grid>
</Grid>
</Window>
Take account on Rows="1" for the UniformGrid. Number of Rows is fixed for the UniformGrid. WrapPanel may have different number of rows.
Related
I'm trying to center a modal popup-style control on a xaml screen relative to the entire screen, but also have the central control get pushed out of the way by a sibling (side panel) in the event the control is so large the two would intersect. This is feasible with codebehind, datanbindings, data triggers, custom controls and other less than totally elegant approaches, but is there a way to solve this problem out of the box with only xaml?
Here's a greatly simplified version of the problem which is a window with two rectangles. The orange rectangle is always 200px. The green rectangle is variably sized but never larger than 600px. Can we make the green rectangle center on the screen unless it is wide enough that it would collide with the orange rectangle in which case the green rectangle is laid out to the right of the orange rectangle (like a stackpanel)? The green and orange rectangles can be placed into any containers you want and the containers can be nested any way you want.
<Window x:Class="WpfApp1.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:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid Width="800">
<Rectangle Width="200" Fill="Orange" HorizontalAlignment="Left" ></Rectangle>
<Rectangle Width="300" Fill="Green" HorizontalAlignment="Center"></Rectangle>
</Grid>
</Window>
There is no built-in way to do this, but this approach works and is fairly simple:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="200"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Rectangle Width="200" Fill="Orange" HorizontalAlignment="Left" />
<Rectangle Grid.Column="1" Width="300" Fill="Green" HorizontalAlignment="Center"/>
</Grid>
And if you prefer not to duplicate the width of the orange rectangle you can do this:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="{Binding ElementName=OrangeRectangle, Path=ActualWidth}"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Rectangle x:Name="OrangeRectangle" Width="200" Fill="Orange" HorizontalAlignment="Left" />
<Rectangle Grid.Column="1" Width="300" Fill="Green" HorizontalAlignment="Center"/>
</Grid>
First of all it's my first day using Xaml so this question might be dummy for you, but i totally got lost.
Overview
My technique is that i have MainWindow.xaml and it's split into three areas (using grid columns) the columns width being set automatically.
Based on some actions in the right column, the middle column with show a page let's say Page.xaml that exists in different namespace.
What i'm seeking for
The problem is i need to set the width and height for this page to be equal the middle column width and height as it will fit this area.
Notes
I have very small experience with xaml and binding techniques.
MainWindow.Xaml
<Window
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" mc:Ignorable="d"
WindowState="Maximized"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Title="MainWindow" d:DesignWidth="1366" d:DesignHeight="768">
<Grid x:Name="MainGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1.2*" x:Name="LeftColoumn" />
<ColumnDefinition Width="3*" x:Name="CenterColoumn" />
<ColumnDefinition Width=".8*" x:Name="RightColoumn" />
</Grid.ColumnDefinitions>
<ScrollViewer Grid.Column="2">
<StackPanel Orientation="Vertical" x:Name="RightStackPanel" Background="LightGray" >
<Border BorderBrush="{x:Null}" Height="50" >
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap" FontWeight="SemiBold" FontStyle="Normal" Margin="3" FontSize="20" >Others</TextBlock>
</Border>
<Expander x:Name="Expander1" Header="Others" Margin="0,0,10,0">
<Button Margin="0,0,0,0" Width="{Binding ActualWidth, ElementName=RightStackPanel}" Background="White" Content="Add" Height="50" Click="Button_Click" ></Button>
</Expander>
</StackPanel>
</ScrollViewer>
<Frame Grid.Column="0" x:Name="LeftFrame" Background="LightGray" ></Frame>
<Frame Grid.Column="1" x:Name="CenterFrame" Background="DarkGray" ></Frame>
</Grid></Window>
Other Xaml file
<Page
x:Name="Page"
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"
mc:Ignorable="d"
Title="Any" d:DesignWidth="1364" d:DesignHeight="868"
>
<Grid>
<Frame Background="DarkGray" />
</Grid></Page>
MainWindow.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
Frame middleFrame=CenterColumn;
Otherxaml other=new Otherxaml();
middleFrame.Source = new Uri("OtherxamlPage.xaml", UriKind.RelativeOrAbsolute);
}
Pertinent to your code snippet, you may place the OtherxamlPage.xaml inside the central frame and set the properties of that frame like shown below:
<Frame Grid.Column="1" x:Name="CenterFrame" VerticalAlignment="Stretch" VerticalContentAlignment="Center" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" Source="OtherxamlPage.xaml" Background="DarkGray" />
You can set the Source="OtherxamlPage.xaml" dynamically in event handler, e.g. Button.Click as per your example.
Alternatively, consider the creation of WPF UserControl (re: https://msdn.microsoft.com/en-us/library/cc294992.aspx) instead of that other XAML Window (or Page) and place it directly into the grid cell. In both cases set the content "Stretch" property in order to adjust its size automatically, thus you won't need to specify it in the code.
Hope this may help.
Let's say I have XAML code like this:
<UserControl x:Class="Sample.MyClass"
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"
mc:Ignorable="d"
d:DesignHeight="220" d:DesignWidth="750">
<ScrollViewer Width="730" Height="150" CanContentScroll="True" HorizontalScrollBarVisibility="Visible">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="680" />
</Grid.ColumnDefinitions>
<TextBox Width="50" Height="200" Grid.Row="0" Grid.Column="0" />
<TextBox Width="680" Height="200" Grid.Row="0" Grid.Column="1" />
</Grid>
</ScrollViewer>
</UserControl>
Now when I scroll to the right I'd like the first TextBox to be fully visible. In other words - I would like the horizontal scrolling (only horizontal scrolling) to apply only to the second TextBox and vertical scrolling to aplly to both. I can't put the first one outside of the ScrollViewer because then vertical scrolling would not work on it.
To give you a more real-life example:
In VisualStudio you have the text area where you can enter code. And on the left side there's a panel showing line numbers and code folding. If you scroll the text area vertically also the left panel is scrolling down or up. When you scroll the text area horizontally, only the text area is affected by it.
You can try to modify XAML as following:
<UserControl x:Class="Sample.MyClass"
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"
mc:Ignorable="d"
d:DesignHeight="220" d:DesignWidth="750">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="680" />
</Grid.ColumnDefinitions>
<ScrollViewer Grid.Row="0" Grid.Column="0"
CanContentScroll="True"
VerticalScrollBarVisibility="Visible"
HorizontalAlignment="Stretch">
<TextBox />
</ScrollViewer>
<ScrollViewer Grid.Row="0" Grid.Column="1"
CanContentScroll="True"
VerticalScrollBarVisibility="Visible"
HorizontalScrollBarVisibility="Visible"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<TextBox />
</ScrollViewer>
</Grid>
</UserControl>
Hope this may help.
I think what you want to do is svnc 2 scroll viewers,
You can do it with a little code behind voodoo, check this out
Synchronized scrolling of two ScrollViewers whenever any one is scrolled in wpf
I'm trying to ditch Windows Forms, and learn to use WPF professionally from now on. Pictured above is a form done in Windows Forms that I'd like to recreate in WPF.
Here is the XAML I have so far:
<Window x:Class="PizzaSoftware.UI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="297" Width="466" >
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".20*"/>
<ColumnDefinition />
<ColumnDefinition Width=".20*"/>
</Grid.ColumnDefinitions>
<Rectangle Grid.Column="0">
<Backcolor?
</Rectangle>
</Grid>
</Window>
Is this even the right approach, I mean using a Rectangle. In my Windows Forms example, I used a Panel and gave it a .BackColor property.
What's the WPF way to achieve this?
Thank you.
Yes, your approach is just fine. Set the background color with the Fill property:
<Rectangle Grid.Column="0" Fill="Orange" />
<Rectangle Grid.Column="2" Fill="Orange" />
<Rectangle Grid.Column="0"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
Fill="Orange" />
Set the background of the window to your orange color. Then set the background of the grid to white, set the width of the grid so that it leaves space on either side, and set the grids HorizontalAlignment to center.
<Windows ....
Background="Orange>
<Grid Background="White" HorizontalAlignment="Center" Width="300">
...
</Grid>
</Window>
I'd skip the rectangle and set the background color on the grid itself, then set colors on components within to grid.
<Grid Background="Orange">
You can set the Background property of your grid to Orange and then add your control in the middle column and Set its Background property to White. Here is a sample code:
<Window x:Class="PizzaSoftware.UI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="297" Width="466"
Height="297"
Width="466">
<Grid ShowGridLines="True" Background="Orange">
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".20*"/>
<ColumnDefinition />
<ColumnDefinition Width=".20*" />
</Grid.ColumnDefinitions>
<!--Control with white background in second column-->
<GroupBox Background="White" Grid.Column="1">
<!-- Groupbox content here-->
</GroupBox>
</Grid>
</Window>
I have a StackPanel containing a StackPanel and some other items. The first StackPanel has a vertical orientation, the the inner one has a horizontal orientation. The inner one has a TreeView and a ListView, I would like them to expand and fit the width of the window, which I set by the window and allow the user to change. I would also like the outer StackPanel to fit the height of the window. How do I do this?
Edit:
I've converted to using a DockPanel, and I've set the DockPanel.Dock properties correctly in each of the elements, and have disabled LastChildFill in both of the dockpanels, the layout still does not stretch.
The Code:
<Window x:Class="Clippy.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="400" Width="600" MinHeight="400" MinWidth="600" Loaded="Window_Loaded" SizeChanged="Window_SizeChanged">
<DockPanel Name="wrapperDockPanel" LastChildFill="False">
<Menu Height="22" Name="mainMenu" Width="Auto" DockPanel.Dock="Top" />
<ToolBar Height="26" Name="mainToolBar" Width="Auto" DockPanel.Dock="Top" />
<DockPanel Height="Auto" Name="contentDockPanel" DockPanel.Dock="Top" LastChildFill="False">
<TreeView Name="categoryTreeView" />
<ListView Name="clipListView" />
</DockPanel>
<StatusBar Height="23" Name="mainStatusBar" DockPanel.Dock="Top" />
</DockPanel>
</Window>
Use a DockPanel instead. StackPanel explicitly doesn't care about visible space, whereas DockPanel does all of it's size calculation based on available space.
Update:
In addition, in my experience, putting the body of the window into a View, and only having the View in the Window makes for a better Auto Size experience.
For some reason putting all of the children directly into the Window seems to not auto size very well.
Update 2:
I would remove the explicit DockPanel.Dock attribute from the element that you want to stretch (fill) the unused space.
This should do it - I set it up so that the TreeView and the ListView shared the main view 50/50; if you don't want that, set it to 'Auto' and '*' or something. Use "LastChildFill" to your advantage!
<Window x:Class="Clippy.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="400" Width="600" MinHeight="400" MinWidth="600" Loaded="Window_Loaded" SizeChanged="Window_SizeChanged">
<DockPanel LastChildFill="True">
<Menu Width="Auto" DockPanel.Dock="Top" />
<ToolBar Width="Auto" DockPanel.Dock="Top" />
<StatusBar DockPanel.Dock="Bottom" />
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.5*" />
<RowDefinition Height="0.5*" />
</Grid.RowDefinitions>
<TreeView Name="categoryTreeView" Grid.Row="0" />
<ListView Name="clipListView" Grid.Row="1" />
</Grid>
</DockPanel>
</Window>
Set width and height properties to "auto"