Home > Software design >  Techniques for getting the value of a specific cell in an SfDataGrid
Techniques for getting the value of a specific cell in an SfDataGrid

Time:11-09

I'm creating a very simple inventory control application intended to be used by a single person. I thought I would get fancy and use some of Syncfusion's controls for a better looking UI. Unfortunately, it would appear that SfDataGrid does not contain any of the same functions as a DataGridView. I'm having trouble using the technique they offer for getting cell values. Below is the snippet I got from their documentation:

private static string GetCellValue(SfDataGrid dGrid, int rowIndex, int columnIndex)
    {
        string cellValue;
        if (columnIndex < 0)
            return string.Empty;
        var mappingName = dGrid.Columns[columnIndex].MappingName;
        var recordIndex = dGrid.TableControl.ResolveToRecordIndex(rowIndex);
        if (recordIndex < 0)
            return string.Empty;
        if (dGrid.View.TopLevelGroup != null)
        {
            var record = dGrid.View.TopLevelGroup.DisplayElements[recordIndex];
            if (!record.IsRecords)
                return string.Empty;
            var data = (record as RecordEntry).Data;
            cellValue = (data.GetType().GetProperty(mappingName).GetValue(data, null).ToString());
        }
        else
        {
            var record1 = dGrid.View.Records.GetItemAt(recordIndex);
            cellValue = (record1.GetType().GetProperty(mappingName).GetValue(record1, null).ToString());
        }

        return cellValue;
    }

This works fine until the point where it calls GetProperty(mappingName) in the cellValue assignment. I want to get the System ID of the item in question as my database will use that to delete specific items. This method will get the mapping name of the column I need, but it does not pull the data from the cell and I cannot figure out why. Below is a capture of the Autos window to show the variables related to the function: Auto Tab displaying related variables, such as cellValue and mappingName. It clearly demonstrates cellValue returning null when it should contain a string of an integer. cellValue should contain a string of an integer I will then base to my database to delete the specified item. I have tried getting the collection of columns and looping through them until the matching mapping name is found and just hard wiring the column index. As far as I know column and row indexing is not the issue. The index for the System ID column is 6 and the row indexing is accessed through click event arguments using e.DataRow.RowIndex. This function below is what calls the GetCellValue function, it may be of some use in determining this issue.

private void inventoryGridView_CellClick(object sender, Syncfusion.WinForms.DataGrid.Events.CellClickEventArgs e)
    {
        if (e.DataColumn.ColumnIndex == 0) 
        {
            return;
        }
        if (e.DataColumn.ColumnIndex == 7) 
        {
            if (MessageBox.Show("Are you sure you want to delete this item?", "Confirmation", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question) == DialogResult.Yes) 
            {
                //TODO: Make delete buttons work
                //this code below calls a function that may not be working properly
                // Get the row index value        
                var rowIndex = e.DataRow.RowIndex;
                //Get the column index value
                var columnIndex = 6;
                //Get the cell value            
                var cellValue = GetCellValue(inventoryGridView, rowIndex, columnIndex);
                MessageBox.Show("Cell value \t:  "   cellValue, "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            return;
        }
    }

inventoryGridView is my SfDataGrid, while column index 7 is a column of delete buttons that should delete the item they share a row with. Please let me know if anymore information is needed and I will provide it. I did find this sample on GitHub, but it is identical to the documentation on Syncfusion's website. I also remember reading a stackoverflow post that was identical to this Syncfusion forum post, reply and everything. Though that was of no help either as it seems to imply GetCellValue should already be a member method and that is not true in my case at the least.

Finally, here is a picture of my SfDataGrid so all of you can see the full picture: SfDataGrid inventoryGridView sample picture.

CodePudding user response:

So for anyone falling into the same abyss I did, here are some answers: The Syncfusion approved method does not work outside of their sample projects (at least for me and it seems many others). the GetItemAt() function actually returns a DataRowView, not the item object you are looking for. To actually pull values off of a specific cell you need to replace these lines of code:

var record1 = dGrid.View.Records.GetItemAt(recordIndex);
cellValue = (record1.GetType().GetProperty(mappingName).GetValue(record1, null).ToString());

With this line of code:

DataRowView record1 = dGrid.View.Records.GetItemAt(recordIndex) as DataRowView;
cellValue = (record1[mappingName].ToString()); 

I am not 100% sure on why this fix has worked for me but the Microsoft documents on DataRowView guided me to what I needed after I figured out what exactly was being returned. Here, I am using the DataRowView.Item[] property to get what I need.

I hope this helps anyone finding themselves in my situation, here is a link to the property documentation that I mentioned above: DataRowView.Item[]

CodePudding user response:

Based on provided information the reported problem occurs due to a mismatched typecast of getting DataRow in SfDataGrid.

You can resolve the reported problem by typecast the record1 and data objects into DataRowView like below-mentioned code snippet,

private static string GetCellValue(SfDataGrid dGrid, int rowIndex, int columnIndex)
{
        
        string cellValue;
        if (columnIndex < 0)
            return string.Empty;
        var mappingName = dGrid.Columns[columnIndex].MappingName;
        var recordIndex = dGrid.TableControl.ResolveToRecordIndex(rowIndex);
        if (recordIndex < 0)
            return string.Empty;
        if (dGrid.View.TopLevelGroup != null)
        {
            var record = dGrid.View.TopLevelGroup.DisplayElements[recordIndex];
            if (!record.IsRecords)
                return string.Empty;
            var data = (record as RecordEntry).Data;
            //below case using for ObservableCollection binded in dataGrid
            //cellValue = (data.GetType().GetProperty(mappingName).GetValue(data, null).ToString());

            //below case using for DataTable Collection binded in dataGrid 
            cellValue = (data as DataRowView).Row[mappingName].ToString();
        }
        else
        {
            var record1 = dGrid.View.Records.GetItemAt(recordIndex);

            //below case using for ObservableCollection binded in dataGrid  
            //cellValue = (record1.GetType().GetProperty(mappingName).GetValue(record1, null).ToString());

            //below case using for DataTable Collection binded in dataGrid 
            cellValue = (record1 as DataRowView).Row[mappingName].ToString();
        }

        return cellValue;
    }

Sample Link: https://www.syncfusion.com/downloads/support/directtrac/general/ze/Sample-2052934720

  • Related