Search code examples
c#linqdatagridviewado.netlinq-to-dataset

Object reference error when iterating through subset of DataGridView using Linq


EDIT : I understand the basics of an NRE, I do not understand the exact reason it is happening with this LINQ query and my datagridview. I see that care must be taken with the "new row", yet I have tried three different ways of adjusting for that - using IsNewRow in two cases and attempting to do where grid.Index != dgv_Exhibitors.NewRowIndex as a third. Please help me understand why this is happening and how to correct it instead of just treating this as a duplicate.

I have code that compares a column in a DataGridView to that in a DataTable. The aim is to find and highlight cells that do not exist in the DataTable. However, I am receiving an Object reference error after cells colors are changed.

private void ValidateData()
{
    DataTable dtSubs = Controller.Instance.GetSubaccounts();

    var entriesNotInSubs =
        dt.AsEnumerable().Select(r => r.Field<string>("EXHIBITOR").Trim()).Except(dtSubs.AsEnumerable().Select(r => r.Field<string>("SGMNTID").Trim()));

    var invalidExhibitors =
        from grid in dgv_Exhibitors.Rows.OfType<DataGridViewRow>()
        join segment in entriesNotInSubs on grid.Cells["EXHIBITOR"].Value.ToString().Trim() equals segment.Trim()
        select grid;

    foreach (var row in invalidExhibitors)
    {
        row.Cells["EXHIBITOR"].Style.BackColor = Color.Red;
    }
}

I am not quite certain how to interpret the error information except that the error occurs on a MoveNext(), but which row is the problem? Thanks for your time.

System.NullReferenceException: Object reference not set to an instance of an object. 
at VirtualPrintFeesGPAddin.ExhibitorMaint.<ValidateData>b__6(DataGridViewRow grid) 
at System.Linq.Enumerable.<JoinIterator>d__61`4.MoveNext()    
at VirtualPrintFeesGPAddin.ExhibitorMaint.ValidateData() 
at VirtualPrintFeesGPAddin.ExhibitorMaint.btnValidate_Click(Object sender, EventArgs e)

Update: I have already done the following and I get the exact same error as without checking the IsNewRow property.

foreach (var row in invalidExhibitors)
{
    if (row.IsNewRow == false)
        row.Cells["EXHIBITOR"].Style.BackColor = Color.Red;
}

Update 2: I have also tested it thusly:

from grid in dgv_Exhibitors.Rows.OfType<DataGridViewRow>()
join segment in entriesNotInSubs on grid.Cells["EXHIBITOR"].Value.ToString().Trim() equals segment.Trim()
where grid.IsNewRow == false 
select grid;

Which provides a slightly different bit of error information:

at System.Linq.Enumerable.<JoinIterator>d__61`4.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()

Solution

  • After many rewrites I found a solution, which I thought would fail as all others had, but to my surprise using two Where clauses finally worked.

    var entriesNotInSubs =
        dt.AsEnumerable().Select(r => r.Field<string>("EXHIBITOR").Trim()).Except(dtSubs.AsEnumerable().Select(r => r.Field<string>("SGMNTID").Trim()));
    
    var dgvRow_ExhibitorNotInSubs =
        (from exibitors in dgv_Exhibitors.Rows.OfType<DataGridViewRow>()
        select exibitors)
            .Where(j => j.IsNewRow == false)
            .Where(i => entriesNotInSubs.Contains(i.Cells[0].Value.ToString().Trim()));
    
    foreach (var row in dgvRow_ExhibitorNotInSubs)
    {
        row.Cells[0].Style.BackColor = Color.OrangeRed;
    }