I want to group rows which is having same Name in DataGridView on Windows Forms below is the image what I want to implement.
Is it possible to implement below without using any third party tool ?
in the DataGridView place the following code in the
dgvProduct_CellFormatting Event
If e.RowIndex > 0 And e.ColumnIndex = 0 Then
If dgvProduct.Item(0, e.RowIndex - 1).Value = e.Value Then
e.Value = ""
ElseIf e.RowIndex < dgvProduct.Rows.Count - 1 Then
dgvProduct.Rows(e.RowIndex).DefaultCellStyle.BackColor = Color.White
End If
End If
All done!
Enjoy
You could try using the functionality of MSFlexGrid's MergeCells property of vertical cell merging instead of row grouping as explained in this article DataGridView Grouping in C#/VB.NET: Two Recipes. In this example, rows which belong to a group are joined visually using cells merged vertically - instead of using classical horizontal group rows.
protected override void OnCellPainting(DataGridViewCellPaintingEventArgs args)
{
base.OnCellPainting(args);
args.AdvancedBorderStyle.Bottom =
DataGridViewAdvancedCellBorderStyle.None;
// Ignore column and row headers and first row
if (args.RowIndex < 1 || args.ColumnIndex < 0)
return;
if (IsRepeatedCellValue(args.RowIndex, args.ColumnIndex))
{
args.AdvancedBorderStyle.Top =
DataGridViewAdvancedCellBorderStyle.None;
}
else
{
args.AdvancedBorderStyle.Top = AdvancedCellBorderStyle.Top;
}
}
To supplement the (chosen) answer, here's the full code. The unmentioned idea is a class extending the DataGridView class.
public class GroupByGrid : DataGridView
{
protected override void OnCellFormatting(
DataGridViewCellFormattingEventArgs args)
{
// Call home to base
base.OnCellFormatting(args);
// First row always displays
if (args.RowIndex == 0)
return;
if (IsRepeatedCellValue(args.RowIndex, args.ColumnIndex))
{
args.Value = string.Empty;
args.FormattingApplied = true;
}
}
private bool IsRepeatedCellValue(int rowIndex, int colIndex)
{
DataGridViewCell currCell =
Rows[rowIndex].Cells[colIndex];
DataGridViewCell prevCell =
Rows[rowIndex - 1].Cells[colIndex];
if ((currCell.Value == prevCell.Value) ||
(currCell.Value != null && prevCell.Value != null &&
currCell.Value.ToString() == prevCell.Value.ToString()))
{
return true;
}
else
{
return false;
}
}
protected override void OnCellPainting(
DataGridViewCellPaintingEventArgs args)
{
base.OnCellPainting(args);
args.AdvancedBorderStyle.Bottom =
DataGridViewAdvancedCellBorderStyle.None;
// Ignore column and row headers and first row
if (args.RowIndex < 1 || args.ColumnIndex < 0)
return;
if (IsRepeatedCellValue(args.RowIndex, args.ColumnIndex))
{
args.AdvancedBorderStyle.Top =
DataGridViewAdvancedCellBorderStyle.None;
}
else
{
args.AdvancedBorderStyle.Top = AdvancedCellBorderStyle.Top;
}
}
}
source courtesy of social.msdn.microsoft
Related
I have set up a form in which I have a column of checkboxes in the right column. The left columns contain data that is read-only if the corresponding checkbox column is unchecked and editable when checked. Since the data columns are dependent on each other for calculations I need (2) checked rows of the data columns editable at a time. I would like the checkable boxes to be limited to any (2) with the remaining boxes to not be checkable until at least one of the checked boxes is unchecked. I figured the best way would be to keep a running total of the number of checked boxes and somehow limit this, but I'm stuck at how to accomplish this. The code below just outputs a persistant GlobalVar.NumChecked = -1 value. Any help or direction would be appreciated.
private void dgvParameters_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
DataGridView dgPG = dgvParameters;
if (e.RowIndex < 0) return;
GlobalVar.NumChecked = 0;
foreach (DataGridViewRow row in dgvParameters.Rows)
{
if (e.RowIndex < 0) return;
DataGridViewCheckBoxCell cell = row.Cells[5] as DataGridViewCheckBoxCell;
if (cell.Value == cell.TrueValue)
{
GlobalVar.NumChecked += 1;
break;
}
if (cell.Value != cell.TrueValue)
{
GlobalVar.NumChecked -= 1;
break;
}
}
label2.Text = Convert.ToString(GlobalVar.NumChecked); //Debug output
}
Don't wait until the cell's Value changes by handling the CellValueChanged event. Handle the CurrentCellDirtyStateChanged event instead to cancel assigning the new value (true) by calling the CancelEdit method if you have two checked cells already.
// +
using System.Linq;
// ...
private void dgvParameters_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (dgvParameters.CurrentCell is DataGridViewCheckBoxCell &&
dgvParameters.IsCurrentCellDirty &&
!(bool)dgvParameters.CurrentCell.FormattedValue)
{
var count = dgvParameters.Rows.Cast<DataGridViewRow>()
.SelectMany(r => r.Cells.OfType<DataGridViewCheckBoxCell>()
.Where(c => (bool)c.FormattedValue))
.Count();
if (count == 2) dgvParameters.CancelEdit();
}
}
If you have more than one DataGridViewCheckBoxColumn in the grid, then you need to specify that in the query as well.
private void dgvParameters_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
int tarCol = 2;
if (dgvParameters.CurrentCell is DataGridViewCheckBoxCell &&
dgvParameters.CurrentCell.ColumnIndex == tarCol &&
dgvParameters.IsCurrentCellDirty &&
!(bool)dgvParameters.CurrentCell.FormattedValue)
{
var count = dgvParameters.Rows.Cast<DataGridViewRow>()
.SelectMany(r => r.Cells.OfType<DataGridViewCheckBoxCell>()
.Where(c => c.ColumnIndex == tarCol)
.Where(c => (bool)c.FormattedValue))
.Count();
if (count == 2) dgvParameters.CancelEdit();
}
}
I want with a condition :
all rows have bool_badge =0 : color with RED
all rows have bool_badge=1 : color with ForestGreen
I have a code Correct BUT just when i click for a cell specific
My code:
foreach (DataGridViewRow dr in dataGridView1.Rows)
{
int row = this.dataGridView1.CurrentCell.RowIndex;
string valeur = dataGridView1[2, row].Value.ToString();
if (valeur == "0")
{
dataGridView1.DefaultCellStyle.SelectionBackColor = Color.Red;
}
else
{
dataGridView1.DefaultCellStyle.SelectionBackColor = Color.ForestGreen;
}
}
The Result :
1) `
2)
But I want when i execute my application , the test begin if bool_badge 0 or 1, and i have for all the gridview : color RED or ForestGreen ,
I try this code:
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
string valeur = dataGridView1[2, i].Value.ToString();
if (valeur == "0")
{
dataGridView1.DefaultCellStyle.SelectionBackColor = Color.Red;
}
else
{
dataGridView1.DefaultCellStyle.SelectionBackColor = Color.ForestGreen;
}
}
But i have ERROR!
this is :
How can i fix it?
Very thanks,
You can use Datagridview's Cell_Formatting event.
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (dataGridView1.Columns[e.ColumnIndex].HeaderText == "bool_badge" && dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value != null)
// if the column is bool_badge and check null value for the extra row at dgv
{
if (dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString() == "0")
{
dataGridView1.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Red;
}
if (dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString() == "1")
{
dataGridView1.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.ForestGreen;
}
}
}
Result will be,
Hope helps,
You should use .Rows and .Cells properties.
string valeur = dataGridView1.Rows[i].Cells[2].Value.ToString();
For helping you debugging don't do Value.ToString(); just
var value = dataGridView_XXX.Rows[rowNumber].Cells[i].value;
And
if (value == null) display your row/column index
else dataGridView_XXX.Rows[rowNumber].DefaultCellStyle.BackColor = xxx;
I have 2 gridControl and I wanna change background of cells (rows) that different between 2 gridControl with primary key is multiple field set by user.
Any solution for this problem?
See this example image
In this two query, key field is col1, col2, col3 and col4. Different in col6 and I want to highlight cell that have different value.
This is my current code for RowCellStyle event
private void gvQuery1_RowCellStyle(object sender, RowCellStyleEventArgs e)
{
if (gcQuery2.DataSource == null || lsKey == null || lsKey.Count <= 0)
return;
List<object> id = new List<object>();
foreach (KeyObject key in lsKey)
{
id.Add((sender as GridView).GetRowCellValue(e.RowHandle, key.key1[1].ToString()));
}
for (int i = 0; i < gvQuery2.RowCount; i++)
{
int rowHandle = gvQuery2.GetVisibleRowHandle(i);
bool flgEqual = true;
for (int j = 0; j < lsKey.Count; j++)
{
object v = gvQuery2.GetRowCellValue(rowHandle, gvQuery2.VisibleColumns[int.Parse(lsKey[j].key2[0].ToString())]);
if (id[j] == null && v == null)
continue;
if (!id[j].GetType().Equals(v.GetType()) || !id[j].ToString().Equals(v.ToString()))
{
flgEqual = false;
break;
}
}
if (flgEqual)
{
for (int k = 0; k < (sender as GridView).Columns.Count; k++)
{
if (!(sender as GridView).GetRowCellValue(e.RowHandle, (sender as GridView).Columns[k].FieldName).ToString()
.Equals(gvQuery2.GetRowCellValue(rowHandle, (sender as GridView).Columns[k].FieldName).ToString()))
{
if (e.Column.FieldName.Equals((sender as GridView).Columns[k].FieldName))
e.Appearance.BackColor = Color.Orange;
}
}
break;
}
}
}
Refer this: Customizing Appearances of Individual Rows and Cells
You can implement your functionality using the
GridView.RowCellStyle event. This event is fired for each cell in
a Grid View and thus it has Column and RowHandle parameters
that identify the cell being painted.
I assume that you have fixed number of records in both grid and also the order of the records are same. Then you can try to user same row handle to access the value from the both grid's MainView at RowCellStyle event as below:
using DevExpress.XtraGrid.Views.Grid;
// ...
private void gridView1_RowCellStyle(object sender, RowCellStyleEventArgs e) {
GridView View = sender as GridView;
GridView leftGridView = leftGrid.MainView as GridView; //It is up to you that which viewtype you have used.
if(e.Column.FieldName == "Col5") {
string srcVal= View.GetRowCellDisplayText(e.RowHandle, View.Columns["Col5"]); // You can use GetRowCellValue() method also to get the value from the cell.
string leftGridVal= leftGridView .GetRowCellDisplayText(e.RowHandle, leftGridView .Columns["Col5"]);
if(srcVal != leftGridVal) {
e.Appearance.BackColor = Color.DeepSkyBlue;
e.Appearance.BackColor2 = Color.LightCyan;
}
}
}
Above code snippet is just like a sudo code to direct you to implement the functionality.. Handle this event on that Grid on which you want to color.. Remember to take care about the RowHandle, you have take care about the row index.
Hope this help..
Use the GridView.RowCellStyle event, which enables appearance settings of individual cells to be changed
Please refer this site for your reference
https://www.devexpress.com/Support/Center/Question/Details/Q520842
void gridView1_RowCellStyle(object sender, RowCellStyleEventArgs e)
{
GridView currentView = sender as GridView;
if (e.Column.FieldName == "Customer")
{
bool value = Convert.ToBoolean(currentView.GetRowCellValue(e.RowHandle, "Flag_Customer"));
if (value)
e.Appearance.BackColor = Color.Red;
}
if (e.Column.FieldName == "Vendor")
{
bool value = Convert.ToBoolean(currentView.GetRowCellValue(e.RowHandle, "Flat_Vendor"));
if (value)
e.Appearance.BackColor = Color.Red;
}
}
I have a datagridview and a checkbox column attached to it. If the user checks a few rows and then presses a button, I would like to be able to get a certain cell value from each row where the box was ticked.
Something maybe like this:
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (Convert.ToBoolean(row.Cells[CheckBoxColumn1.Name].Value) == true)
{
//...
}
}
The problem is that the datagridview might contain up to 3000 or 4000 rows. I would like to see if there is a faster way to get the checked rows, other than to iterate through all the rows for the grid.
If you don't want to iterate all rows, then use temporary list of checked rows.
Then after button was clicked use values from that List
HashSet<DataGridViewRow> _CheckedRows = new HashSet<DataGridViewRow>();
private void DataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
if (DataGridView.Columns[e.ColumnIndex].Name.Equals(CheckBoxColumn1.Name) == false)
return;
DataGridViewRow row = DataGridView.Rows[e.RowIndex];
if (Convert.ToBoolean(row.Cells[CheckBoxColumn1.Name].Value) == true)
{
_CheckedRows.Add(row);
}
else
{
_CheckedRows.Remove(row);
}
}
You could manage your own list of checked rows.
You would bind to the dataGridView1.CellClick event, and add/remove rows from the list:
var checkedRows = new List<DataGridViewRow>();
dataGridView1.CellClick += (sender, args) =>
{
if (args.RowIndex != YOUR_CHECKBOX_COLUMN_INDEX)
{
return;
}
var cell = dataGridView1[args.ColumnIndex, args.RowIndex];
if (cell.Value == null)
{
cell.Value = false;
}
cell.Value = !(bool)cell.Value;
if ((bool)cell.Value)
{
checkedRows.Add(dataGridView1.Rows[args.RowIndex]);
}
else
{
checkedRows.Remove(dataGridView1.Rows[args.RowIndex]);
}
};
All you have to do then is:
foreach (DataGridViewRow row in checkedRows)
{
//...
}
You can use Linq like this :
var checkedRows = from DataGridViewRow r in dataGridView1.Rows
where Convert.ToBoolean(r.Cells[CheckBoxColumn1.Name].Value) == true
select r;
foreach (var row in checkedRows)
{
//
}
Using CheckBoxColumn1.Name instead of CheckBoxColumn1.Index seems like a tiny bottleneck to me.
To avoid the casting to DataGridViewRow and Boolean, my suggestion is something like (not tested):
int colIndex = CheckBoxColumn1.Index; // or dataGridView1.Columns.IndexOf(CheckBoxColumn1.Name) ?
for ( int r = 0; r < dataGridView1.RowCount; r++ )
{
if ( true.Equals( dataGridView1[colIndex, r].Value ) )
{
//...
}
}
The other answers that use cell events are better because the list of checked rows will be ready when needed, but also can be a bit harder to maintain/debug depending on how you do the filtering and rest. Here is my version:
private HashSet<int> checkedRowIndexes = new HashSet<int>();
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if ( e.ColumnIndex == CheckBoxColumn1.Index )
{
if ( true.Equals( dataGridView1[CheckBoxColumn1.Index, e.RowIndex].Value ) )
checkedRowIndexes.Add(e.RowIndex);
else
checkedRowIndexes.Remove(e.RowIndex);
}
}
I have one xtragrid control on my devxpress form . I've created the columns of my grid at runtime when i load the form . I'm developing the Field chooser for my grid view which is situated on the same form. For that i used the repositoryItemCheckedComboBoxEditcontrol & in that control i added the column names which will be present in the xtragrid.
Basically i created the columns to the xtragrid with the Visible property to false. When user checks particular column name by using repositoryItemCheckedComboBoxEdit then i set the Visible to true & again if user unchecked the column name then again i set the visible to false. & while creating column i set the width of the column.
Problem which i'm facing is that if user select the all fields from the repositoryItemCheckedComboBoxEdit then the grid control should show the horizontal scroll bar automatically when require.
And another problem is that with the columns is besides setting the width of the column, it is not showing the required width of that column . it shrinks that all column width .
code which i use for creating column to the xtragridview at run time is as follows -
public void AddGridColumn(string fieldName, string caption, int nRowWidth, RepositoryItem Item, object oCollection, string DisplayMember, string ValueMember, string format, FormatType type)
{
DevExpress.XtraGrid.Columns.GridColumn column = ColumnView.Columns.AddField(fieldName);
column.Caption = caption;
column.ColumnEdit = Item;
column.DisplayFormat.FormatType = type;
column.DisplayFormat.FormatString = format;
column.VisibleIndex = ColumnView.VisibleColumns.Count;
column.Width = nRowWidth;
}
code for the field chooser is as follows -
I used this function for filling the items of the repositoryItemCheckedComboBoxEdit control
private void FieldCollection()
{
allFields = new ArrayList();
columnNames = new Dictionary<string, string>();
allFields.Clear();
repositoryItemCheckedComboBoxEdit1.Items.Clear();
for (int i = 0; i < gvBase.Columns.Count; i++)
{
allFields.Add(gvBase.Columns[i].Caption );
if (gvBase.Columns[i].FieldName != "ContactID")
{
if (gvBase.Columns[i].Visible == true)
{
if (gvBase.Columns[i].Caption != "Label1" && gvBase.Columns[i].Caption != "Label2" && gvBase.Columns[i].Caption != "Label3" && gvBase.Columns[i].Caption != "Label4" && gvBase.Columns[i].Caption != "Label5")
repositoryItemCheckedComboBoxEdit1.Items.Add(gvBase.Columns[i].Caption, CheckState.Checked);
if (!columnNames.ContainsKey(gvBase.Columns[i].Caption))
columnNames.Add(gvBase.Columns[i].Caption, gvBase.Columns[i].FieldName);
}
else
{
if (gvBase.Columns[i].Caption != "Label1" && gvBase.Columns[i].Caption != "Label2" && gvBase.Columns[i].Caption != "Label3" && gvBase.Columns[i].Caption != "Label4" && gvBase.Columns[i].Caption != "Label5")
repositoryItemCheckedComboBoxEdit1.Items.Add(gvBase.Columns[i].Caption, CheckState.Unchecked);
if (!columnNames.ContainsKey(gvBase.Columns[i].FieldName))
columnNames.Add(gvBase.Columns[i].Caption, gvBase.Columns[i].FieldName);
}
}
}
cmbFieldChooser.EditValue = "";
}
this is used for the repositoryItemCheckedComboBoxEdit control event -
private void cmbFieldChooser_EditValueChanged(object sender, EventArgs e)
{
ArrayList temp = new ArrayList();
temp.AddRange(allFields);
string[] strFields = cmbFieldChooser.EditValue.ToString().Split(',');
for (int i = 0; i < strFields.Length; i++)
{
if (temp.Contains(strFields[i].Trim()))
temp.Remove(strFields[i].Trim());
if (strFields[i] != "")
{
if (columnNames.ContainsKey(strFields[i].Trim()))
{
if (gvBase.Columns[columnNames[strFields[i].Trim()]].Visible == false)
{
gvBase.Columns[columnNames[strFields[i].Trim()]].Visible = true;
gvBase.Columns[columnNames[strFields[i].Trim()]].BestFit();
}
}
}
}
if (temp.Count < 20)
{
for (int j = 0; j < temp.Count; j++)
{
if (columnNames.ContainsKey(temp[j].ToString().Trim()))
{
gvBase.Columns[columnNames[temp[j].ToString().Trim()]].Visible = false;
}
}
}
cmbFieldChooser.EditValue = repositoryItemCheckedComboBoxEdit1.GetCheckedItems();
if ((cmbFieldChooser.EditValue.ToString()).Split(',').Length > 5)
{
gvBase.OptionsView.ColumnAutoWidth = false;
gvBase.BestFitColumns();
gvBase.HorzScrollVisibility = ScrollVisibility.Always;
}
else
{
gvBase.OptionsView.ColumnAutoWidth = true;
gvBase.HorzScrollVisibility = ScrollVisibility.Never;
}
}
How to resolve this problem?
thanks.
How many columns do you have in your Grid?
I see you have code there to turn off the ColumnAutoWidth once you go past 5 columns (ie 6 columns or more). Have you debugged this condition to ensure the ColumnAutoWidth is indeed being turned off?
As per BestFitColumns Help Doc the BestFitColumns will only calculate for the first n rows as per the BestFitMaxRowCount property unless it it set to -1, could this be a cause?
The other thing that seems a little odd if that you are setting the EditValue of cmdFieldChooser within the cmdFieldChooser_EditValueChanged event... why so?