Hi,
I use your WinGrid (2008 vol 3) in my project.
First I make a control ctlTaskDataGrid that inherits from the WinGrid control.
There I add all columns dynamicly at runtime. Then I add a Column "Selected" (DataType: Boolean).
I want to use this column to let the user select multiple rows without having to use SHIFT or CTRL. Only the problem is that all columns must be readonly (they are bounded columns and I don't want the user to make be allowed to make any changes on those records) EXCEPT the "Selected" column in which the user must be able to check or uncheck the value.
This is how I thought it must be done:
//Insert Select-Column this.DisplayLayout.Bands[0].Columns.Add("Selected", "S"); this.DisplayLayout.Bands[0].Columns["Selected"].DataType = Type.GetType("System.Boolean"); this.DisplayLayout.Bands[0].Columns["Selected"].CellActivation = Activation.AllowEdit;
//For each Column in the Dynamics NAV Table foreach (clsColumn col in table.Columns) { //If the Column is set to visible if (col.Visible) {
//Add the Column To the UltraGrid with ***ated .NET DataTupe, Name, Header Caption.. this.DisplayLayout.Bands[0].Columns.Add(col.ColumnNameNav, columnDisplay); this.DisplayLayout.Bands[0].Columns[col.ColumnNameNav].DataType = col.GetNetType(); this.DisplayLayout.Bands[0].Columns[col.ColumnNameNav].CellActivation = Activation.NoEdit; this.DisplayLayout.Bands[0].Columns[col.ColumnNameNav].Nullable = Infragistics.Win.UltraWinGrid.Nullable.Nothing; //Set the Display Date/Time according to XML Config File Format Values if (col.NavDataTypeEnum == NavDataType.Date) this.DisplayLayout.Bands[0].Columns[col.ColumnNameNav].Format = clsApplication.appSettings.GetDateFormat(); if (col.NavDataTypeEnum == NavDataType.Time) this.DisplayLayout.Bands[0].Columns[col.ColumnNameNav].Format = clsApplication.appSettings.GetTimeFormat(); //Set the Tag property of the UltraGrid Column to the Dynamics NAV Column Information this.DisplayLayout.Bands[0].Columns[col.ColumnNameNav].Tag = col; //Set Options to text instead of integers if (col.NavDataTypeEnum == NavDataType.Option) { this.DisplayLayout.ValueLists.Add(col.ColumnNameNav); int index = 0; foreach (string item in col.GetOptions()) { this.DisplayLayout.ValueLists[col.ColumnNameNav].ValueListItems.Add(index, item); index++; } this.DisplayLayout.Bands[0].Columns[col.ColumnNameNav].ValueList = this.DisplayLayout.ValueLists[col.ColumnNameNav]; } //Set the Column Sorting to None clsSortColumn SortCol = new clsSortColumn(col.ColumnNameNav, col, SortIndicator.None, -1); SortColumns.Add(SortCol);
}
But this doens't work.
The result should look like this: ("S" = Selected Column)
I don't see anything obviously wrong with your code here. I assume that there is no "Selected" column in the table.Columns collection, so you are not setting the CellActivation on the "Selected" column to something other than AllowEdit.
What exactly do you mean when you say this "doesn't work"? I assume this means you cannot change the CheckBox via the mouse? If that's the case, then my best guess is that some other setting you are applying o the grid does not allow you to edit a cell. Are you setting CellClickAction or AllowUpdate? Are you loading a Layout or a Preset that might be setting these properties?
This KB article describes all of the ways in which editing can be disabled in the grid, so perhaps it might give you some indication of other properties to look for: HOWTO:How can I make a grid or a column, row, or cell in the UltraWinGrid disabled or read-only?
Thank you for the quick response, I was able to find a bound column where the user name is stored that selected the row (it's a multiuser application and a row can only be selected by one user). I added a column to my datasource (before binding it, so it's also a bounded column) to display true (checked) if user is the same and false otherwise. I had to indeed set the CellClickActivation on Edit and set all other columns to CellActivation.None to allow the user to check/uncheck the "S" Checkboxes and not allowing to change other column.
So your solution worked. But now I have another problem. I set the RowSelector property on False because this checkboxcolumn "S" is in fact the rowselector column. Now my propblem is setting the rows with the checkboxes checked to selected (with a different backgroundcolor) and those where the checkbox is unchecked back to normal. I wanted to do this with something like this in the cellchange event (I tried all others(Before/AfterCellUpdated..) but had an even worse result):
private void ugvShipmentMovements_CellChange(object sender, CellEventArgs e) { StringBuilder sb = new StringBuilder(); foreach (UltraGridRow row in ugvShipmentMovements.Rows) { if ((bool)row.Cells["S"].Value) { row.Selected = true; row.Appearance.BackColor = Color.Red; } else { row.Selected = false; row.Appearance.BackColor = Color.Transparent; } sb.AppendLine("Ship N°: " + row.Cells["Shipment No."].Value.ToString() + " Movement N°: " + row.Cells["Movement No."].Value.ToString() + Environment.NewLine + "Checkbox CheckState: " + row.Cells["S"].Value.ToString() + Environment.NewLine + "Row selected: " + row.Selected.ToString() + Environment.NewLine + "Row BackGroundColor: " + row.Appearance.BackColor.ToString()); sb.AppendLine("-------------------------"); } this.Refresh(); MessageBox.Show(sb.ToString()); }
The messagebox is for allowing me to see what the status are of the different rows.
I also pasted that code in the LoadData Function (occurs each load or refresh);
The first time the form loads everythings seems OK. The one row that was selected in database is also selected in the list and it's background color may not be red but the DisplayLoayout.Override.SelectedRowAppearance.BackColor is 'Linnen' and this is the color displayed, so not really a problem:
The MessageBox Also displays everything we expect:
BUT, then the user wants to select a row for the first time, and he get's this as result:
Colors are NOT set and even worse, the MessageBox Says the row is not selected:
And then a even stranger thing happens if the user selects a second row (so 1 row is selected from values of the database, and two others row must be selected by the user). Then we get this:
Notice that the values for the previous selected row AND the current row are correct now on the messagebox!! Only the fact that color is not set is not as wished.
This is what I call strange at least but also a source of a lot of frustrations. Strangely enough, when UNselecting everything works like it should. Colors are immediatly set to transparent and Row is not selected anymore and checkbox is unchecked.
I would appreciate any help to find a solution!
Hi Andy,
There are a couple of problems here.
First, you are not going to be able to use the grid's built-in Selected rows collection. Once a cell in the grid enters edit mode, the selection will be lost.
Also CellChange is not really a good place to do this. And you really don't need to loop through the rows - not sure why are you doing that.
The easiest thing for you to do would be to use the InitializeRow event and simply apply an appearance (not set the Selected property) to the row based on the value of the checkbox cell. This is more efficient and a lot less code.
To determine the "selected" rows, you can either loop through all the rows in the grid looking for checked rows. Or, you could use the AfterCellUpdate event to keep a list of the "selected" rows dynamically. The latter approach is more efficient, but more complex to code. But unless you have thousands of rows, I'd probably just loop.
I did as you told, the background color only updates after the user clicks on another row..
Oh, I see. InitializeRow won't fire until you leave the cell.So you probably need to apply the color to the row in the CellChange event, too, in addition to InitializeRow.
That's right. I put this code into the cellchange event:
if (e.Cell.Column.Header.Caption == "S") { bool selected; if (prevRow != e.Cell.Row) { countPrevRows = 0; selected = !(bool)e.Cell.Value; } else { countPrevRows++; int remainder; Math.DivRem(countPrevRows, 2, out remainder); if (remainder != 0) selected = (bool)e.Cell.Value; else selected = !(bool)e.Cell.Value; } if (selected) { if (!SelRows.Contains(e.Cell.Row)) { SelRows.Add(e.Cell.Row); } e.Cell.Row.Appearance.BackColor = Color.Linen; e.Cell.Row.Appearance.ForeColor = Color.Black; } else { if (SelRows.Contains(e.Cell.Row)) { SelRows.Remove(e.Cell.Row); } e.Cell.Row.Appearance.BackColor = Color.Transparent; e.Cell.Row.Appearance.ForeColor = Color.Navy; } } prevRow = e.Cell.Row; }
It's quite complex but it's the only way because the value is not always whatyou would expect like in a AfterCellUpdate event.
You can simplify this. The CellChange event fires when the user changes the cell, but the grid doesn't write this into the Value property of the cell inside the event, because for many cells (like a date, for example), then text entered into the cell may not be valid as the user is still typing. So what you should do is use the Text property of the cell, instead of the Value.