I'm developing a Database system that needs to be resolution independent, some use screens that are still running at 1024 x 768, some use screens that are at 1920 x 1080 and others use everything in between.
I haven't done much work with WPF before so I'm sort of just starting out and attempting to get my head around height, widths and alignments.
What I have at the moment is one main window that holds an grid in which at the top there is a row for a label and some navigation buttons, as well as the time and the username of the person logged in. I then have a second row below that that holds a frame which I load pages into for the main navigation of the program.
In the pages I mainly use the grid layout, and occasionally the stack panel. One of the biggest problems I have come across is an issue like this;
In low resolutions this is common, where as in a higher resolution the buttons look fine;
This is the XAML code for the buttons within their parent grid;
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Content="HR" Margin="10" Click="RunHrSystem" FontSize="18.667" />
<Button Content="Companies" Margin="10" Click="RunCompSystem" FontSize="18.667" Grid.Row="1" />
<Button Content="People" Margin="10" Click="RunPeopleSystem" FontSize="18.667" Grid.Row="2" />
<Button Content="IT Management" Margin="10" Click="RunITManagementSystem" FontSize="18.667" Grid.Row="3"/>
<Button Content="Sales" Margin="10" FontSize="18.667" Grid.Row="4" />
<Button Content="Buying" Margin="10" FontSize="18.667" Grid.Row="5" />
<Button Content="Estimating" Margin="10" FontSize="18.667" Grid.Row="6"/>
<Button Content="Design" Margin="10" FontSize="18.667" Grid.Row="7"/>
</Grid>
Is there anything obvious I am doing wrong here that is preventing the buttons from resizing according to a lower resolution? As I say I get this throughout my program when using buttons, as well as the rectangle shape and in some situations labels, where the bottom of the label will be cut off too.
Currently, you are declaring RowDefinitions to use *, this tells the row to use the height as a percentage of the available space. Therefore, if your resolution changes, your row heights will change.
Instead, you want the RowDefinition to be the height of the content. In this case, when the resolution changes, the row heights will not change.
<RowDefinition Height="Auto"/>
It'd be a good idea to put the grid in a ScrollViewer, just in case the grid becomes larger than the screen.
<ScrollViewer>
<Grid>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
...
In your particular example, I would instead use a StackPanel.
<ScrollViewer>
<StackPanel>
<Button ...
I guess it's a bad practice to hide existing buttons in a non-visible area. The user should scroll for accessing bottom buttons. If you need to support the low-resolution monitor, an app should adjust to the current resolution.
I guess the best way is decreasing the margin, set * for RowDefinitions and limit grid height to prevent huge stretching.
Related
I have a stackpanel that contains an expander control and below that 3 rows of buttons. Depending on logic the buttons may be collapsed. If enough buttons are collapsed to eliminate a row of them, I would like the expander to open up revealing more of it contents. I need it to open up depending on how much room is available below it.
Is there anyway to partially open up an expander to make use of additional space if it becomes available?
Thanks
Harold
I think what you are trying to do is simpler than you make it sound,
You need the right container/ panel to achieve what you are asking.
An example is like below
:-
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Expander Grid.Row="0"/>
<Button Grid.Row="1"/>
<Button Grid.Row="2"/>
<Button Grid.Row="3"/>
<Grid>
With the Grid Panel if you use auto when the control within gets collapsed so does the space and because the first Expander's Grid row is * it will adjust to fill and free space.
I have the following Grid setup in a WPF application.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="220" />
<RowDefinition Height="40" />
<RowDefinition Height="80" />
<RowDefinition Height="180*" />
</Grid.RowDefinitions>
<!-- some content -->
</Grid>
What I want is for the final row to take up as much height as available in its parent. But it does not seem to honor my '*' command in the final row definition.
Please note that I want all other row heights to be fixed..
Is this possible? If so how? Any help or pointers are appreciated..
place height="*" in last row.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="220" />
<RowDefinition Height="40" />
<RowDefinition Height="80" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
What you have written should be fine (though as #Bolu commented, the 180* could be replaced with * in this case). If the content in the last row is not expanding to fill the available size, I would suspect one of the following:
The Grid may be nested somewhere below a layout panel that does not arrange its children to fill all available vertical space. For example, is one of the Grid panel's ancestors a StackPanel? A good way to test whether this is the culprit is to comment out the entire Grid and replace it with a Border with an easily distinguishable background (e.g., Magenta) and see if it occupies the entire area you expect the Grid to fill.
There may not actually be any content in the last row. Did you set the correct Grid.Row value correctly?
You may be overriding the layout behavior of the last row's content. Are you setting the content's VerticalAlignment to anything other than Stretch?
Remove the Height property from the last Row:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="220" />
<RowDefinition Height="40" />
<RowDefinition Height="80" />
<RowDefinition/>
</Grid.RowDefinitions>
<!-- some content -->
</Grid>
I got a ListView (wrapped in a ScrollViewer), which resizes itself if the elements inseretd exceed the visible area until the parents Max Height is reached.
The ListView is embedded the following way.
<Window ... SizeToContent="Height">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<ScrollViewer x:Name="MyScrollViewer" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ListView Name="MyListView"
ItemsSource="{Binding Path=RetrievalStringResults, Mode=OneWay}"
IsSynchronizedWithCurrentItem="True" />
</ScrollViewer>
<DockPanel Grid.Row="0" Grid.Column="1">
...
</DockPanel>
<Expander Grid.Row="1" Grid.ColumnSpan="2">
<DockPanel Height="150" HorizontalAlignment="Stretch">
<TextBox DockPanel.Dock="Top" />
</DockPanel>
</Expander>
<DockPanel Grid.Row="2" Grid.ColumnSpan="2">
... some buttons
</DockPanel>
</Grid>
</Window>
I used SizeToContent because I got a text box on the bottom wrapped in an Expander, which shall expanded on demand, and actually therefore my main window needs to resize. This actually works fine.
The problem is though the ListView's Height isn't the max height on start-up wherefore I got that "auto-resize" effect.
How can I set the ListView's hight to the max of the parents height to avoid this effect?
Another, more general issue. I think avoiding static layout parameters (static values for hight/width) is nice, but I got the feeling I'm loosing some control over my UI controls.
I recognized, resizeing my main window manually in height, it "jumps" by the 150 height of the DockPanel wrapped by the Expander on the bottom, anyway to avoid this?
What is the best pratice in dynamic UI Layout? I explored DockPanel beeing more dynamically in sizing to the surounding contorls than a StackPanel. But I guess thats not everything.
I think your issue is with your Grid definitions
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
...
</Grid>
This means that the top row is going to be twice the size of rows 2 and 3, so the top row will only take up 50% of your space while your bottom two rows each take up 25% space.
If you want the top row to take up all available space, make sure it is the only * size row, and set the other rows to Auto so they will take up whatever space they need.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
...
</Grid>
I am making a UI in WPF, I have a bunch of functional areas and I use a Grid to organize it.
Now the Grid that I want is not uniform, as in, some functional area will span multiple cells in the Grid. I was wondering what the best practise is in solving this. Should I create one grid and then for each functional area set it to span multiple cells, or should I split it up into multiple nested Grids.
In this image, the leftmost panel (panels separated by the gray bar) is what I want. The middle panel shows one grid where the blue lines are overlapped by a functional area. The rightmost panel shows how I could do it with nested grids. You can see the green grid has one horizontal split. In the bottom cell is the yellow Grid with a vertical split. In side the left cell is the red Grid with again a horizontal split.
Grids http://www.freeimagehosting.net/uploads/08f2711bae.jpg
I was just wondering what is best practise, the middle or the right panel.
UPDATE: Just for clarification, a more 'code oriented' example:
The Middle panel
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Menu Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" />
<uc:Info Grid.Row="1" Grid.Column="0" />
<uc:Control Grid.Row="2" Grid.Column="0" />
<uc:Simulation Grid.Row="1" Grid.Column="1" Grid.RowSpan="2" />
</Grid>
The Right panel:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Menu Grid.Row="0"/>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<uc:Info Grid.Row="0" />
<uc:Control Grid.Row="1" />
</Grid>
<uc:Simulation Grid.Column="1" />
</Grid>
</Grid>
Update: I have to admit that now that I wrote out the code for both approaches, the "span" solution looks a lot better.
I would personally go with your middle layout using a single grid with column and row spans to structure the overall layout of the UI, then put a panel in each of those sections to contain the actual controls (and possible further detailed layout).
I would recommend to create one master grid divided into functional areas, then create separate grids/stackpanels/etc in these areas.
You may not know the requirements for each functional area, so you can arrange their elements freely and switch bettween layouts. When you put everything in one grid with span columns and/or rows - you would get a "hard to manage" layout.
I am afraid I am unable to distinguish your solutions with the color in the different grids and sub-grids.
What I can advise is to create a UserControl for each functional area, then have a grid to arrange these areas.
Each UserControl is then free to create its own layout (with another grid, or a simpler StackPanel, or whatever) and is responsible to display a data subset/handle user events in its own area.
The outer grid is then an arbiter for things that involve more than one area (e.g. event forwarding between areas).
Frankly i would go for a dockpanel or like that for top level composition, and grids for low level
My group is building an editor-type app in WPF. One thing we noticed is that on my WinXP machine, running with the "windows classic style" theme, the text on buttons is fits fine. However on my friend's machine, who's running with the "windows xp style" theme, the font size is bigger so text on buttons get clipped at the bottom.
Is there a way to handle this nicely, like automatically resizing controls to fit the text?
I hesitate to manually resize the button to fit his layout as anyone else can have totally different settings through the Display Properties and Accessibility Options.
Thanks!
A WPF button will automatically resize to fit the content that it has been given, however it will only do this when it is inside a container that does not enforce size and its size has not been set manually. To prove this mess around with the font size in the following code snippet:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button
Grid.Column="1"
Grid.Row="1"
FontSize="24"
Content="QWERTY"/>
</Grid>
I guess that your buttons haven't resized because you have constrained them. To fix this you need to decide how you want them to resize (which can be very complicated when elements would overlap if they just grew blindly) and if none of the supplied panel types perform the growth behaviour that you are looking for then you may need to write your own that does.
Have you hardcoded element sizes using Width and Height properties? In WPF the recommended way to do this is to use the several layout containers.
The following is an example of a grid which lays two buttons at the bottom and a textbox at the top.
<Grid>
<Grid.RowDefinitions>
<!-- TextBox row with unspecified height. -->
<RowDefinition Height="*"/>
<!-- Button row with automated height so it resizes to
fit the content -->
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Textbox on first row. -->
<TextBox Margin="3" Name="textBox1" Grid.Row="0" AcceptsReturn="True" />
<!-- StackPanel which lays the two buttons at the bottom horizontally.
RightToLeft is specified so that the first button appears on right.
-->
<StackPanel Grid.Row="1" HorizontalAlignment="Right"
Orientation="Horizontal" FlowDirection="RightToLeft">
<!-- The buttons. Only padding and margin are hardcoded so these
can resize to the contents -->
<Button Padding="3" Margin="3">OK</Button>
<Button Padding="3" Margin="3">Cancel</Button>
</StackPanel>
</Grid>