Compare today's date to a column and highlight the cell - c#

In my winform app , there is a column called "Next_Calibration_On"(in the format "dd-MM-yyyy") with which i have to compare today date if it is less than it then i want highlight the cell in the datagrid view in red .
Fr this i have the below code :
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
DateTime currentToday = (DateTime)this.dataGridView1.Rows[e.RowIndex].Cells["Next_Calibration_On"].Value;
if (currentToday <= DateTime.Now.Date)
{
e.CellStyle.ForeColor = Color.Red; //Font Color
e.CellStyle.SelectionForeColor = Color.Red; //Selection Font color
}
However this is showing the error message as below:
System.ArgumentException: 'Column named Next_Calibration_On cannot be found.Parameter name: columnName'
But i do have column in my table ..how to solve this?

Don't edit your cells. Tell your DataGridView where to fetch its data
Don't put the data directly in the DataGridView, tell it where to fetch its data, and how to display the fetched data. This separates your data from how it is displayed. Whenever you decide to display it differently you don't have to change your original data.
You can see how this separation between data and display is done in a spreadsheet. The spreadsheet data can be shown as a collection of cells layed out in columns and rows, and displaying textual representation of the values in the cells.
Another method to show the same data would be in a graph: even though the display is entirely different than a collection of cells, the data behind is the same.
Same data, differently displayed.
In winforms you have the same separations with all Controls that show sequences of data: ListBox, ListView, DataGridView, Chart, etc.
All these classes offer the possibility to directly add the data to the component, but they also have a property DataSource.
If you assign a sequence to the DataSource, something like a List or Array, the Data is displayed. other properties decide how each element of the DataSource must be displayed.
In a DataGridView the DataGridViewColumns define which property of each row must be displayed, and how they must be displayed.
In its most easy form:
Suppose you have a class Customer:
class Customer
{
public int Id {get; set;}
public string Name {get; set;}
public Address Address {get; set;}
public string PhoneNr {get; set;}
};
Suppose you also have a DataGridView that shows only the Id and Name of Customers
DataGridViewColumn columnCustomerId = new DateGridViewColumn
{
DataPropertyName = nameof(Customer.Id),
ValueType = typeof(int),
};
DataGridViewColumn columnCustomerName = new DateGridViewColumn
{
DataPropertyName = nameof(Customer.Name),
ValueType = typeof(string),
};
DataGridView customersDataGridView = new DataGridView(...) {...}
customersDataGridView.Columns.Add(columnCustomerId);
customersDataGridView.Columns.Add(columnCustomerName);
Now to show Customers:
List<Customer> customers = FetchCustomers(...);
customersDataGridview.DataSource = customers;
This is enough to show the customer's Id and Name. If you also want to show the Telephone numbers, just add a Column. You don't have to change your original data.
Similarly if you want to format the cells of certain customers differently: this has no influence on your original customer collection. Only the Display changes.
Side Remark
Although the above works, you still have problems if operators edit the displayed data. If you want to automatically update changes made by operators, do not put the data in a List, but in a System.ComponentModel.BindingList:
BindingList<Customer> customers = new BindingList<Customer>(FetchCustomers(...));
customerDataGridView.DataSource = customers;
Now if the operator adds / removes / changes Customers from the DataGridView, they are automatically updated in the BindingList.
And a handy tip: if you want automatic sorting by clicking on the column header, and if you want easy filtering: "show only Customers who live in 'Amsterdam'" without having to change the Customers list, consider to use Nuget package BindingListView
BindingListView<Customer> customers = new BindingListView<Customer>(FetchCustomers(...));
customerDataGridView.DataSource = customers;
And presto: you've got sortable columns; editable customers. Filtering is easy:
// show only Amsterdam customers:
customers.ApplyFilter( customer => customer.Address.City == "Amsterdam");
Even though you don't show the City of the customer in the DataGridView, you can easily filter on it.
By the way: did you notice how easy I switched from DataSource without even changing my DataGridView? This is because I separated the display from the source data.
Back to your question
You want to change the layout of the cells in column NextCalibration. Every Cell with a value higher than xxx should be Red.
The layout of a cell is done in a DataGridViewCellStyle. If your Cell doesn't have its own CellStyle, it uses the CellStyle of the DataGridViewColumn.
You want to change the cell style whenever the value of the displayed property meets some requirement. In this case: foreground color red if it is less than today's date, otherwise the default value. Make a Clone of the default cell style of the column.
DataGridViewColumn columnNextCalibration = ...
DataGridViewCellStyle specialCellStyle = (DataGridViewCellStyle)columnNextCalibration
.CellTemplate
.CellStyle
.Clone();
If your column has no special style (it is null), use the InheritedStyle.
// adjust the CellStyle to the style it should have when the value meets the requirements
specialCellStyle.ForeColor = Color.Red;
// if desired: change the Font, the fontSize, or the BackColor, the frame whatever!
You want to select either the default CellStyle (null) or this special cell style, depending on the displayed DateTime value:
Now that you have a special CellStyle wait until the displayed value changes:
this.customersDataGridView.CellValueChanges += OnCellValueChanged;
private void OnCellValueChanged(object sender, DataGridViewCellEventArgs eventArgs)
{
DataGridView dgv = (DataGridView)sender;
// is the changed cell from my column in my DataGridView?
if (Object.ReferencEquals(sender, customersDataGridView)
&& e.ColumnIndex == columnNextCalibation.DisplayIndex)
{
DataGridViewCell changedCell = dgv.Rows[e.RowIndex].Column[e.ColumnIndex];
DateTime cellValue = (DateTime)cell.Value;
DateTime today = ...
if (cellValue < today)
{
// use the special CellStyle:
changedCell.CellStyle = specialCellStyle;
}
else
{
// use the default CellStyle of the column, not a special one for this cell
changedCell.CellStyle = null;
}
}
}

