Load combobox according to selected row.

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;

            }

        }




10 Replies 1 reply marked as answer

VS Vijayarasan Sivanandham Syncfusion Team July 29, 2022 02:21 PM UTC

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


Attachment: Sample_f42adbb4.zip


SA Sergio Ayala July 29, 2022 04:54 PM UTC

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.



VS Vijayarasan Sivanandham Syncfusion Team August 1, 2022 02:27 PM UTC

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


Attachment: ModifiedSample_68290579.zip


SA Sergio Ayala August 1, 2022 04:00 PM UTC

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... ¿?



VS Vijayarasan Sivanandham Syncfusion Team August 2, 2022 04:14 PM UTC

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



SA Sergio Ayala August 2, 2022 06:37 PM UTC

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"...  


¿?



VS Vijayarasan Sivanandham Syncfusion Team August 3, 2022 03:10 PM UTC

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



SA Sergio Ayala August 12, 2022 08:49 AM UTC

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



SJ Sathiyathanam Jeyakumar Syncfusion Team replied to Vijayarasan Sivanandham August 15, 2022 03:16 PM UTC

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


Marked as answer

BM Bridget Murphy December 15, 2023 02:46 AM UTC

Good luck on your project.


Loader.
Up arrow icon