How to create TableLayoutPanel in WPF? - c#

I worked with WinForms and there was an option to create TableLayoutPanel.
For example: I need that my window devided to two parts top and bottom, and I would like that top part take 70% of the window and bottom part 30% of the window...
Now, I am working with WPF and according to this
https://www.codeproject.com/Articles/30904/WPF-Layouts-A-Visual-Quick-Start
there are in WPF a lot of different layouts, but I did not find any that has the same bihaiour as TableLayoutPanel - that I can set how many rows I need and how much of the window should each row take.
How to do it?

To achieve the same behaviour as TableLayoutPanel you can use the Grid control in WPF, it allows you to define as much columns and rows as you need, XAML works very differently than WinForms when designing.
You can add them through the grid properties window under the layout section, specifically ColumnDefinitions and RowDefinitions.
As you begin adding rows, you will see that the width or height of the element is 1 unit of star (which is its default value), this is a special value that helps in distributing the width and height equally among all members of a RowDefinition or ColumnDefinition collection in the available space of a control. You can make a column or row take more available space by incrementing the value of stars the intended row is expected to take.
To give an example, if you have a grid with 3 columns and 2 rows, all with default values, you will have the following XAML:
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
</Grid>
And in the designer, you will see the following grid:
As you can see, all the available space is divided equally between all the columns horizontally and all the rows vertically, if you would like to have a column take more space, you could give it a value of 2 stars, and it will take the space that 2 stars should take.
In that case, the XAML will look like this:
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
</Grid>
And your designer will look like this
There are more options for width values:
Auto: This option will resize itself to fit its children dimensions.
Pixel: This option will make the dimension take up as much pixels as specified (the real dimension can vary slightly, but that's out of scope of this answer)
Now, when you want to put elements inside the grid, you can do so in the designer, or in the xaml, the element that is placed in the first row and first column, will have no tags, but in case you want to put the elements in the second column of the second row, your XAML would look like the following;
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="1" Grid.Column="1">
</TextBlock>
</Grid>
The values Grid.Row and Grid.Column specify in which column and row you want to place the element and are zero-based indexes.
I believe this pretty much sums up all you need to know to get started, WPF has a learning curve (which some say it is a wall) that once you learn it, developing UI becomes trivial, unlike winforms.

Related

How to change resolution of a main window with a user control inside it?

I am trying to add UserControl to MainWindow. And I want to set property of the Screen resolution of the controls also automatically. Please help me for that screen
Please be more clear while asking a question. Do you want the user control to fill inside your window or you want to re-size the window width to the size of the control within it?
If you want the user control inside the window to fit inside the window you could use the same width as the window excluding the border for the user control or use "*" for the user control width so that it can occupy the entire space.
If you want responsive layout, then you should divide UI proportionally. As a consequence of this, you can set proportion what you want and this proportion will be resized proportionally depending on your display size. For example, you have FooUserControl:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="5*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="3*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="4*"/>
</Grid.ColumnDefinitions>
<local:FooUserControl Grid.Row="1" Grid.Column="1"/>
</Grid>
The size of Height and Width can have three values:
Fixed - it is fixed size. (1/96 inch)
Auto - it takes as much space as needed by the placed control
Star (*) - the available width/height is divided evenly among all columns/rows proportionally.

StrechToFit in XAML

I want to arrange two UIControls vertically. The top one is variable height while the bottom one is fixed height. How can I make the top element stretch to available height in a StackPanel or Grid?
My question is similar to this question, and the answer suggested the use of DockPanel, however in WP8 there's no DockPanel, so is there any other alternative of that?
A Grid can do that with a row-height of "*" - i.e. a Grid with two rows, the top one "*" the bottom one "auto" would do the trick (not verified for Win8 but should work if memory serves)
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
...
</Grid>

TextWrapping, TextTrimming, Center Aligned and vertically stretching

I have a seemingly simple layout problem in Windows Phone. The problem is illustrated in the image below:
My requirements are as follows:
Subtitle must always be visible, at the expense of the overflowing text of the title.
Title and subtitle together must be vertically and horizontally centered.
When I use a StackPanel or auto-height Grid rows, the box will overflow. If I try star height rows
I can't control a large title.
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock ...>Title</TextBlock>
<TextBlock Grid.Row="1" ...>SubTitle</TextBlock>
</Grid>
Found the solution, this will cover everything except the bottom element overflowing the whole screen, in my case this won't be possible. It only works if the parent container does not have infinite height provided (like a StackPanel).
Basically, auto height takes 'precedence' over star-height elements. This gives the bottom TextBlock room to choose its height, and then assigns the remaining available space to the top element.

Grid ColumnDefinition star-width is stretching beyond the parent container's bounds

I've designed a grid row as being another grid with a 20/80 split between two columns, with the one on the left having a min width of 250:
<Grid Grid.Row="1" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" MinWidth="250"/>
<ColumnDefinition Width="4*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" Background="Red" />
<Grid Grid.Column="1" Background="Blue" />
</Grid>
At widths greater than 1250, this works as expected, but as soon as I shrink below that, the first column stops shrinking (as it should) because it has hit 250, but the second column keeps shrinking at the same rate as it did before (rather than collapsing at the same rate of the surrounding window). The result is that a portion of the content is cut out, even though the grid is set to stretch to its container:
Why isn't the blue frame resizing to fit within its parent container the way other star width columns do? Why has setting a min width broken this all of the sudden?
Update: I've rebuilt my entire UI in a sample window (by simply replacing each section's contents with a border), and am unable to reproduce the issue:
It it possible that the contents (which aren't encountering any MinWidth constraints and seem to be resizing properly as well, albeit too slowly like their parent grid columns) are still somehow impacting the grid columns? What about the fact that the original is in a UserControl and this is in a Window?
I apologize - given the information in the original question, it was impossible to answer this question.
Unfortunately for me the problem is a bug in the implementation of the Xceed DataGridControl. By simply replacing each DataGridControl with a border or other control in my original UI, all elements are resized as they should be.
The problem was not that the DataGridControls were encountering their own size constraints. They were in fact continuing to resize themselves as the window resized but they were getting it wrong. My guess is that their implementation relies on walking up the hierarchy or parent UI elements and sizing themselves in accordance to what they calculate their available space to be. I found that nothing short of dictating the exact width of one of the parent elements solves this. If the parent elements use star sizing, and these widths are constrained by column definitions to have a maximum or minimum width or height, the Xceed DataGridControl is oblivious and incorrectly requests a size greater than or less than what is available, even if it's been told to stretch to fit its parent control.
The only workaround I found that doesn't involve boycotting Xceed (which is very tempting) is to redesign the layout so that the first column doesn't grow with the rest of the window and is simply fixed at its minimum width:
<Grid Grid.Row="1" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250"/>
<ColumnDefinition Width="4*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" Background="Red" />
<Grid Grid.Column="1" Background="Blue" />
</Grid>
It looks odd and disproportionately squished on large resolution screens, but any attempt to constrain the width while auto-sizing it leads to the behaviour described.
That is totally correct.
In your definition you define that the first columns width has to be at least 250. So 1* has to be at least 250 too. Your second columns width has to be the value of your first column multiplicated by 4. Sorry for my bad english, i hope you can understand.
I cant find an easy and fast solution for that. Maybe you have to bind the MaxWidht property of the second column to the ActualWidth property of the grid and than reduce that value by 250.

Auto resize window content in WPF

When debugging my WPF programs I have noticed that when the window is the set size, the contols look just fine. But when the window is maximized, the content is positioned at the same place as if window has not resized. I want it so that the content and window resize proportionately. How can I do this? Sorry if it is a noobish question, but I'm kinda new in the WPF era.
The XAML code is not completely ready yet but here is some of elements:
<DockPanel>
<StackPanel DockPanel.Dock="Left">
...
</StackPanel>
<TabControl DockPanel.Dock="Right">
...
</TabControl>
<ListView>
...
</ListView>
</DockPanel>
Usually, this is because dimension values are set statically, rather than dynamically. Here's the static approach:
<RowDefinition x:Name="NavigatorRow" Height="120"/>
<RowDefinition x:Name="TaskPanelRow" Height="80"/>
Both rows will have fixed heights, and they won't resize with the window.
Here is the dynamic approach:
<RowDefinition x:Name="NavigatorRow" Height="1*"/>
<RowDefinition x:Name="TaskPanelRow" Height="80"/>
The bottom row still has a fixed height of 80, but the top row will expand to fill whatever space is available. In other words, the rows will resize with the window. Columns work the same way.
If I had three rows, I could do this:
<RowDefinition x:Name="NavigatorRow" Height="1*"/>
<RowDefinition x:Name="CalendarRow" Height="2*"/>
<RowDefinition x:Name="TaskPanelRow" Height="80"/>
The Navigator Row and the Calendar Row will share the available space, with the Calendar Row taking twice the height of the Navigator Row. You get the idea.
So, it's not the container you use, but how you size that container. The one exception, as noted above, is the StackPanel, which does not scale. Use a Grid instead, since it does scale.
Usually this is because the content is hosted in a container which has an explicitly set width and height - like Grid for example.
Post your Xaml or that answer is the best you will get!
Avoid using StackPanels they don't resize dynamically properly.
Ideally you should use a grid and specify percentages if you want things to resize proportionately.
Not sure why everyone is saying stackpanels don't resize dynamically. They handle resizing just like grids do. Just make sure you set your HorizontalAlignment="Stretch" (and/or VerticalAlignment) and the content will expand to fill the stackpanel size. I'm currently using a UI that consists of many nested stackpanels, horizontal and vertical resizing the window expands/contracts all the controls equally inside the window.
Well, you have to have some sort of container for your controls, right? If you're using Canvas and just position your controls absolutely inside there you're pretty much out of luck; this isn't very well for scaling interfaces.
However, there are various container controls that will layout whatever you put in them in certain ways. And if used properly, they scale with a resizing window, too. The Grid is pretty flexible, but StackPanel and DockPanel are very handy at times, too.
You can nest them, if you need.
Use WPF grid with the Widht and Height properties setupped with the "Number*" notion.
For example Width="0.6*", wich is not absolute height but proportional relation to the container. Generaly , if you want resizable content, avoid the fixed size properties as much as you can.
<Grid.RowDefinitions>
<RowDefinition Height="10*"></RowDefinition>
<RowDefinition Height="*" ></RowDefinition>
</Grid.RowDefinitions>
Good Luck.

Categories