Related

DataGridView Loading From LINQ

I have a form with DataGridViews that have the DataSource set to a DataContext of my database to auto pull in the info and allow it to be edited. But I need a color to display a Color from the color id that corresponds to a color in a colors table and I don't know how I can achieve this with also allowing it to auto edit and update the records.
private dbCounterTopsDataContext dbContext = new dbCounterTopsDataContext();
private void FrmCurrentInventory_Load(object sender, EventArgs e)
{
dataGridColors.DataSource = dbContext.Colors;
dataGridBarTops.DataSource = dbContext.BarTops;
dataGridKitchenTops.DataSource = dbContext.Kitchens;
dataGridVanityTops.DataSource = dbContext.Vanities;
}
I have also tried this and it worked with displaying but I could no longer update directly from the datagrid
private void FrmCurrentInventory_Load(object sender, EventArgs e)
{
dataGridColors.DataSource = dbContext.Colors.Select(o => new { ColorId = o.ColorID, Color = o.Color1 });
dataGridBarTops.DataSource = dbContext.BarTops.Select(o => new { Color = o.Color.Color1, Length = o.Length, Width = o.Width });
dataGridKitchenTops.DataSource = dbContext.Kitchens.Select(o => new { Color = o.Color.Color1, Length = o.Length }).ToList();
dataGridVanityTops.DataSource = dbContext.Vanities;
}
Some good tips in the comments from SSS, perhaps the easiest way to get this going is to use AutogenerateColumns to gen most of the stuff and then add a few combo box columns for your colors. It would probably go something like this:
dataGridColors.DataSource =
dataGridBarTops.DataSource = dbContext.BarTops;
dataGridBarTops.AutogenerateColumns = false;
var c = new DataGridViewComboBoxColumn();
c.HeaderText = "Color";
c.DisplayMember = "Color1"; //name of property that says Blue in color entity
c.ValueMember = "ColorID"; //name of property that says 5 in color/entity
c.DataPropertyName = "BarTopColorId"; //name of property that says 5 in BARTOPS table/entity
c.DataSource = dbContext.Colors; //personally I would use a bindingSource here
dataGridBarTops.Columns.Add(cb);
I'll leave removing the text box color is column as an exercise for you- maybe leave it in first to see how combo is working
The Colors datagridview is for editing the actual Colors definitions etc. The combo box in the bar top table is for choosing a different color is for a single bar top. If you edit the Colors table it will change what is in the list of the combo. If you pick a new combo value it will change the bartop's color id (whatever that property is called) value
Be careful not to edit away ids in Colors that are used in bartops - don't delete color Id 5 from the Colors table while there is still a bartop that uses it
I put a comment there about bindingsources. I've never bound a DGV straight to a LINQ entity list, nor probably would I (partly because it's downloading an entire table, which could be huge and partly because my winforms databinding is near exclusively with strongly typed datasets) but you find it to work (and maybe you need the whole table, no filtering). If, however you start to see strange effects like selecting different rows in the Colors datagridview causes all the combo boxes to change value, bind the combo through a bindingsource so they have something that dedicatedly tracks "the current item" for the combo

