I have a Grid with 5 rows and 5 columns. I creating this Grid dynamically. Every cell contains custom user control. I would like to replace the user control dynamically with other user control at given row and column. You can see the method implementation which creates the Grid here.
My question is how to replace the user control at given row and column after the Grid is already created? Sorry if my English is bad!
Thank you in advance!
This function will probably fit your needs
public void ReplaceItemAt(Grid grid, FrameworkElement fe, int row, int col)
{
// clear desired cell
var items = grid.Children
.Where(x => Grid.GetRow(x) == row && Grid.GetColumn(x) == col)
.ToArray();
foreach(var item in items) grid.Children.Remove(item);
// make sure the new item is positioned correctly
Grid.SetRow(fe, row);
Grid.SetColumn(fe, col);
// insert the new item into the grid
grid.Children.Add(fe);
}
Related
I'm assigning textboxes to cells in a grid but will like to confirm if an object already exists in the cell before assigning. Is it possible to query a row at a specific column that returns null if empty?
I could create a list of lists representing the grid which I modify as i add and remove objects but this sounds to be inefficient.
A sample code I've written:
TextBlock _text = new TextBlock()
{
Text = _cont,
Background = new SolidColorBrush(_colo.disciplinecolor)
}; TextBlockStyle(_text);
int index = SearchDate((DateTime)_dt);
Grid.SetRow(_text, 1); Grid.SetColumn(_text, index);
Maindispgrid.Children.Add(_text);
Essentially this code block is called every time the user clicks a button with the TextBlock added to a dated column(pre-selected by the user), and hopefully, the next available row in the column . I've tried GetRow() but this searched by UIElement which didn't seem to work as all TextBlock are created with the same name.
I might have approached this all wrong so any leads as to what I need to read up on will be much appreciated.
Basically the end result should hopefully work as this:
TextBlock _text = new TextBlock()
{
Text = _cont,
Background = new SolidColorBrush(_colo.disciplinecolor)
}; TextBlockStyle(_text);
int index = SearchDate((DateTime)_dt);
//check for next available row at specific column index
Grid.SetRow(_text, nextAvailableRow); Grid.SetColumn(_text, index);
Maindispgrid.Children.Add(_text);
You can iterate over the children list via Maindispgrid.Children. For each child, retrieve the assigned Row and Column value (if assigned at all). Use this information to calculate the available row.
IList<int[]> indices = new List<int[]>();
foreach (var child in Maindispgrid.Children)
{
int rowIndex = Grid.GetRow(child);
int columnIndex = Grid.GetColumn(child);
indices.Add(new int[] {rowIndex, columnIndex});
}
// work with the "indices" list
The goal is to copy the selected cell data out of a selected row.
I'm doing this by catching the CopyingRowClipBoardContent event inside my datagrid and redirecting it to this code:
var currentCell = e.ClipboardRowContent[VwrGrid.CurrentCell.Column.DisplayIndex];
e.ClipboardRowContent.Clear();
e.ClipboardRowContent.Add(currentCell);
This works perfectly! the only issue, is that if some of the columns are hidden, DisplayIndex reads improperly.
So if we have Item 1, Item 2, and Item 3.
If all are showing and I selected item3 and copy it, I get the cell value in Item 3.
The problem is, If Item 2 is collapsed/not shown, then copying Item 3 will tell you you're trying to copy out of bounds. because it's counted displayIndex , 3 from the left, and only two were shown. so it's moved outside of the table
For WPF Datagrid, try this:
// The clipboard row works only for visible cells
// To obtain the data column use the columnIndex and then map that to the Columns collection
int columnIndex = dataGrid.CurrentCell.Column.DisplayIndex;
var column = dataGrid.Columns[columnIndex];
// Now get the needed column
var cellContent = e.ClipboardRowContent.Where(i => i.Column == column).First();
e.ClipboardRowContent.Clear();
e.ClipboardRowContent.Add(cellContent);
For Winforms:
Use .Index instead. .DisplayIndex applies only to visible columns.
Because this is WPF and I can't simply use an index, I just iterated through the columns and counter the number of columns that had their visibility set to collapsed up to the column we were attempting to grab the displayindex for. Then subtracted that number from the displayIndex.
private void DataGrid_CopyingRowClipboardContent(object sender, DataGridRowClipboardEventArgs e)
{
//because we need to use displayindex, we need to check how many collapsed columns there are before our column, and adjust our display index accordingly
int invisibleCols = 0;
foreach(DataGridColumn col in VwrGrid.Columns)
{
if (col.Visibility == Visibility.Collapsed)
invisibleCols++;
if (col.Header.ToString() == VwrGrid.CurrentCell.Column.Header.ToString()) break;
}
try
{
var currentCell = e.ClipboardRowContent[VwrGrid.CurrentCell.Column.DisplayIndex - invisibleCols];
e.ClipboardRowContent.Clear();
e.ClipboardRowContent.Add(currentCell);
}
catch
{
}
}
In winforms I need to retrieve the position of each column in my DataGridView, to do this I use this function:
Rectangle rec = dgv.GetColumnDisplayRectangle(getColumnIndexByName(entry.Key), true);
and give me the rec of the column, but if I have a table with no records, the function get a rec with 0 value...
How can I solve this??
here is what I have if the grid has rows:
in the blue panel I've got some textbox that I use as filter of the value of the column below
Now if the grid has some rows, it works perfectly, I get right the column rectangle, I obtain the left and width and I'm able to place the filters above the header.. but if I set a wrong filter and the query retrieve 0 records, I don't know where place the textboxes
Edit: the code of getColumnIndexByName:
protected int getColumnIndexByName(string name)
{
foreach (DataGridViewColumn col in dgv.Columns)
{
if (col.Name.ToLower().Trim() == name.ToLower().Trim()) return col.Index;
}
return -1;
}
thanks
GetColumnDisplayRectangle returns Rectangle.Empty if the column is not Displayed.
You may also want to take a look at source code for GetColumnDisplayRectanglePrivate method which is used by DataGridView to calculate rectangle of the given column.
The method contains following code:
if (!this.Columns[columnIndex].Displayed)
{
return Rectangle.Empty;
}
Workaround
If you are looking for a workaround, you can use the following code which gets a list of rectangles without any flicker:
this.SuspendLayout();
var width = this.dataGridView1.Width;
this.dataGridView1.Width = 8388607;
var rectangles = this.dataGridView1.Columns.Cast<DataGridViewColumn>()
.Select(x => dataGridView1.GetColumnDisplayRectangle(x.Index, false))
.ToList();
this.dataGridView1.Width = width;
this.ResumeLayout();
I am trying to obtain DataGridRow from my DataGrid based on index. I am using following code:
public DataGridRow GetGridRow(int index)
{
DataGridRow row = (DataGridRow)DG_Statement.ItemContainerGenerator.ContainerFromIndex(index);
if (row == null)
{
// May be virtualized, bring into view and try again.
DG_Statement.UpdateLayout();
DG_Statement.ScrollIntoView(DG_Statement.Items[index]);
row = (DataGridRow)DG_Statement.ItemContainerGenerator.ContainerFromIndex(index);
}
return row;
}
Ref Link - Get row in datagrid
But unfortunately its returning a null object of DataGridRow.
If I check the Items[] property of my grid I could see 13 items.
Need suggestion on how to obtain the Grid Row as I want to change color of top 2 and bottom 2 rows of my data grid.
Any help is appreciated. Thanks!!
Adding Screenshot of DataGrid Items
Important Update
If I call GetGridRow() from the SelectedIndexChanged Event of the Grid it works flawlessly.
On the other hand, if I call it after I construct the object of the page on which my grid is displayed it returns row object as NULL.
So if its in the code behind. You can just get the selected index of the DataGrid. I've named the datagrid dataGrid as an example.
var rowIndex = dataGrid.SelectedIndex;
var row = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(selectedIndex);
Check to make sure the index you're passing in is actually within bounds.
I have one listview whith several columns.
I want to fill this listview in a vertical form
column to column.
Sorry, but this is not (easily) possible.
A ListView has a list of ListViewItems, where each one has a List of ListViewSubItems (and to make it a little more complex at the first spot, the first ListViewSubItem is the same as the ListViewItem itself).
So if you like to fill up a ListView column by column you first have to add the ListViewItems to the ListView for all the values you want in the first column.
Afterwards you iterate through the ListView.Items and call on every ListViewItem.Subitems.Add to fill up the next column. This must be done for each column you like to fill.
If you like to fill in the column values in another order then from left to right, you should take a look into the DisplayIndex of the ColumnHeader within the ListView.Columns.
Some example code:
// Some values
var someValues = Enumerable.Range(1, 10);
// Fill up the first column
foreach (var item in someValues)
{
listView.Items.Add("0." + item);
}
// Run for each column in the listView (the first is already filled up)
foreach (ColumnHeader column in listView.Columns.Cast<ColumnHeader>().Skip(1))
{
// Get the value and the index for which row the value should be
foreach (var item in someValues.Select((Value, Index) => new { Value, Index }))
{
// Add the value to the given row, thous leading to be added as new column
listView.Items[item.Index].SubItems.Add(column.Index + "." + item.Value);
}
}