Hello, I have implemented a "GridComboBoxColumn" column that must be filled according to the header field of the row. Then every time the user "clicks" or "doubleclicks" the elements are displayed on demand and not filled initially. This is my idea, is it possible to improve it? If I use "IDataSourceSelector" I would not be able to use the method asynchronously.
private async void View_CellDoubleClick(object? sender, CellClickEventArgs e)
{
DataRow? row = e.DataRow as DataRow;
NotasPdtesListModel? header = row!.RowData as NotasPdtesListModel;
if (e.DataColumn.GridColumn.MappingName == "Giro")
{
DataColumnBase? datasource = e.DataColumn;
GridComboBoxColumn? d = datasource.GridColumn as GridComboBoxColumn;
if (d.DataSource == null)
{
view.BeginInvoke(
new Action(() => ShowBusyIndicator(view.DataGrid.TableControl))
);
SfDataGrid? grid = sender as SfDataGrid;
Dictionary<string, string>? res = await repo.LLenarCombo(
header!.Header!.Rut.ToString(),
header.Header.VerificationCode!
);
(grid!.Columns["Giro"] as GridComboBoxColumn)!.DataSource = res;
busyIndicator.Hide();
}
}
else
{
e.Cancel = true;
}
}
Hi Sergio Ayala,
We suspect that your requirement is set the IDataSourceSelector for different columns while clicking on the specific GridComboBoxColumn in SfDataGrid. You can
achieve this by creating the instance for CustomSelector and assign to the IDataSourceSelector
property in different GridComboBoxColumn. Please refer to the below code snippet,
|
//create the instance for customSelector CustomSelector customSelector = new CustomSelector();
private async void View_CellDoubleClick(object sender, CellClickEventArgs e) { DataRow row = e.DataRow as DataRow;
OrderDetails header = row.RowData as OrderDetails;
if (e.DataColumn.GridColumn.MappingName == "ShipCityID") { DataColumnBase datasource = e.DataColumn;
GridComboBoxColumn d = datasource.GridColumn as GridComboBoxColumn;
d.ValueMember = "ShipCityID"; d.DisplayMember = "ShipCityName";
if (d.IDataSourceSelector == null) { this.BeginInvoke(new Action(() => { ShowBusyIndicator(this.sfDataGrid.TableControl);
Task.Delay(50000); SfDataGrid grid = sender as SfDataGrid; //assign IDataSourceSelector based on your custom condition in SfDataGrid (grid.Columns["ShipCityID"] as GridComboBoxColumn).IDataSourceSelector = customSelector;
busyIndicator.Hide(); })); }
} else { e.Cancel = true; } } |
Please find the sample in the attachment
UG Link: https://help.syncfusion.com/windowsforms/datagrid/columntypes#loading-different-datasources-for-each-row-of-gridcomboboxcolumn
If we misunderstood your requirement, please provide more
information regarding the requirement. This would help us to proceed further.
Regards,
Vijayarasan S
no, I need to load different datasource for each row (for one combobox into one column). And that the data is loaded only at the request of the user.
Hi Sergio Ayala,
GridComboBoxColumn is derived from the GridColumn which hosts SfComboBox as an edit element. The DataSource of SfComboBox is assigned while entering edit mode in a cell
by default.
However, we suspect that your requirement is to assign the DataSource only when entering
edit mode in GridComboBoxColumn of each row. You can achieve this by
customizing the OnInitializeEditElement and OnRender methods in
GridComboBoxCellRendererExt in SfDatGrid. Please refer to the below code
snippet,
|
//remove the existing renderer this.sfDataGrid.CellRenderers.Remove("ComboBox"); //add the custom renderer this.sfDataGrid.CellRenderers.Add("ComboBox", new GridComboBoxCellRendererExt(sfDataGrid));
sfDataGrid.Columns.Add(new GridComboBoxColumn() { MappingName = "ShipCountry", HeaderText = "Ship Country" , DisplayMember= "ShipCountry", DataSource = new CountryInfoRepository().CountryList });
//here ShipCityID column each row ComboBox DataSoure set based on ShipCountry column value sfDataGrid.Columns.Add(new GridComboBoxColumn() { MappingName = "ShipCityID", HeaderText = "Ship City", ValueMember = "ShipCityID", DisplayMember = "ShipCityName" });
|
Renderer Customization Code Snippet:
|
public class GridComboBoxCellRendererExt : GridComboBoxCellRenderer { private SfDataGrid DataGrid; CustomSelector customSelector;
public GridComboBoxCellRendererExt(SfDataGrid dataGrid) : base() { this.DataGrid = dataGrid; //create the instance for customSelector customSelector = new CustomSelector(); }
protected override void OnRender(Graphics paint, Rectangle cellRect, string cellValue, CellStyleInfo style, DataColumnBase column, RowColumnIndex rowColumnIndex) { //here we have set the DataSource when enter edit mode in ShipCityID if (column.GridColumn.MappingName == "ShipCityID") { //here set the display text for only edited cell if (string.IsNullOrEmpty(cellValue) && maintainEditedValue.ContainsKey(rowColumnIndex)) { var rowGenerator = (RowGenerator)this.TableControl.GetType().GetProperty("RowGenerator", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this.TableControl); var dataRow = rowGenerator.Items.FirstOrDefault(row => row.RowIndex == rowColumnIndex.RowIndex); //here assign the IDataSourceSelector directly to the enter cell contains ComboBox var dataSource = customSelector.GetDataSource(dataRow.RowData, DataGrid.DataSource); var gridComboBoxColumn = column.GridColumn as GridComboBoxColumn; var getDisplayValue = gridComboBoxColumn.GetType().GetMethod("GetDisplayValue", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public);
var value = getDisplayValue.Invoke(gridComboBoxColumn, new object[] { dataSource, gridComboBoxColumn.DisplayMember, maintainEditedValue[rowColumnIndex].SelectedItem });
cellValue = value != null ? value.ToString() : string.Empty;
} }
base.OnRender(paint, cellRect, cellValue, style, column, rowColumnIndex); }
Dictionary<RowColumnIndex, SfComboBox> maintainEditedValue = new Dictionary<RowColumnIndex, SfComboBox>();
protected override void OnInitializeEditElement(DataColumnBase column, RowColumnIndex rowColumnIndex, SfComboBox uiElement) { //here we have set the DataSource when enter edit mode in ShipCityID if (column.GridColumn.MappingName == "ShipCityID") { //Note: OnInitializeEditElement contains large code. So, her customized code only displayed //check the sample for full code snippet var gridComboBoxColumn = column.GridColumn as GridComboBoxColumn;
object dataSource = null; if (customSelector != null) { var rowGenerator = (RowGenerator)this.TableControl.GetType().GetProperty("RowGenerator", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this.TableControl); var dataRow = rowGenerator.Items.FirstOrDefault(row => row.RowIndex == this.CurrentCellIndex.RowIndex); //here assign the IDataSourceSelector directly to the edited cell in GridComboBoxColumn dataSource = customSelector.GetDataSource(dataRow.RowData, DataGrid.DataSource);
}
//here maintain the Selected Item with combobox if (maintainEditedValue.ContainsKey(rowColumnIndex)) { maintainEditedValue[rowColumnIndex] = uiElement; } else maintainEditedValue.Add(rowColumnIndex, uiElement);
} else base.OnInitializeEditElement(column, rowColumnIndex, uiElement); } |
UG Link: https://help.syncfusion.com/windowsforms/datagrid/columntypes#customize-column-renderer
https://help.syncfusion.com/windowsforms/datagrid/columntypes#loading-different-datasources-for-each-row-of-gridcomboboxcolumn
Please find the modified sample in the attachment and let us know if you have any
concerns in this.
Regards,
Vijayarasan S
Hello!
In my question I wrote:f I use "IDataSourceSelector" I would not be able to use the method asynchronously.
That means that I need you to explain to me how to implement the " IEnumerable GetDataSource(object record, object dataSource)" method in an asynchronous way, something like an observable<dynamic> if possible... ¿?
Hi Sergio Ayala,
We regret to inform you that the GetDataSource method in
IDataSourceSelector does not contain support to asynchronously load data in
GridComboBoxColumn.
Regards,
Vijayarasan S
I was trying to call the data directly in the "OnRender" method should it work? (in the file you attached)
System.Collections.IEnumerable dataSource = "my repo data"...
¿?
Hi Sergio Ayala,
As we mentioned earlier, GridComboBoxColumn does not support
loading data asynchronously by using the OnRender method.
However, you can
assign the DataSource only when entering edit mode in the GridComboBoxColumn of
each row by using the OnRender method as we mentioned in the previous update.
Regards,
Vijayarasan S
Hello, I have another question about it. I am loading a combobox but this list has no field related to the header row. So when loading the combobox no element is selected by default. I need the field corresponding to the header (text) to be shown by default in the combobox and then when the user clicks, the combobox must be loaded with the list of data. Something like that:
header:
idheader
after8
address
combo box:
id_cbo
name_cbo
GridComboBoxColumn()
by default show=> after8 field of header
event click show=> name_cbo field
Hi Sergio Ayala,
We are little unclear your statement as per our understanding you tried to bound the different itemsSource in each row by using the DataSourceSelector. If you want to update the selected data in a GridComboBoxColumn, then you should set the “ValueMember ” and “DisplayMember” of GridComboBoxColumn. And anyone of your GridComboBoxColumn.DataSource property must be present in the underlying model.
You can refer our previous update sample, and, in a sample, we have used “ShipCityID” as a MappingName and the same ShipCityID is present in our each GridComboBoxColumn DataSource. (See the OnRender method in the previous update).
And we don’t know how you update the DataSource in each row. Can you please try to set the ValueMameber and DisplayMember to your GridComboBoxColumn?
Is any possibility to share the demo same as your application it will help us to investigate further and provide the better solution as much earliest.
Regards
Sathiyathanam
Good luck on your project.