Show 0/1 as yes/no in DevExpress XtraGrid? - c#

I had this code for a regular DataGridView, and I'm having trouble getting the same effect on the XtraGrid:
private void RosterGridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (e.ColumnIndex == 7 && e.Value is long)
{
e.Value = (long)e.Value == 0 ? "No" : "Yes";
}
}
The issue is I am using SQLite and it doesn't have any true boolean data type, or else this would be easy. The column is set up in the DB to only accept 0 and 1, kind of a makeshift boolean.

With DevExpress you can set up the specific column to use the RepositoryItemCheckEdit:
// Assign a repository item to a column
RepositoryItemCheckEdit checkEdit = new RepositoryItemCheckEdit();
gridControl.RepositoryItems.Add(checkEdit);
gridView.Columns["Mark"].ColumnEdit = checkEdit;
After that, you can set up the ValueChecked, ValueUnchecked and ValueGrayed properties specify the values that correspond to the editor's checked, unchecked and indeterminate state, respectively. The default values of the ValueChecked, ValueUnchecked and ValueGrayed properties are true, false and null, respectively. You can assign custom values to these properties as your logic requires:
checkEdit.ValueChecked = (long)1;
checkEdit.ValueUnchecked = (long)0;
With this approach, you can avoid any value conversion operations when displaying and editing values in GridView.

Another possibility is to use the CustomColumnDisplayText event on the gridView
private void gridView1_CustomColumnDisplayText(object sender, DevExpress.XtraGrid.Views.Base.CustomColumnDisplayTextEventArgs e)
{
if (e.Column = <yourColumn>)
{
e.DisplayText = (long) e.Value == 1 ? "Yes" : "No";
}
}

Related

How to exclusively set the value of a DataGridViewCheckBoxCell?

I have a List<Car> objects that have a bool property named Marked.
I want to check / uncheck the Cell corresponding to this property, in a way that only one Car can be selected at the same time.
I want that the value of this property is updated in the bank.
Sample table:
Car Name
Marked
a
 
b
 
The problem is I can't check the state of CheckBox Cells.
This is what I tried, but it's not working:
Example 1:
DataGridViewCheckBoxCell dataGridViewCheckBoxCell = DataGridView1.Rows[e.RowIndex].Cells["Marked"] as DataGridViewCheckBoxCell;
if(Convert.ToBoolean(dataGridViewCheckBoxCell.Value) == true)
{
//some code
}
else if(Convert.ToBoolean(dataGridViewCheckBoxCell.Value) == false)
{
//some code
}
Example 2:
foreach (DataGridViewRow row in DataGridView1.Rows)
{
DataGridViewCheckBoxCell chk =(DataGridViewCheckBoxCell)row.Cells["Marked"];
if (chk.Value == chk.TrueValue)
{
chk.Value = chk.FalseValue;
}
else
{
chk.Value = chk.TrueValue;
}
}
how can I do it?
You can handle the CellContentClick (or CellClick) event of your DataGridView to set the state of a DataGridViewCheckBoxCell that should be a single choice (hence behaving as a RadioButton).
Store the Cell object currently selected when the Cell meets the criteria (its OwningColumn is a DataGridViewCheckBoxColumn named Marked).
Change the state of this Cell if it's the one currently selected, or reset it back to false if it's not.
In this case, set the current Cell to the one just selected and set its state to true.
Then you don't need to loop all the Rows each time a CheckBox changes value.
If you need to, call [DataGridView].EndEdit() to update the value immediately.
For example:
DataGridViewCheckBoxCell currentCheckBoxCell = null;
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex < 0 || e.RowIndex < 0) return;
var dgv = sender as DataGridView;
if (dgv[e.ColumnIndex, e.RowIndex] is DataGridViewCheckBoxCell cell &&
cell.OwningColumn.Name == "Marked")
{
if (currentCheckBoxCell is null) currentCheckBoxCell = cell;
if (cell == currentCheckBoxCell) {
cell.Value = !(bool)cell.Value;
}
else {
currentCheckBoxCell.Value = false;
currentCheckBoxCell = cell;
}
// Affects CellValueChanged
// dgv.EndEdit();
}
}
This is how it works:
See also DataGridView CheckBox selection bug to select a CheckBox Cell by clicking anywhere in a Row and while immediately update the data source.
It is unclear “where” the first code snippet is called from so I will focus on the second snippet of code.
One of the problems you will have comes from the if statement…
if (chk.Value == chk.TrueValue) …
This condition chk.Value == chk.TrueValue may not throw an error, HOWEVER… this is checking two different OBJECTS… chk.Value is an OBJECT as is chk.TrueValue … so it makes sense that the two “different” OBJECTS would NEVER be equal.
One way to solve this is to simply “cast” those OBJECTS to bool values like…
if ((bool)chk.Value == (bool)chk.TrueValue) {…
HOWEVER the above line of code will ONLY work “IF”… the check box columns TrueValue AND FalseValue properties have been SET like…
CheckBoxColumn.TrueValue = true;
CheckBoxColumn.FalseValue = false;
IF you have NOT set the Check box column’s two properties TrueValue AND FalseValue like above… then the Check box columns TrueValue and FalseValue will be null and this will cause the line of code … if ((bool)chk.Value == (bool)chk.TrueValue) … to throw an exception since chk.TrueValue is null and the cast to a bool will throw a null exception.
Therefore, if you DO SET the Check box columns TrueValue and FalseValue then you will have to “cast” the objects to bool values in order for the comparison to work as shown above.
Given all this… you may want to re-consider using the Check box columns TrueValue and FalseValue as the intended purpose of those properties is to allow you to “change” the actual true and false values to something else that is not necessarily a true or false value.
It is unimportant how you would use these properties in that context as it appears very clear that in this context… setting the Check box columns TrueValue and FalseValue properties to true and false is somewhat superfluous and creates more work for you.
So in this case, I suggest you completely drop using the Check box columns TrueValue and FalseValue properties.
If you want to ensure that only ONE check box is checked in the column… then you could wire up the grids CellContentClick event. If the check box value changed, then simply “uncheck” all the cells in that column.
Fortunately, the grids CellContentClick will fire “before” it actually sets the check box cell, so unchecking them all works out fine for both checked and unchecked states. Crude yes, but it should work.
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e) {
if (dataGridView1.Columns[e.ColumnIndex].Name == "Marked") {
foreach (DataGridViewRow row in dataGridView1.Rows) {
if (!row.IsNewRow) {
row.Cells["Marked"].Value = false;
}
}
}
}
I hope this makes sense and helps.

