Your recent problem with resizing the window is a different problem, and one which should be addressed on a new topic when you reach that stage. First, stick with this topic and write the Xaml as I have shown and explained to you. Give your Grid a name, and then write your C# code in your Code behind file for adding the functionality of adding new controls to your grid. Once you reach this point, you will probably end up using a wrap panel around all of the grids items, (that is of course if you don't want to bother writing a lengthy class based on the Window Size from the Windows SizeChangedEventArgs
to structure your grids elements based on the window size and how many items are in your grid.) Yes this would be avoided by using a wrap panel. That being said, I'd prefer to write an explicit class to handle the grids elements when the Window changes size. I don't think there are many programmers who would do it my way, so I am not advising that you do either, as the simpler thing at that point would be to use a wrap panel and be done with it. As an added exercise, you could always remove your wrap panel and write an explicit class to handle your Grids elements when your window size changes.
You are already using the correct structure. You're using
a grid, which is the correct control to use. But I am trying to get you to avoid using the wrap panel too, as you will learn much more by writing your Xaml code, but more importantly by writing your own code behind file which holds all your logic for controlling how new items are added and removed. Including what happens when you resize your window. This is all doable by writing a class, and manipulating your grids behaviour from your code behind file. Providing you name your items wrote-out in your Xaml markup, you can manipulate them just as efficiently in your code behind file.
What Skydiver has done, is used a ItemsControl, and while there is nothing wrong with his example, its not how I would have gone about it either. And the reasons for that is because it does what I didn't want to do. See here :
WPF ItemsControl Example As data templates generally require devs to use some kind of
"layout" panel for putting data on it.
The ItemsControl already uses a stack panel inherently.
Anyway, myself and Skydiver did discuss this between ourselves prior to Skydiver writing out his own example for you. He thought the grid was rather complicated without using a stack or wrap panel, hence the use of his data template with the ItemsControl as a method to avoid using the Grid control.
But if you want to learn, then you should make it a challenge to write out a class and try to understand how you can construct that class to control the flow of your grids elements just as you would if you were writing it in Xaml. One of the main reasons I am advising you with this route is because you will learn more about xaml than you ever will by also allowing a simple control to do it for you.
Anyhow, after Skydiver messaged. He asked me some very genuine questions on how to actually approach some of the issues he was facing. With his permission, I am sharing some of that chat log here, since he and I also might help you to understand some of the approaches to take based on some of the questions you are likely both asking.
Please keep in mind, I am not a master in WPF, but I do work on this platform for work and for customer and personal projects, so I am familiar with finding my way around and I do know some neat tricks, but there may be a point where some of the other devs on this topic might say stop. Hold on; why not just let him use the stack and wrap panels? Well he can use them if he so wishes, but one of the main reasons I advised our OP to take this route; was to learn Xaml, and to learn how to manipulate the structure they started out with in the Xaml and to learn to do this by making a managed class for handling the different variables involved with both the Grid definitions, and the windows actual width, especially when being resized.
Here are Skydiver's questions in quotes (discussed off the board) :
Well how to determine how many column and row definitions have to be created.
By determining if a control resides in that column. When a user of your program adds more controls, you add more definitions. If your window is running out of space for new definitions, you will have no choice but to eventually add (I may stand corrected), but to add a ItemsControl which allows us to use vertical and horizontal scroll bars unless I am mistaken another control, but I'm pretty certain I am not mistaken.
Well how to determine how many column and row definitions have to be created.
By creating the amount you start off with in your Xaml, you count how many you have, keep track of this in a class and then when a user adds new controls you can add the new column/row definitions, and add the new controls or fragments to that column and again, keep track of this in a class.
Remember the main reason I wanted him to do it this way was to learn Xaml mostly, and because the grid is the correct way to do it.
If you say, that "no man, you just hardcode those definitions into the XAML", then how do you deal with more items being added, or the window being resized?
That is what a class is for. That is what looping your grid column's is for, and collecting the actualwidth from. Like :
double t_width = default;
foreach (ColumnDefinition cd in MyGrid.ColumnDefinitions)
{
t_width += cd.ActualWidth;
}
Console.WriteLine($"Total Width is @ { t_width }");
Essentially you end up with a total size of all column's which lets you set the overall size of the Window. At this point, I should also point out that you do not get the width of the controls or "fragment" controls in the same way as in windows. While WPF does have a width property, this is not what you want to use as this property is actually used for binding. Width is also a
DependencyProperty
so it does allow binding and as I said above and it must be set on the UI thread also. It is also worth mentioning that this will not give you the width unless measure is called. You can read more on that one here :
UIElement.Measure(Size) Method (System.Windows)
Chicken and egg problem: MyGrid.ColumnDefinitions will start out empty since I don't know how many columns will fit it the Window.
Not really a problem. If there are none, then you start with none.
If I make it non-empty by hardcoding columns, I need to make sure that the number of columns and items will exceed the size of the Window.
E.g. Even if I define 100 columns, but there is a single item, what is the appropriate width? And conversely, if I define only 9 columns, but the user sets up 100 narrow fixed width items?
Width of what? The Definitions? The definitions would only be set to Auto. Nothing else. I already answered that above, by using a managed class to mange adding new definitions for each item needing to be added to the grid. By using the Auto property, the grids definitions will handle the size of the child controls proportionately.
I then went on to make the point :
Btw, don't be alluded to believe that i am condemning your suggestion to use the controls to simplify how this should be done. As we all know it can be done with those panels. But It's more fun and challenging to use a Grid to build up that structure and then at a later point add a managed class to control how items are added to it.
I hope I've not missed any of the questions or missed applying an answer. I'm happy to answer any questions or provide some basic sample code providing I'm not already occupied with other work/chores. Remember, I'm not smarties, and I don't have all the answers.
Edit : I apologise for some of the minor typos. I can't be arsed to fix them all as I've been wring this post on and off all day and finally found time to post it.