I am trying to write a XAML UI in WPF where the main window container (a panel) would host children.
The tricky part is I want the children to resize when the window resizes (e.g. when it's being maximized on a screen) and I want them to occupy the maximum of the available space without stretching.
But at the same time I would like them to be allowed to wrap like a wrap panel when possible.
I have designed a quick mockup for easier understanding.
Image mockup on Imgur (25.2KB)
The top one shows a panel hosting 3 elements which all share the same width and the same height. Two are on the first line, the third one takes advantage of the 2nd line to display.
If all were displayed on the first line, they would be of a smaller width.
The bottom one shows a panel hosting 8 elements which all share the same width and the same height (smaller than in the first mockup so they can fit in one screen). The first two lines have 3 elements each while the last line has only 2.
My initial idea was to use a Stackpanel but they strech your child elements and, as far as I know, they don't allow dynamic sizing of their children depending on the number of elements.
Then I had a look at the wrappanel which does the wrapping very nicely but requires you to set the children size in order to do its magic (I might have missed something but I couldn't find a way around it).
Do you have any idea how I could implement this behaviour while keeping my pannel flexible?
The application which is going to use it will have a different number of children to put in the panel depending on the user's settings.
Ah, I forgot to mention that there should obviously be no vertical scrolling, everything should fit on one screen like a dashboard. That's the point of this panel, make sure that everything fits but displays as big as possible, with no distortion.
If you have any question, just ask.
Thank you for your help.
Related
Alright, so I'm trying to figure out the best way to accomplish this for my rather unique case. I have a fullscreen WPF application where controls are added to a Grid dynamically and the user is given the option to freely move/resize them. The controls can be individually moved or resized anywhere on the parent Grid but I have prevented them from overlapping via their MouseMove events. They also cannot be moved outside of their container. Since the app will be running on machines with different monitor sizes, I need to take that into consideration when making the original layout. I have an initial layout that I would like to use, but it would seem that I'm out of options:
I first tried using rows and columns just to (initially) place the controls that are added. This method places them correctly but becomes a problem when I need to move or resize the elements because the control is already assigned to a particular row and column. I could try to use this method and then remove any rows/columns after placing the controls, but I don't think that would work well.
I've also considered a Viewbox, but that's not practical in my case for fairly obvious reasons (as it merely resizes the controls to fit the screen). I'd prefer not to use this because I would only need it to standardize my initial layout. That's it. I also don't want to mess up any text that will be displayed on the window.
So yeah, this is more of a "best practice" question because any solution I can think of would not look very professional or elegant. Feel free to ask any questions if you need clarification.
Edit: As an additional note, I'd prefer to stick with a Grid as opposed to a Canvas as my container.
Edit 2: Just to be clear, I would not need the specific (inital) layout after the first launch. When the program exits, the layout (Margins, Width & Heights, etc. for each element) is saved to a file to use for the next launch.
I've developed a number of kiosk/interactive applications using WPF. If you are trying to show the element transitions (while moving), then it might be best to use a parent Canvas and bind the Canvas.Left and Canvas.Top properties. You can mimic the grid alignment, using a Canvas, if you put in place mechanisms (e.g. Manipulation/Mouse events, converters) to make sure that the Canvas attached properties adjust to the row/column offsets.
It is not uncommon at all to use the Viewbox to mitigate display differences (and your use case is not "rather unique"). You set the Viewbox to a target resolution (e.g. 1920x1080) and allow the control to fill the available space. The other alternative would be to dynamically apply a content template based on the application window size/ratio.
After looking at multiple options, I've decided to just use a calculation to (sort of) simulate the behavior of rows/columns. Because my application is fullscreen, I can take my SystemParameters.PrimaryScreenWidth and SystemParameters.PrimaryScreenHeight to orient my layout. Using a combination of universal padding (static values) and ratio-based calculations (dynamic values), I can smoothly set my initial layout.
For instance, I'm dividing the width of my monitor by 6 (rounded up to avoid decimals) and using that (minus half the control's width) as the control's Margin.Left property, centering it on a 'column' of sorts.
Honestly, my initial layout is fairly simple right now, so we'll see if this will suffice going forward. Thanks to everyone who contributed to the question, and sorry if I was unclear on what I was asking.
I have a WinForm form that has two DataGridView controls paced on it such that they are stacked, one above the other against the right hand side of the form.
I would like a way of setting them so that when I expand the form, they expand height-wise with it, as well as width-wise. I managed width-wise by anchoring them to the left and right sides and anchoring the top one to the top and the bottom one to the bottom. However, from here I'm not sure how to get them to use up the space in the middle that appears when the form maximizes...Maybe an image will make my meaning clearer:
Normal Size:
Maxmized; I'd like the grids to expand to take up the full height of the form between the two of them as the red arrows show:
If this question is blindingly obvious I apologise and can only say I didn't really know how to phrase it properly and so found searching for it on Google unhelpful!
You have two options:
TableLayoutPanel or
SplitContainer
The former lets you create a table of many columns and/or rows with various sizing options from absolute and percent to autosize. This is very powerful for layout; but in other respects TLPs are somewhat restricted as the 'cells' are only virtual..
A SplitContainer offers only two panes but lets you treat each with all the things you can do to a container: add one or more controls, anchor or dock them, give each pane a BackColor and make use of its event model.
So if you need just two controls of equal size that adapt to the form size like you showed in the question, a SplitContainer is maybe the better option.
Set the splitter to fixed and make it smaller, anchor the SplitContainer to all sides and drop the DGVs into their panes and Dock them to Fill.
You could also make the splitter moveable to allow the user to resize the panes; if you do that do make the splitter width larger..
Also make sure that the FixedPanel is set to None so that height changes are shared.
Hint: If you want a few more panes to share the space you can nest several SplitContainers.. But for larger numbers do consider switching to TLP!
I started my app by placing rectangles and other objects on a stackpanel. That worked will until I wanted to split my rectangles and have two columns of rectangles. The vertical stackpanel worked well until I needed to split my rectangles into two columns and put stuff on the left and stuff on the right.
So I converted to a canvas. Now
mainCanvas.Children.Add(grid); // seems to replace what the last Add placed on screen. Any ideas how to control the position of items added to the canvas?
Edit:
Ok clearly a canvas is the wrong panel to use. Two column's of stackpanel's might be made to work. But when I look at what I am actually trying to accomplish, the column's aren't limited to two, but could be n number of columns. Why? Because the application is a flowchart style app that builds a custom language script. The diamond decision shape splits one column into two which can split into two more extra.
I wonder about using a single stack panel and just making a grid with multiple grids horizontally in it. But mouse events would have to be smart enough to know which grid in the grid your actually in. Not undoable I think, but not trivial...just looking to see if there is a obvious use this choice that i am missing by being a wpf rookie.
Edit2:
The issue I have with just using a grid is that when the window is stretched a
grid does not resize to the new window size.
making a grid of multiple other grids, then using isMouseOver to test to see which grid in the single child of the stackpanel actually needs mouse highlighting works.
Following the guide here, I have created a full-screen WPF application. But I met a problem: the various size & resolution of screens. For example, I want to put several sprites on the screen as buttons; but they are located at different positions in each screen, and even different to what shown in the XAML designer.
I have searched all over without a clue got. How can I fix this problem? (to make the buttons appears the exact place (in the center), and better, help the xaml designer reflect exactly what will happens when the program is running). Any help will be appreciated.
UPDATE: I'm defining my page as a Canvas inside the Window element. Actually I like Canvas more, cause I can easily put my sprites anywhere, not like a grid.
In general, you should not use pixel values in WPF.
Instead, you should layout your content in <Grid>s with rows and columns, and it will automatically expand to fill the screen (based on the alignments and row / column definitions).
Avoid using the canvas. Also, do not rely too much on the designer to build your layout. Using Grids, Stackpanels and/or Dockpanels will give much better results (and scale when resizing your window). For example, if you use only the designer and drag-and-dropp all your elements, the designer often puts huge margins a bit randomly and this will not always scale properly if you resize your window.
So, I've been asked to redesign an old application I wrote a few years ago.
Basically, nothing much needs to be changed, except that the Customer wants it to be more fluid, and that it must be fullscreen (no visible "window") I.e. no Titlebar, just a Borderless fullscreen Window.
What is the best way to make sure everything stays fluid, I mean how can we make sure everything appears where it should, 'cause you know, different resolutions, monitor sizes etc?
This is easy in web pages/css, but this is not something I've done before. Most of the Controls will be created programatically at runtime, based on what action was performed, etc. How would I accomplish such a layout? Basically I want to be able to lay it all out full screen, without knowing how large their monitor is, or what resolution they're using.
Your certainly correct in trying to design your form using a fluid layout that responds to the size of the available space and size of the form font. To do that you want to use the following controls and control properties.
1, TableLayoutPanel will split an area into a set of rows and columns and allow you to position your child controls within individual cells of that table layout. This responds to a change in the form width and height.
2, FlowLayoutPanel will position your child controls from left to right and automatically move to a new row when you run out of space. This is great for a fluid design as it will adjust the layout depending on the available space.
3, Control.Anchor property allows a child control to alter position and size based on the size of the form client area. So you make your control always be a fixed offset from the right or bottom edges.
4, Control.Dock property will position a child control against an edge and the opposite size will automatically be defined by the containing form.
You could put Your controls into tableLayout, and set the Dock property to fill.