I am using a ComponentOne DataTree that is a FlexGrid with child grids. The parent grid has 2 columns a 'Select' column which is a checkbox and another column that is read-only. The child grid has 5 columns. The first is a checkbox and the other 4 are readonly. The read-only columns appear gray by default. I set the DataTable columns that is the data source of the grids to ReadOnly. I want the non-header columns to have a background of white by default. Neither grid is updated.
I define the style as a member variable and create the style in the Initialize method:
C1.Win.C1FlexGrid.CellStyle defaultRowStyle;
private void InitializeControls()
{
txtWorkZone.Enabled = true;
txtWorkZone.Focus();
defaultRowStyle = c1flxdatatreeCasePick.Styles.Add("DefaultRowStyle");
defaultRowStyle.BackColor = Color.White;
}
This is the OwnerDrawCell method that sets it:
private void c1flxdatatreeCasePick_OwnerDrawCell(object sender, OwnerDrawCellEventArgs e)
{
C1FlexDataTree grid = sender as C1FlexDataTree;
if (grid == null || grid.DataSource == null)
return;
if(e.Row > 0)
grid.Rows[e.Row].Style = grid.Styles["DefaultRowStyle"];
//Get the child grid
C1FlexDataTree childGrid = grid.Rows[e.Row].UserData as C1FlexDataTree;
if (childGrid != null)
{
if(e.Row > 0)
childGrid.Rows[e.Row].Style = grid.Styles["DefaultRowStyle"];
}
}
Why won't the grids get the row style setting?
Thanks
Gloria
You wont be able to use OwnerDrawCell as you've expected here. After the FlexGrid is loaded on the form use the following snippet used to repaint readonly columns background:
C1.Win.C1FlexGrid.CellStyle cs;
cs = _flex.Cols[2].StyleDisplay;
cs.BackColor = Color.White;
cs = _flex.Cols[3].StyleDisplay;
cs.BackColor = Color.White;
If you need to change the background color of the Child Tables you have to change each child's properties individually. Use the following snippet to access the Child tables:
for (int row = 0; row < _flex.Rows.Count; row++)
{
C1FlexDataTree child = _flex.Rows[row].UserData as C1FlexDataTree;
if (child != null)
{
// Access Child Tables here
}
}
To make the child tables in my C1FlexDataTree read-only:
for (int row = 0; row < _flex.Rows.Count; row++)
{
C1FlexDataTree child = _flex.Rows[row].UserData as C1FlexDataTree;
if (child != null)
{
foreach (Column c in child.Cols)
{
c.AllowEditing = false;
}
}
}
Related
I would like to get all rows in order to check some rows that are the same in the database , I'm try using many solutions in StackOverlow but any of them work for me :
Get row in datagrid
WPF Datagrid set selected row
for (int i = 0; i < dataGrid.Items.Count; i++)
{
DataGridRow row = (DataGridRow)dataGrid.ItemContainerGenerator
.ContainerFromIndex(i);
}
This code return value cannot be null Exception.
I have tried also this line of code and I'm got the same Exception ( the object currentitem was null ).
var currentItem = myDataGrid.SelectedItem as MyObject;
Complete Code:
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
grid.ItemsSource = null;
grid.ItemsSource = work;
grid.Items.Refresh();
for (int i = 0; i < grid.Items.Count; i++) // My grid items count equals to 7
{
DataGridRow row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(i); // this value was null
var currentItem = grid.SelectedItem as object; // this value was null
}
}
You could bind the item source of your DataGrid to an ObservableCollection and run a foreach loop over it.
I think that makes things a lot easier.
Finally I got it , I fixed the error by using this code :
for (int i = 0; i < grid.Items.Count; i++)
{
GridModel row = (GridModel)grid.Items[i];
}
// Note : The grid model is a class for the Datagrid ( properties are the same as the columns name of the datagrid
Good day
I must be missing something really simple here; I have a datagrid with two combobox columns and a datagridtextcolumn. Once the user has selected a value for both of these comboboxes (a value ranging from 1 to 5), a calculation is done with these 2 values (on a combobox selection changed event). I need to write the result of the calculation in to a cell (the datagridtextcolumn) and change the background of that cell to a specific colour based on the value. I have managed to find the values in the comboboxes and the index of the current row, but accessing the relevant cell to write the result to is getting the better of me...
Here is the coding for the event handler that calls the calculation thus far:
private void cmbConseq_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var cellInfos = dgDeviation.SelectedCells;
if (cellInfos == null)
{
return;
}
var content = cellInfos[0].Column.GetCellContent(cellInfos[0].Item);
DataRowView row = (DataRowView)content.DataContext;//get the datacontext from FrameworkElement and typecast to DataRowView
object[] obj = row.Row.ItemArray;//ItemArray returns an object array with single element
int likely = Convert.ToInt16(obj[0]);
int cons = Convert.ToInt16(obj[1]);
int riskValue = new Calculations().riskRankingCalc(likely, cons);
int rowIndex = dgDeviation.Items.IndexOf(dgDeviation.CurrentItem);
How do I write the 'riskValue' variable to the relevant cell in the currently selected row in the eventhandler?
After a bit of experimentation and help from other SO questions, the solution that worked for me was to implement the following two helper methods:
public static T GetVisualChild<T>(Visual parent) where T : Visual
{
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++)
{
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null)
{
child = GetVisualChild<T>(v);
}
if (child != null)
{
break;
}
}
return child;
}
public static DataGridCell GetCell(DataGrid grid, int column)
{
DataGridRow row = grid.ItemContainerGenerator.ContainerFromIndex(grid.SelectedIndex) as DataGridRow;
if (row != null)
{
DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(row);
if (presenter == null)
{
grid.ScrollIntoView(row, grid.Columns[column]);
presenter = GetVisualChild<DataGridCellsPresenter>(row);
}
DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
return cell;
}
return null;
}
And then to make the change in the cell is as easy as calling: GetCell(myDatagrid, columnIndex).Content = "New Value";
I am developing a software and i need different form of a DataGridView.
I created them and inserted them into an array with this method:
private DataGridView[] cloneDataGridViews(int posCount, DataGridView dataGridView)
{
List<DataGridView> dataGridViewList = new List<DataGridView>();
for(int i=0;i<posCount;i++)
{
DataGridView dgv = new DataGridView();
dgv = dataGridView;
dataGridViewList.Add(dgv);
}
return dataGridViewList.ToArray();
}
And I am trying to show them with this code:
void GridViewSelectorLoad(object sender, System.EventArgs e)
{
this.AutoScroll = true;
int startY = 30;
for(int i=0;i<dataGridViewArray.Length;i++)
{
int height = dataGridViewArray[i].Height;
int posY = startY + 10 + i*height;
Panel pnl = new Panel();
pnl.Controls.Add(dataGridViewArray[i]);
dataGridViewArray[i].Parent = pnl;
pnl.Location = new Point(100,posY);
pnl.Name = "pnl"+i.ToString();
pnl.Height = dataGridViewArray[i].Height;
pnl.Width = dataGridViewArray[i].Width;
pnl.Parent = this;
this.Controls.Add(pnl);
}
}
But it shows just one datagridview, how can I show all of them?
What is wrong with that code?
A control can only have one parent, but you're trying to set the same DataGridView as a child of multiple Panels.
for(int i=0;i<posCount;i++)
{
DataGridView dgv = new DataGridView();
dgv = dataGridView; // not creating a new instance of DataGridView
dataGridViewList.Add(dgv);
}
Here's the relevant part of the Controls.Add() method that causes this behavior.
if (value.parent != null)
{
value.parent.Controls.Remove(value);
}
You've got a single instance of DataGridView that you add to each new Panel. Each time, it's Parent property is set to the latest Panel. Then when you try adding it to the next Panel, the code above removes it from the previous one.
If you create a new instance inside the loop, it works fine. You'll need to copy over those values from the existing DataGridView that you wish to have in each new DataGridView instance.
for(int i=0; i<posCount; i++)
{
DataGridView dgv
= new DataGridView
{
Name = dataGridView.Name,
DataSource = dataGridView.DataSource,
...
};
dataGridViewList.Add(dgv);
}
cloneDataGridViews is not cloning the datagrid, its adding the same instance multiple times:
dgv = dataGridView;
It has been pointed out that all you are copying in your code is the same old reference to the same DGV into each slot of your list. Instead you will have to copy both the column structure and the values of all cells like this:
public DataGridView cloneDataGridView(DataGridView oldDGV)
{
DataGridView newDGV = new DataGridView();
foreach (DataGridViewCell cell in oldDGV.Rows[0].Cells)
newDGV.Columns.Add(new DataGridViewColumn(cell));
newDGV.Rows.Add(oldDGV.Rows.Count);
for (int row = 0; row < oldDGV.Rows.Count; row++)
for (int col = 0; col < oldDGV.Columns.Count; col++)
newDGV[col, row].Value = oldDGV[col, row].Value;
return newDGV;
}
You could call it like this:
for(int i=0;i<posCount;i++)
{
DataGridView dgv = cloneDataGridView(dataGridView);
dataGridViewList.Add(dgv);
}
Note: This piece of code assumes that there is at least one row in the source DGV.
i am trying to delete grid view data as i am filling grid like,
public void FillCompanyInfo()
{
DataTable dtCompanyInfo = new DataTable();
dtCompanyInfo = objFunctions.GetCompanyInfo();
if(dtCompanyInfo.Rows.Count>0)
{
dgvCompany.DataSource = dtCompanyInfo;
}
if (dtCompanyInfo.Rows.Count > 0)
{
if (this.dgvCompany.Columns.Count == 8)
{
DataGridViewCheckBoxColumn checkColumn = new DataGridViewCheckBoxColumn();
checkColumn.Name = "";
checkColumn.HeaderText = "Select";
checkColumn.Width = 50;
checkColumn.ReadOnly = false;
checkColumn.FillWeight = 10; //if the datagridview is resized (on form resize) the checkbox won't take up too much; value is relative to the other columns' fill values\\
dgvCompany.Columns.Add(checkColumn);
}
}
}
After filling grid i click on grid row and click delete button as,
private void btn_Delete_Click(object sender, EventArgs e)
{
foreach (DataGridViewRow r in dgvCompany.Rows)
{
if (Convert.ToBoolean(r.Cells[8].Value)) //cells[4] CONTAINS CHECKBOX COLUMN
{
string strId = r.Cells[1].Value.ToString(); //cells[0] CONTAINS EMPIDCOLUMN
objFunctions.DeleteCompany(strId);
}
}
FillCompanyInfo();
}
But it delete the data wrongly in my grid view i get fields numeric and string from 0 to 6 and chk box at 7th place while after binding data to grid i also attach one more column at 8 place may me it is due to some that reason ?
while debugging i suddenly notice at this place,
foreach (DataGridViewRow r in dgvCompany.Rows)
that grid view have column in this manner chk box at zero position then seven fild and again then chk box at 8 place how it change the order ?
hopes for your suggestion thanks in advance
You need to clear the grid view data source before bind it.Please Refer this link to clear grid view. try this code
Datagridview remove all columns
public void FillCompanyInfo()
{
dataGridView1.DataSource = null;
dataGridView1.Columns.Clear();
dtCompanyInfo = GetCompanyInfo();
if (dtCompanyInfo.Rows.Count > 0)
{
dataGridView1.DataSource = dtCompanyInfo;
DataGridViewCheckBoxColumn checkColumn = new DataGridViewCheckBoxColumn();
checkColumn.Name = "";
checkColumn.HeaderText = "Select";
checkColumn.Width = 50;
checkColumn.ReadOnly = false;
checkColumn.FillWeight = 10; //if the datagridview is resized (on form resize) the checkbox won't take up too much; value is relative to the other columns' fill values\\
dataGridView1.Columns.Add(checkColumn);
}
}
.Net 4 WPF DataGrid MVVM
User clicks add button which triggers command on viewmodel. In the viewmodel command execute, I add a new object to the viewcollection of the viewmodel that the grid is bound to. The new row does appear in my grid. However, I also want to send the focus to the first editable cell in that new row.
I even "cheated" mvvm, added an event on my viewmodel that the view listens to, to know when to focus the new row.
I've searched but no luck. I was hopeful when I came across this:
Datagrid Set focus on newly added row
which leads to
http://social.msdn.microsoft.com/forums/en-US/wpf/thread/63974f4f-d9ee-45af-8499-42f29cbc22ae
But the problem that others have reported and no one has answered is how to deal with the virtualizing behaviour of the grid. The newly added row has not yet been created. So that GetCells call fails frequently. And if ScrollIntoView is required, then it's that much more likely to fail.
I've hooked a ton of events including LoadingRow and RequestBringIntoView with no luck. Depending on which event I hook, I have managed to be able to get a reference to the cell. But then I get an error "Cannot call StartAt when content generation is in progress". But I checked the status of the ItemContainerGenerator and it was ContainersGenerated when I made the call to the cell's BeginEdit.
Here is one way to set focus to a particular cell programmatically:
DataGridCell cell = GetCell(rowIndex, colIndex);
cell.Focus;
Please see the following article for more information on GetCell().
This seemed to work for me:
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
private void SetFocusOnNewRow(DataGrid theDataGrid, Int32 columnIndex)
{
theDataGrid.UnselectAll();
theDataGrid.UpdateLayout();
Int32 newRowIndex = theDataGrid.Items.Count - 1;
theDataGrid.ScrollIntoView(theDataGrid.Items[newRowIndex]);
DataGridRow newDataGridRow = theDataGrid.ItemContainerGenerator.ContainerFromIndex(newRowIndex) as DataGridRow;
DataGridCellsPresenter newDataGridCellsPresenter = GetVisualChild<DataGridCellsPresenter>(newDataGridRow);
if (newDataGridCellsPresenter != null)
{
DataGridCell newDataGridCell = newDataGridCellsPresenter.ItemContainerGenerator.ContainerFromIndex(columnIndex) as DataGridCell;
if (newDataGridCell != null)
newDataGridCell.Focus();
}
}
static T GetVisualChild<T>(Visual parent) where T : Visual
{
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++)
{
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null)
{
child = GetVisualChild<T>(v);
}
if (child != null)
{
break;
}
}
return child;
}
This is work for me:
private void button_Click(object sender, RoutedEventArgs e)
{
//Scroll to the last row
var border = VisualTreeHelper.GetChild(dataGrid, 0) as Decorator;
if (border != null)
{
var scroll = border.Child as ScrollViewer;
if (scroll != null) scroll.ScrollToEnd();
}
//Edit the first cell of the last row
int lastRow = dataGrid.Items.Count - 1;
DataGridCell cell = GetCell(lastRow, 0);
cell.Focus();
dataGrid.BeginEdit();
}
public DataGridCell GetCell(int row, int column)
{
DataGridRow rowContainer = GetRow(row);
if (rowContainer != null)
{
DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);
// try to get the cell but it may possibly be virtualized
DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
if (cell == null)
{
// now try to bring into view and retreive the cell
dataGrid.ScrollIntoView(rowContainer, dataGrid.Columns[column]);
cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
}
return cell;
}
return null;
}
public DataGridRow GetRow(int index)
{
DataGridRow row = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(index);
if (row == null)
{
// may be virtualized, bring into view and try again
dataGrid.ScrollIntoView(dataGrid.Items[index]);
row = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(index);
}
return row;
}
static T GetVisualChild<T>(Visual parent) where T : Visual
{
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++)
{
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null)
{
child = GetVisualChild<T>(v);
}
if (child != null)
{
break;
}
}
return child;
}