VS2010 -C#
I have a TextBox where you can input an integer and a UniformGrid is dynamically generated with the integer number of UniformGrid Cells. Now if I want to add a TextBox to each UniformGrid Cell, I do the following (e.g. int is a 5):
TextBox[] tb = new TextBox[5];
for (int i = 0; i < 5; i++)
{
tb[i] = new Textbox();
UniformGrid1.Children.Add(tb[i]);
}
Ok..that works fine. But problem comes when I need also to fill in some more Texboxes, Buttons, and Labels in it with some design properties defined, possibly also insert a grid inside a UniformGrid Cell. It will get extremely messy if I create arrays for each control and define each array properties in the loop.
Not only that it's messy, I cannot put the textbox inside the UniformGrid's Cell's Grid. The children add the grid on top of the TextBox instead.
Is there a better way to approach this?
You should use DataBinding instead.
Make a ItemsControl bind it to ObservableCollection and use UniformGrid as a container to ItemsControl.
I think that using specialized controls like DataGrid would be better, beacuse it automatically creates two-way bindings to model, it's easy to maintain, etc. There are lots of examples, for example here (Google can help you to find more, if you ask something like "wpf datagrid example tutorial")
Related
I'm dynamically creating a WPF window with a grid-like presentation. There is a header row that contains the column headers. It must always be visible. Below that there is a large number of rows (like hundreds) that can be vertically scrolled. Each row contains a text in the first column and a checkbox in each remaining column.
The list of columns and rows is dynamic, so creating a viewmodel class and binding with templates doesn't work (or would at least be very complicated and require much code while giving up the dynamic nature of the problem). Also, with each checkbox interaction in one row, all other rows might be affected (for the same column) and need to be updated. This would need a lot of interaction between all individual row viewmodels.
I'm looking for a solution to create the columns and rows of an existing empty ListView control and populate all of its data, checkboxes and interaction entirely in C# code.
Specifically I'm missing some ListView method that lets me set the content of a specific cell. While I can add columns to the ListView's GridView.Columns collection, I can't go anywhere from there without templates and bindings. Is is possible to use WPF like this?
The problem is that when I use a template for, say, a checkbox column, all checkboxes do exactly the same an no customisation is possible anymore because I don't create each checkbox, instead WPF creates them for me.
You may create a specific CellTemplate for each GridViewColumn using either XamlReader.Parse:
const string Xaml = "<DataTemplate xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xmlns:x = \"http://schemas.microsoft.com/winfx/2006/xaml\">" +
"<CheckBox Content=\"{Binding Name}\" IsChecked=\"{Binding IsChecked}\" />" +
"</DataTemplate>";
column.CellTemplate = XamlReader.Parse(Xaml) as DataTemplate;
...or a FrameworkElementFactory:
FrameworkElementFactory checkBox = new FrameworkElementFactory(typeof(CheckBox));
checkBox.SetBinding(CheckBox.ContentProperty, new Binding("Name"));
checkBox.SetBinding(CheckBox.IsCheckedProperty, new Binding("IsChecked"));
column.CellTemplate = new DataTemplate() { VisualTree = checkBox };
This lets you customize the columns but still use the GridView and its functionlity the way you are supposed to. Trying to modifying the generated visual elements is not recommended, especially not if you are using the UI virtualization.
I want to make layout dynamically.
For example, When I drag and drop a image, 1 image appears on the box.
When I drag and drop another image, box divide into 2 box (dynamically divide into two).
My question is, what layout should I use (stack panel, grid, or something else) and How to I make layout dynamically using code?
I know question is a little vague but I'm not so good at WPF so please understand Thx.
I would use a GridView and so you can add column or row.
DataGridViewTextBoxColumn trackPositionTextBox = new DataGridViewTextBoxColumn();
trackPositionTextBox.HeaderText = "Track Postion";
trackPositionTextBox.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
dataGridViewSamples.Columns.Add(trackPositionTextBox);
That's to add a Column in a DataGridView.
dataGridViewSamples.Row.Add()
That's to add a row.
I'm also not the best in wpf, but I hope it was helpful.
If you don't need any animation, you could simple add new columns and rows to your WPF-Grid, while drop an image.
Maybe this help you: How to add rows and columns to a WPF Grid programmatically
I am practicing to learn XAML, but syntax is too verbose at my first impression. I am trying to create a gridView from codebehind like below:
var gv = new GridView();
gv.Name = "itemGridView";
gv.ItemsSource = sampleDataGroups;
gv.SetValue(AutomationProperties.AutomationIdProperty, "ItemGridView");
gv.SetValue(AutomationProperties.NameProperty, "Grouped Items");
gv.Padding = new Thickness(116, 137, 40, 46);
Grid.SetRowSpan(gv, 2);
While I can set my gridView' padding like a property, why I am using a static method of grid class to set its rowSpan ?
What is the reason behind that decision ?
Note: I guess I can write an extension method to do that but I am curious why it is not made at the beginning.
The reason is - a GridView (or pretty much every other control except the Grid itself) doesn't have a RowSpan property. Neither do these controls have the Row, Column and ColumnSpan properties.
Don't believe me? Check out the MSDN documentation for GridView. ;)
These are properties which you can use when you put something inside a Grid. Note that in XAML, you also set these properties up in a slightly different fashion: Grid.Row="1" as opposed to just Padding="2".
You can also set up the Grid properties as you did with AutomationProperties. The Grid.SetRowSpan is just a shorthand.
Because setrow and setrowspan are attached properties which are available to gridview's parent GRID which decides the measuring and the layout of the children and hence are not directly available to the children (gridview).
I have my custom Control which is sudoku grid. It acts like any itemscontrol like listbox or combobox. Items are Cells. Items are bound to collection of these cells. My control automaticaly lays out these cell into grid (9x9 board).
When i place my control with items everything looks good and cells are present.
Problem is when i try to print my control using document paginator. Control is printed but it is empty, no items present. It looks like control needs somehow to be redrawn or notified to update itself and to load binded values. Any clues please?
This is how i generate my control on the fly before passing it to document paginator ehich is used to place multiple controls on page:
private UIElement generateGridControl(SudokuFile file, int row, int column)
{
//Contsruct control
View.GridControl.GridControl grid = new View.GridControl.GridControl();
//Create sudoku data from provided file
Grid model = new Grid(file.Type, file.ID);
model.setValues(file.Data);
//Create new viewmodel for my control and inject it to control
grid.init(new GridVM(model), file.Save);
//Set appearance
grid.Width = 500;
grid.Height = 500;
grid.showLabel(true);
//Create viewbox used to stretch control to desired size and wrap it around my usercontrol
System.Windows.Controls.Viewbox box = new System.Windows.Controls.Viewbox
{Stretch = System.Windows.Media.Stretch.Uniform, Child = grid};
System.Windows.Controls.Grid.SetRow(box, row);
System.Windows.Controls.Grid.SetColumn(box, column);
box.Margin = new Thickness(5);
return box;
}
Printing in WPF still strikes me as somewhat black magic. There are a couple of pitfalls that I've been exposed to. One is if the control is not set into a visible portion of the screen and allowed to render, the control tends to not print correctly. Things like layout transforms will fail if the control is not rendered onto the screen for instance. Another thing that helps is to call Measure and Arrange on the item you're trying to print.
grid.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
grid.Arrange(new Rect(0, 0, grid.Height, grid.Width));
The ViewBox needs an initial layout to be calculated. Call
box.UpdateLayout();
before returning from generateGridControl. Keep in mind that UpdateLayout will not generally force a layout update, but only affects elements where IsMeasureValid or IsArrangeValid is false. Anyway, here it will work, since it is the initial layout.
I'm trying to make a grid that represent bookings over a month(excel style).
For this I have used the WPF Datagrid and defined my column in C# code:
for (int i = 0; i < noOfDaysInMonth; i++)
{
DataGridTextColumn tmpColumn = new DataGridTextColumn
{
Header = (i + 1).ToString(),
Binding = new Binding("CellStrings[" + i + "]"),
};
overviewBookingsDataGrid.Columns.Add(tmpColumn);
Now this works fine. The problem I got is that I donĀ“t know how to style the background color of each cell depending on if the slot is fully booked, partially booked or empty.
All examples I have found has been in XAML and defines it togheter with the column and I don't know that translates to C#.
You need to define a datagridcell style in your XAML. Set some triggers based on the cell's Tag property. For instance if it is "Green" then color your cell green.
Once you have populated your datagrid you can iterate through your table in code, get the datagridcell for each required item, set the cell's tag to a proper value and the style triggers will take care of coloring the cell for you (if you want to clear the background color, set the Tag back to null). Or, if you want to avoid XAML, you can directly set the cells background.
There are plenty of examples on the web how to retrieve a datagridcell for a given item, but I'll give one word of warning - because the wpf datagrid is virtualized by default, you'll need to scroll your items into view and call UpdateLayout() on the item's datagridrow, before you can safely access a datagridcell for a given datagridrow.