DataGridView using DataSourceNullValue: enter either nothing, or the nullValue

I have a DataGridView, which is databound to a DataSource.
One of the columns of the DataGridView is bound to a property of type decimal? (nullable decimal). This column is editable.
If the value of the property is null, then the underlying object should use a default value retrieved from another object.
Operators seem to be confused if this column shows nothing. Hence I want to show the string "<default>", indicating that the default value is used.
When editing this value, I'd like to give the operator the freedom to either leave an empty field, or enter something like "<default>", if he wants to indicate that the default value should be used. So:
operator enters the string "<default>": property gets value (decimal?)null
operator enters empty string: property gets value (decimal?)null
operator enters any other value: validate if it is a decimal, and use this value.
What I tried (that's always the first that is asked for :-)
public MyForm() // constructor
{
this.InitializeComponent();
// initialize datagridview (part of this could have been done in designer)
this.dataGridView1.AutoGenerateColumns = false;
this.dataGridView1.DataSource = ...;
var valueCellStyle = this.columnNonDefault.DefaultCellStyle;
valueCellStyle.DataSourceNullValue = (decimal?)null;
valueCellStyle.NullValue = "<default>";
}
The validation event handler is as follows:
private void OnCellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
if (e.CollumnIndex == this.columnNonDefaultValue.Index)
{ // validating the non-default value
// allow either empty string, or cellStyle.NullValue or decimal
string proposedValue = (string)e.FormattedValue;
// check if empty:
if (String.IsNullOrEmpty(proposedValue)
{ // accept empty:
e.Cancel = false;
}
else
{ // check if "<default>"
var cellToValidate = this.dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex];
DataGridViewCellStyle style = cellToValidate.InheritedStyle;
if (!style.IsNullValueDefault
&& String.Equals(proposedValue, style.NullValue.ToString()))
{ // accept default value:
e.Cancel = false;
}
else if (this.IsProperDecimal(proposedValue)
{ // accept decimal value
e.Cancel = false;
}
else
{ // all others: don't accept
this.ShowInvalidData(...)
e.Cancel = true;
}
}
}
}
This works fine if people enter a proper decimal value, or "<default>". If an empty string is entered, then as soon as the data is pushed to the databound item I get a string format exception.
I had expected I should handle the CellValuePushed event, with VirtualMode = true. Alas, because the grid view is databound this event is not called, not even if a proper value is pushed
So what can I use to accept both "" and empty string as (decimal?) null?
As an option you can use CellParsing and CellFormatting events to handle conversion between entered value to data source value and displaying the data source value in a suitable format.
CellParsing: To convert entered text to the suitable data source value.
Here you want to convert entered value to your default value based on some criteria (when the entered text is empty or "" or equals to the default value).
CellFormatting: To convert data source value to suitable text to show in cell.
Here you want to convert your default value to some text like <Default>.
Here is an example:
public class Test
{
public int X { get; set; }
public decimal? Y { get; set; }
}
BindingList<Test> list;
decimal? defaultValue = 100; //Some default value
string defaultFormattedValue = "<Default>"; //Some default formatted value
private void Form1_Load(object sender, EventArgs e)
{
list = new BindingList<Test>(new List<Test>());
this.dataGridView1.DataSource = list;
}
private void dataGridView1_CellParsing(object sender, DataGridViewCellParsingEventArgs e)
{
var value = string.Format("{0}", e.Value);
if (value == string.Empty || value == "\"\"")
e.Value = defaultValue;
e.ParsingApplied = true;
}
private void dataGridView1_CellFormatting(object sender,
DataGridViewCellFormattingEventArgs e)
{
if (e.Value is int? && (int?)e.Value == defaultValue)
e.Value = defaultFormattedValue;
}

Formatting columns with multiple types

I have currency text and numeric type values in my datagridview columns. I would like to format the currency value using the below code, but it's not working.
private void gv_EmployeeAdditional_CellLeave(object sender, DataGridViewCellEventArgs e)
{
if (gv_EmployeeAdditional.Rows[e.RowIndex].Cells["EmpDatatype"].Value.ToString() == "Currency")
{
gv_EmployeeAdditional[e.ColumnIndex, e.RowIndex-1].Style.Format = "#,##0.00##";
}
}
Can't test it right now but I think this is what you are looking for, set a break-point and make sure you are getting inside of the if statement then run a few test cases...
if (gv_EmployeeAdditional.Rows[e.RowIndex].Cells["EmpDatatype"].Value.ToString() == "Currency")
{
gv_EmployeeAdditional.Columns[e.ColumnIndex].DefaultCellStyle.Format = "N2";
gv_EmployeeAdditional.Columns[e.ColumnIndex].ValueType = typeof(decimal);
//gv_EmployeeAdditional[e.ColumnIndex, e.RowIndex - 1].Style.Format = "#,##0.00##";
}
Maybe even just try set this line:
gv_EmployeeAdditional[e.ColumnIndex, e.RowIndex - 1].Style.Format = "N2";
Formatting types in C# link here

How to mask values in data grid?

I have SSN column in data grid and i want to mask it like *****1234 this. But when user type type SSN it should not mask it. Is there any way to mask cell in data grid.
I only know one way to do this, though there may be a simpler one*. You can host custom editing control in your datagridview cells. This contor only appears while you are editing the cell, and the value of the cell is visible otherwise. You can read more about this here:
https://msdn.microsoft.com/en-us/library/7tas5c80.aspx
You can implement this in a way, that the cell itself holds only the masked value, and the editing control holds the full value.
*There is indeed a simpler one, see Vincent's answer.
You can do this by creating an event handler for the CellFormatting event of the DataGridView. For example like this:
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (e.Value != null && e.Value.ToString() != "SSN")
{
if (!(dataGridView1.CurrentCell != null && dataGridView1.IsCurrentCellInEditMode && dataGridView1.CurrentCell.RowIndex == e.RowIndex && dataGridView1.CurrentCell.ColumnIndex == e.ColumnIndex))
{
e.Value = "****1234";
e.FormattingApplied = true;
}
}
}

Datagrid cell formatting not retain after user edit?

i have a datagrid with the following cell formatting
datagrid.rows[0].cells[0].Value =1;
datagrid.rows[0].cells[0].Style.Format ="#k";
this works fine and the output will be 1k, however when the user edit the cell value example to 2 then cell formatting will not take effect?
question is how can i retain the cell formatting after user edit?
thanks
I guess you are not working with an underlying datasource. You are inserting DataGridViewRows manually into the DataGridView.
If you were using a datasource, if the column datatype was numeric, the styling will work in both edit and readonly modes.
In your case, you need to handle the CellFormatting event of the DataGridView and set the format of your cell there:
void dataGridView1_CellFormatting(object sender,
DataGridViewCellFormattingEventArgs e)
{
if (e.ColumnIndex == 0 && e.RowIndex == 0)
{
// if the underlying type is int
int value;
if(e.Value != null && int.TryParse(e.Value.ToString(), out value))
{
e.Value = value.ToString("#k");
/*** OR ***
e.Value = value;
e.CellStyle.Format = "#k";
*/
}
}
}

Categories

Resources