How to implement GridControl with CheckBox inside it in Syncfusion using C Sharp?

I want to implement GridControl for my project but I realize Syncfusion GridControl is little more tough than Windows controls.
my requirement is like that: Suppose I have three columns and 15 rows in my gridControl and in first column of first row I want to write some hardcoded input string and in second column of first row I want to add CheckBox.
Kindly suggest me how to bind cells with CheckBox so that it would work dynamically while scrolling.
I also go through from Here:
Query 1
In first column of first row I want to write some hardcoded input string
Suggestion 1
The cell value for a particular cell can be set by using CellValue property of cell style. Please refer the below code,
this.gridControl1[1, 1].CellValue = "Sample";
Suggestion 2
The cell value can also be set by using Text property of cell style. Please make use of below code,
this.gridControl1[2, 1].Text = "Data";
Suggestion 3
To set the cell value for a particular cell, the QueryCellInfo event can also be used. Please refer below code,
//Event Triggering
this.gridControl1.QueryCellInfo += GridControl_QueryCellInfo;
//Event Customization
private void GridControl_QueryCellInfo(object sender, GridQueryCellInfoEventArgs e)
{
if(e.RowIndex==1 && e.ColIndex==1)
{
e.Style.CellValue = "Sample Name";
}
if(e.RowIndex==2 && e.ColIndex==1)
{
e.Style.Text = "Sample ID";
}
}
Query 2
In second column of first row I want to add Checkbox
Suggestion 1
To set the cell type as CheckBox for a particular cell, the CellType property can be used and the name for the CheckBox can be set by using Description property. Please refer the below code,
this.gridControl1[1, 2].CellType = GridCellTypeName.CheckBox;
this.gridControl1[1, 2].Description = "CheckBox";
The CheckBox can be checked or unchecked based on the cell value by defining the CheckBoxOptions property of the cell.
this.gridControl1[1, 2].CheckBoxOptions = new GridCheckBoxCellInfo("True","False","False",true);
this.gridControl1[1, 2].CellValue = "True";
Suggestion 2
To set Cell type as CheckBox for a particular cell, the QueryCellInfo event can also be used. Please refer the below code,
//Event Triggering
this.gridControl1.QueryCellInfo += GridControl_QueryCellInfo;
//Event Customization
private void GridControl_QueryCellInfo(object sender, GridQueryCellInfoEventArgs e)
{
if(e.RowIndex==2 && e.ColIndex==2)
{
e.Style.CellType = GridCellTypeName.CheckBox;
e.Style.Description = "CheckBox";
e.Style.CheckBoxOptions.CheckedValue = "True";
e.Style.CellValue="True";
}
}
Screenshot
Sample Link
UG Link
Dashboard sample
\Syncfusion\EssentialStudio<Installed Version>\Windows\Grid.Windows\Samples\ Cell Types\Interactive Cell Demo\CS

how to display custom text in data bound GridViewComboBoxColumn

