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.
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.
In the data grid control, there's an empty row at the bottom. When a user fills the cells, I can store the contents, hence creating an additional element in the database.
However, when the number of pre-existing rows grows large, the user'd have to scroll each time to access that row. Is there a smooth way to move it up to the top?
The solution I can think of is placing other controls in a panel right above the data grid. But that's more work than I'm willing to spend. Still, it'd be nice to let the users not be forced to scroll their mouses off.
Assuming the collection view returned by your DataGrid's Items property implements IEditableCollectionView (which, in my experience, does for an editable DataGrid), then you should be able to use the NewItemPlaceholderPosition property through the explicit interface:
// Assume myDataGrid is the DataGrid control holding your results.
// You can do this inside your window/control's constructor after its
// call to InitializeComponent and after myDataGrid's ItemsSource
// property has been set.
var collView = myDataGrid.Items as IEditableCollectionView;
if( collView != null )
collView.NewItemPlaceholderPosition = NewItemPlaceholderPosition.AtBeginning
I have a button. When I click at it, a new row is added to the gridview and allow a user to edit in that row. How do I make new row appear in the first row?
It looks like the top most row in the following article but not
https://documentation.devexpress.com/#windowsforms/CustomDocument778
Currently, I did like the following code. It works but not good. With this solution, I also have a problem with scroll bar. If grid has many rows, the scroll bar will appear. Grid view will have a little blink when a new row is added because
it moves focus and scroll to last row -> last row is removed -> new row is added at the top -> move focus and scroll to top row
To disable scroll, I followed the article https://www.devexpress.com/Support/Center/Question/Details/CQ19190 to create a custom gridview. So far so good. But the problem is I do not want to custom grid. Does anybody have idea?
If I have to custom grid, how can I convert MainView to my custom grid at design mode?
- in design mode, click on MainView of grid view, then choose convert to ...-> custom grid view does not appear in the menu
Sample code
private void AddNewRow(GridView gv) {
gv.AddNewRow();
var row = gv.GetRow(GridControl.NewItemRowHandle);
var helper = new ListDataControllerHelper(gv.DataController);
// Binding list has a method InserAt(index, object), but in my case the object can not be created directly.
// Hence, I do not know what it is. I only get new object through gv.AddNewRow()
// I can work around by extending binding list
// but grid view does not support adding new row at specific position to adapt with InsertAt or my custom binding list
// It is not a good idea
helper.BindingList.Remove(row);
helper.BindingList.Insert(0, row);
gv.FocusedRowHandle = 0;
gv.SetFocusedRowModified();
}
I will appreciate all the help.
Thank you
If you simply want to add a row without your layout being updated automatically, try to suspend and resume the layout like so:
gv.SuspendLayout();
helper.BindingList.Remove(row);
helper.BindingList.Insert(0, row);
gv.FocusedRowHandle = 0;
gv.SetFocusedRowModified();
gv.ResumeLayout(true);
In general, your method of inserting a row seems fine.
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).
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")