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);
}
}
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
{
}
}
I'm trying to find a way to add data from one datagrid to another and for that data to be inserted to only one column at a time in my second datagrid. The specific column is created each time the Add button has been clicked.
My coding so far:
private void btnFeedbackAddSupplier_Click(object sender, RoutedEventArgs e)
{
dgFeedbackSelectSupplier.Items.Clear(); //So that my rows do not stack each other on every add
DataGridTextColumn columnSupplier = new DataGridTextColumn();
columnSupplier.Binding = new Binding("Supplier");
DataGridTextColumn columnFeedbackSupplierItem = new DataGridTextColumn();
//The 'Item' column is binded in XAML
columnSupplier.Header = (cmbFeedbackSelectSupplier.SelectedItem as DisplayItems).Name;
columnSupplier.IsReadOnly = true;
dgFeedbackAddCost.SelectAll(); //Selects all the rows in 1st datagrid
//Casts selected rows to my 'ViewQuoteItemList' class
IList list = dgFeedbackAddCost.SelectedItems as IList;
IEnumerable<ViewQuoteItemList> items = list.Cast<ViewQuoteItemList>();
var collection = (from i in items let a = new ViewQuoteItemList { Item = i.Item, Supplier = i.Cost }
select a).ToList();
//Adds both the column and data to the 2nd datagrid
dgFeedbackSelectSupplier.Columns.Add(columnSupplier);
foreach (var item in collection)
dgFeedbackSelectSupplier.Items.Add(item);
}
My reason for wanting to add the data to only one separate column at a time is because the data is different each time I want to add it to my 2nd datagrid and it overwrites any previous data that was entered in older add's.
EDIT: I Here are some images of what my current problem is
Here I add the first company and it's values. Everything works fine
Here I add the second company with it's new values, but it changes the values entered with the first company. This is my big problem. So you can see how my values are changed from the first to the second image
I think your problem here is that all your columns are bound to the same property: Supplier. Since you're updating that property everytime, all columns are assigned the same value. In the end, there's only one Supplier property for each row, so you can't show a different value for that single property on each column since everytime you change that property's value, the Bindings get notified and update themselves.
Maybe you could try using a OneTime Binding instead of a regular one. That way, the cells would retain the value they had when you first added them to the DataGrid. But for that to work, you should avoid clearing the DataGrid's items list, since re-adding the items would force them to rebind again.
Another option would be having a list of suppliers in your Supplier property, and have each column bind to an index of that list.
private void btnFeedbackAddSupplier_Click(object sender, RoutedEventArgs e)
{
// ...
columnSupplier.Binding = new Binding(string.Format("Supplier[{0}]", supplierColumnIndex));
// ...
var supplierCosts = new List<int>();
// ...
// Fill the list with the Costs of the Suppliers that correspond to each column and item
// ...
var collection = (from i in items let a = new ViewQuoteItemList { Item = i.Item, Supplier = supplierCosts }
select a).ToList();
//Adds both the column and data to the 2nd datagrid
dgFeedbackSelectSupplier.Columns.Add(columnSupplier);
foreach (var item in collection)
dgFeedbackSelectSupplier.Items.Add(item);
}
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 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);
}