I am working on RadGridView of telerik. I have a "GridViewComboBoxColumn" with a list of strings as data source.
Now the problem is that when I populate the grid view with data, it is possible that the value in data is not available in the strings data source for that column which results in blank value.
I tried setting DropDownStyle to RadDropDownStyle.DropDown but that doesn't change anything. And I just need to display the data even if that is not present in the drop down list.
Here is some code to help you understand it better.
Dim lstValues As New List(Of String)
lstValues.Add("Approved")
lstValues.Add("Declined")
lstValues.Add("Pending")
Dim col5 As GridViewComboBoxColumn = RadGridView1.Columns("column2")
col5.DataSource = lstValues
col5.DropDownStyle = Telerik.WinControls.RadDropDownStyle.DropDown
Now the row being added would be following.
RadGridView1.Rows.Add("Application Name", "Processing")
As you can see that column2 has no item named "Processing" so it is not displayed and showing as blank.
Thanks in advance for the help.
Regards
You can use the formatting events and set the cell text to whatever you need, however, note that the cell value will not be changed by this, but this is what you need as far as I can understand.
void radGridView1_CellFormatting(object sender, Telerik.WinControls.UI.CellFormattingEventArgs e)
{
if (e.Column.Name == "column2" && e.Row.Cells["someColumn"].Value == something)
{
e.CellElement.Text = "some text";
}
else
{
e.CellElement.ResetValue(LightVisualElement.TextProperty, ValueResetFlags.Local);
}
}

How to change the value of a cell in a gridview at runtime?

Details
I have a datagridview that manipulate data from a DataBase. I have a column that has numeric value and each number is representation of a string value, for example,
0 => "group 1",
1 => "group 2"
and so on...
User must see this data as an readable format, meaning 0 => "group 1". something like this:
id priceGroupID
----------- ------------
1234 -1 => "group -1"
36968 0 => "group 0"
1 2 => "group 2"
2 2 => "group 2"
3 2 => "group 2"
1003 2 => "group 2"
in this link: (stackoverflow.com/questions/10314996/…) represent an idea, but I want something else. something more powerful. don't be shy, if there is no other way please tell me that there is not.
Summary and questions
so in brief:
I want to display this data in the Gridview without any change in my db.
I want the proposed format. Is there a simple way to make that format, meaning n => "group m".
cellformatting is not what I'm wanting here. CellFormatting just formats the cell in terms of the data format. (msdn)
and one more thing: my programming language is c# in the windows app.
I hope to say what I mean.
thanks in advance.
Let see what you got.
I want to display this data in the gridview without change in my db.
Great, this is how it should be. Data must be separated from the data representation.
cellformatting is not what I'm wanting here. cellformatting just formats the cell in terms of the data format.
Wrong!
Formatting is exactly what you need. One and the same data can be represented in many ways. For instance, one and the number or date value can be shown (formatted) using thousands ways (formats). This is exactly what string.Format (and other Format) methods do. Another example is Checkbox showing bool value. Yet another example is ComboBox displaying ValueMember as DisplayMember. Etc.
In fact your requirement is a variation of the Format function and can be achieved with a Custom Numeric Format String. All you need is to set DataGridViewColumn.DefaultCellStyle property Format to "Group 0".
If the format wasn't enough, contrary to what some people say, the CellFormatting event is exactly what you need.
By default, the DataGridView control will attempt to convert a cell's value into a format suitable for display. For example, it will convert a numerical value into a string for display in a text box cell. You can indicate the formatting convention to use by setting the Format property of the DataGridViewCellStyle returned by properties such as the DefaultCellStyle property.
If the standard formatting is insufficient, you can customize the formatting by handling the CellFormattingevent. This event lets you indicate the exact display value as well as the cell styles, such as background and foreground color, to use for the cell display. This means you can handle this event for any kind of cell formatting, regardless of whether the cell value itself needs formatting.
The effect on the performance is negligible most of the time because the value is converted to string only when needed to be displayed on the screen, and the screen can a limited number of rows compared to the total number of rows (in case you have a huge data).
One of the advantages of the value/display text separation is that the grid sorting works correctly (by numeric rather than by text).
To conclude, don't be fooled to convert your data storage values for display. Every control has formatting capabilities, just use them. Since you asked for a simple way, Format property is the simplest yet effective solution in your case.
Here is an example with 100,000 rows using both formatting approaches (comment the one and uncomment the other to play with). You can see that there is absolutely no performance issues, and GroupId column sorting works correctly.
using System;
using System.Data;
using System.Linq;
using System.Windows.Forms;
namespace Samples
{
static class Program
{
static void UseFormat(DataGridView dg)
{
dg.ColumnAdded += (sender, e) =>
{
if (e.Column.DataPropertyName == "GroupId")
{
e.Column.DefaultCellStyle.Format = "Group 0";
}
};
}
static void UseCellFormatting(DataGridView dg)
{
dg.CellFormatting += (sender, e) =>
{
if (e.ColumnIndex >= 0 && e.RowIndex >= 0)
{
var column = dg.Columns[e.ColumnIndex];
if (column.DataPropertyName == "GroupId" && e.Value != null)
{
e.Value = "Group " + e.Value.ToString();
e.FormattingApplied = true;
}
}
};
}
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var form = new Form();
var dg = new DataGridView { Dock = DockStyle.Fill, Parent = form, ReadOnly = true, AllowUserToAddRows = false };
UseFormat(dg);
//UseCellFormatting(dg);
var data = new DataTable();
data.Columns.Add("Id", typeof(int));
data.Columns.Add("GroupId", typeof(int));
var groupIds = Enumerable.Range(0, 15).ToArray();
for (int i = 0; i < 100000; i++)
data.Rows.Add(i, groupIds[i % groupIds.Length]);
dg.DataSource = data;
Application.Run(form);
}
}
}
sure, its simple.
you need to access the row index followed by the name of the column and set its value. For example:
this.dataGridView.Rows[0].Cells["FirstName"].Value = "billy";
this example accesses the first row and the cell "FirstName" and changes its value to "billy".
changes wont affect the DB but may affect the datasource binding thus causing the change on the datasource. instead you may want to not reference the datasource so the changes are not finally committed back to the DB when you operate with that datasource such as updating it.
Try this, you have to create a foreach loop to iterate through all items in the datagridview, this example shows you to change it for just the first record:
int groupIdentifier = this.dataGridView.Rows[0].Cells["Group"].Value;
this.dataGridView.Rows[0].Cells["Group"].Value = GetGroupName(groupIdentifier);
List<Groups> ListGroups = new List<Groups>();
private string GetGroupName(int groupIdentifier)
{
var group = ListGroups.FirstOrDefault(g=>g.Id == groupIdentifier);
return group.Name;
}
Use this when you are populating the grid.
Hope this helps

