I'm having some problems with the layout of buttons on a screen. There are a number of buttons with the visibility set to collapsed depending on certain criteria.
Anyway, with the buttons sitting in a stackpanel, the contents determine the width of the buttons. Because these should share the same size, I put them in a grid where the columns are using the SharedSizeGroup.
Having done this, buttons now all share the same width, the smallest width needed to display the button with the largest content. What it does mean though is that buttons don't display at the required position.
That is - assume five buttons in columns 0-4 where the first button is collapsed, buttons should ideally all shift to the left so that they always occupy space left to right. Is there any way I can accomplish this or, if not, how can I get buttons in a stackpanel to share the same width?
Any help is much appreciated.
You can wrap your buttons with individual grids and use that to set a shared size, the scope should be the stackpanel. Then control the visibility of the individual grids instead of the buttons, this is a bit messy though.
Edit: This is probably what you need:
<UniformGrid Rows="1" HorizontalAlignment="Left">
...
Related
I'm working on a Windows Store App.
I have a ListView with a bunch of items in it. It is nested in some stack panels and grids, but they all essentially are auto sized. Essentially, the ListView is given most of the right half of the screen, regardless of what size it is.
If I give the ListView a hard-valued Height, a scrollbar will automatically appear with no extra work. Great. But I don't want to set a height... I want it to be all of the area available in its container. If I try to be clever and set it to 9999 or something then it will not scroll.
I've done a bunch of research, and similar questions like this say that the thing that holds the ListView cannot give it infinite size like a StackPanel would. What alternatives do I have? How can I put a ListView in something with arbitrary space and get a scroll bar to appear?
My only thought is that there must be some way to, in the container that holds the ListView, tell the ListView that it has all available area in such a way that it's height gets set that that value. Sort of like how to have to set ListViewItem's HorizontalContentAlignment property to 'Stretch' in order to get the items within a ListView to know what what available width they actually have.
The essential bits of my layout is this:
<!-- Nested in some other stuff simple Grids and StackPanels, none of which has hard heights set (all auto or *) -->
<!-- Even if I made this a Grid with one Row, setting definition to * or Auto doesn't help the issue - no scroll bar appears -->
<StackPanel>
<!-- Other stuff that has Visibility="Collapsed"... I have code so that only one item at a time within this container will ever be visible, and it gets all available space. -->
<ListView ItemsSource="{Binding SomeBigList}" ItemTemplate="{StaticResource MyDataTemplate}" />
<!-- Other stuff that has Visibility="Collapsed" -->
</StackPanel>
How can I get a scrollbar to appear in the ListView without setting a hard height anywhere? Thanks for you're help.
Don't use a <StackPanel>.
If you are in control over what gets drawn and only one item is ever visible at any one time, then use a non-infinite sized container like <Grid>. You can put each item in the same row, or use a separate row if only for ease of spotting what's what.
I ran into similar on the Windows Phone app. You need to remove the variables of the other containers by creating a test page and determining which panel is causing your ultimate problem.
Create new blank page with a Grid and ListView.
Work the grid sizing to be automatic (auto) or * sized until you see the horizontal scroll bar.
Once the horizontal scroll bar appears, add the other containers, one by one until the scroll bar disappears. That will inform you of the culprit which is causing the miss-sizing and ultimately the failure of the scrollbar to appear.
I have the following layout problem best explained here (apologies for the crude illustration)
Assume each control is implemented as a separate user control
I want behavior such that expanding the top right (green) control will render into view an expanded region wider than the initial (green) control's width and appear directly beneath it, with a width equal to the 2 controls in the first row (eg colspan of 2) while pushing down all the content beneath it
Assume initially there is a grid with 2 rows ..first row is some control and secondly the expandable control - the second row can have anything that will fill a colspan of 2 ..could be another layout container or user control with anything inside it etc.
If the green expandable control was a user control, what would I need to do to obtain this behavior I'm describing?
I'm thinking I need to set the Grid.Row and Colspan attached properties of the container representing the expanded content(?) from inside the user control to the layout grid the user control is inside? (but then how would I set the attached property of a control inside the user control to a layout container outside the user control - especially if the expanded content is itself inside a grid within the user control).
And even if I could do this, this would be very fragile since it would only work if the control was in a grid layout container.
Any ideas? Doesn't have to use a grid but that seems to be the natural / obvious way to solve it?
I had a similar layout a while ago. This worked for me:
On the green control, create dependency properties for the sizes you need. In this case, I expect the full width (lower rect) and the narrow width (upper rect).
In the top-level container, you create a grid for measuring the sizes. So you'll get something like this:
<Grid x:Name="fullSize">
<ColumnDefinition/>
<ColumnDefinition x:Name="halfSize"/>
</Grid>
Here you can divide the width over the columns in the appropriate way.
- Then, bind the widths measured with this grid
<foo:GreenControl
FullWidth={Binding ElementName=fullSize, Path=ActualWidth}
NarrowWidth={Binding ElementName=halfSize, Path=ActualWidth}
/>
Now the GreenControl can set its width to whatever it needs to be, e.g. in the handler for the value update. In my case I set bindings on the elements in the XAML to the dependency props.
I want to anchor below datagridviews to top, left, right & down in a way that they don't over lap when the size of form is increased or decreased. Dock and Anchor both don't seem to provide any solution for this.
You probably need to have a TableLayoutPanel handle that. Three columns, middle column is fixed (Absolute), the outside columns would be based on percentage (50% each).
The DataGridView controls would then be dock-filled into each side column.
Or just handle the layout yourself in the form's Resize event.
I have a dialog with column down the right side filled with buttons. The dialog is built with Windows Forms. I have a mockup at the following link:original dialog
(I would have included it but apparently i'm not allowed to use image tags)
I would like for the buttons in the right column to resize themselves to fill the remaining vertical space when the dialog resizes. It doesn't particularly matter to me whether or not buttons simply increase in size or whether the buttons remain the same size while the gaps between them increase. I'm simply want the buttons to go from the top to the bottom. (I have a mockup for this as well but apparenlty i can only include one link)
I've tried hosting the buttons in a FlowLayoutPanel but they do not increase as the dialog stretches, I only get whitespace at the bottom after I run out of buttons. I also tried a TableLayoutPanel and had the same result but I may have misused it. Does anyone have any ideas how I could accomplish this?
Thanks in advance,
Jeremy
To get you started. Use the TableLayoutPanel, set its Anchor property to top, bottom, left, and right. Set the rows and columns to percentages as needed. I suggest each control have it own cell. Note that each control in a "cell" can have its Dock and Anchor property set as needed.
You can do this with a TableLayoutPanel. Create a column for the buttons, with each button having it's own row / cell in the column. Set each row to be an even percentage for height (if there are 10 buttons, each row would be 10%), and dock the TableLayoutPanel to the right side of the screen. Then, put the buttons into their rows and set them to full docking. Then, when the dialog expands, the TableLayoutPanel will expand to fill the entire right side of the screen, each row will adjust proportionally, and each button would expand to fit the new row size.
You may have to adjust this a bit to fit your needs, especially in how it relates to the other content in the window.
Some WPF controls (like the Button) seem to happily consume all the available space in its' container if you don't specify the height it is to have.
And some, like the ones I need to use right now, the (multiline) TextBox and the ListBox seem more worried about just taking the space necessary to fit their contents, and no more.
If you put these guys in a cell in a UniformGrid, they will expand to fit the available space. However, UniformGrid instances are not right for all situations. What if you have a grid with some rows set to a * height to divide the height between itself and other * rows? What if you have a StackPanel and you have a Label, a List and a Button, how can you get the list to take up all the space not eaten by the label and the button?
I would think this would really be a basic layout requirement, but I can't figure out how to get them to fill the space that they could (putting them in a DockPanel and setting it to fill also doesn't work, it seems, since the DockPanel only takes up the space needed by its' subcontrols).
A resizable GUI would be quite horrible if you had to play with Height, Width, MinHeight, MinWidth etc.
Can you bind your Height and Width properties to the grid cell you occupy? Or is there another way to do this?
There are also some properties you can set to force a control to fill its available space when it would otherwise not do so. For example, you can say:
HorizontalContentAlignment="Stretch"
... to force the contents of a control to stretch horizontally. Or you can say:
HorizontalAlignment="Stretch"
... to force the control itself to stretch horizontally to fill its parent.
Each control deriving from Panel implements distinct layout logic performed in Measure() and Arrange():
Measure() determines the size of the panel and each of its children
Arrange() determines the rectangle where each control renders
The last child of the DockPanel fills the remaining space. You can disable this behavior by setting the LastChild property to false.
The StackPanel asks each child for its desired size and then stacks them. The stack panel calls Measure() on each child, with an available size of Infinity and then uses the child's desired size.
A Grid occupies all available space, however, it will set each child to their desired size and then center them in the cell.
You can implement your own layout logic by deriving from Panel and then overriding MeasureOverride() and ArrangeOverride().
See this article for a simple example.
Well, I figured it out myself, right after posting, which is the most embarassing way. :)
It seems every member of a StackPanel will simply fill its minimum requested size.
In the DockPanel, I had docked things in the wrong order. If the TextBox or ListBox is the only docked item without an alignment, or if they are the last added, they WILL fill the remaining space as wanted.
I would love to see a more elegant method of handling this, but it will do.
Use the HorizontalAlignment and VerticalAlignment layout properties. They control how an element uses the space it has inside its parent when more room is available than it required by the element.
The width of a StackPanel, for example, will be as wide as the widest element it contains. So, all narrower elements have a bit of excess space. The alignment properties control what the child element does with the extra space.
The default value for both properties is Stretch, so the child element is stretched to fill all available space. Additional options include Left, Center and Right for HorizontalAlignment and Top, Center and Bottom for VerticalAlignment.
Use SizeChanged="OnSizeChanged" in your xaml and the set the sizes you want in the code behind.
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
{
TheScrollViewer.Height = MainWin.Height - 100;
}
Long term it will be better for you.
When your manager comes along and asks "make that a bit bigger" you won't to spend the afternoon messing about with layout controls trying to get it to work. Also you won't have to explain WHY you spent the afternoon trying to make it work.