Search code examples
sortingvisual-c++mfccgridctrl

Custom sorting with CGridCtrl with multiple columns


I sort my CGridCtrl like this at the moment:

m_gridAssignHist.SortItems(pfnCellCompareDate, DISCUSS_COL_DATE, TRUE);

It uses a custom sort function:

int CALLBACK CChristianLifeMinistryDiscussionsDlg::pfnCellCompareDate(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
    auto* pCell1 = (CGridCellBase*)lParam1;
    auto* pCell2 = (CGridCellBase*)lParam2;

    if (!pCell1 || !pCell2) return 0;

    auto lDate1 = static_cast<long>(pCell1->GetData());
    auto lDate2 = static_cast<long>(pCell2->GetData());

    if (lDate1 < lDate2)
        return -1;

    if (lDate1 > lDate2)
        return 1;

    return 0;
}

In itself it has no problem. It is just that I would like to add a second layer of sorting if possible. At the moment the data is sorted on column DISCUSS_COL_DATE. If lDate1 is the same as lDate2 then I would like it to sort on the DISCUSS_COL_NAME column. But I can't work out how to establish the row that each cell is on in the grid.

It seems there was method called GetCoords in the source code (found on CodeProject) but they don't seem to do anything.


Solution

  • I came up with a simple solution. It occurred to me that I was adding item data like this:

    m_gridAssignHist.SetItemData(iRow, DISCUSS_COL_DATE, CInPlaceDT::GetLongDate(kv.second.datMeeting));
    

    I was being daft! I simply changed it to:

    m_gridAssignHist.SetItemData(iRow, DISCUSS_COL_DATE, (LPARAM)&kv.second);
    

    Now the item data is a pointer to the item in the underlying list.

    I was able to adapt the sorting comparison function as follows:

    int CALLBACK CChristianLifeMinistryDiscussionsDlg::pfnCellCompareDate(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
    {
        auto* pCell1 = (CGridCellBase*)lParam1;
        auto* pCell2 = (CGridCellBase*)lParam2;
    
        if (!pCell1 || !pCell2) return 0;
    
        auto* pData1 = (CChristianLifeMinistryDefines::S_DISCUSSION_HIST_ITEM*)pCell1->GetData();
        auto* pData2 = (CChristianLifeMinistryDefines::S_DISCUSSION_HIST_ITEM*)pCell2->GetData();
    
        if (!pData1 || !pData2) return 0;
    
        if (pData1->datMeeting < pData2->datMeeting)
            return -1;
    
        if (pData1->datMeeting > pData2->datMeeting)
            return 1;
    
        return pData1->strName.CollateNoCase(pData2->strName);
    }
    

    Works as expected:

    Multiple sorting