How to set max length of datagridview column

I have a DataGridView where the units can be entered in a TextBox column.
How do I restrict the input length of this column to 6 characters?
Use the MaxInputLength property of the DataGridViewTextBoxColumn.
This property is available through the Designer or through code:
((DataGridViewTextBoxColumn)dataGridView1.Columns[yourColumn]).MaxInputLength = 6;
Please use CellValueChanged event of DataGridView.
In the handler of the event you can check ColumnIndex and RowIndex properties of DataGridViewCellEventArgs argument to identify that grid's field of interest is edited and then - take appropriate actions.
As stated in other answers - most natural way to restrict text lengths for DataGridView field is to modify respective grid column properties. Properties of grid columns can be altered on Edit Columns form that is invoked for grid control in form designer with right click menu item Edit Columns...:
You may have to play with cell-edit events.
http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.cellvaluechanged.aspx
You don't necessarily have the columns ready to manipulate if you're using data binding. For data binding, using the ColumnAdded listener can help:
public FormSingleValidation(BindingList<ValidateSingle> validateSingles)
{
InitializeComponent();
dataGridViewSingleValidation.ColumnAdded += ColumnAdded;
this.validateSingles = validateSingles;
var source = new BindingSource(validateSingles, null);
dataGridViewSingleValidation.DataSource = source;
}
private void ColumnAdded(object sender, DataGridViewColumnEventArgs e)
{
if(e.Column.GetType() == typeof(DataGridViewTextBoxColumn))
{
DataGridViewTextBoxColumn column = (DataGridViewTextBoxColumn) e.Column;
column.MaxInputLength = 6;
}
}
Caveats
Obviously this applies to all text columns without discrimination, you can add a conditional filter using the column's name if you only want specific columns to be effected.

Categories

Resources