c++mfccpropertysheet

How to reorder the CPropertyPage inside a CPropertySheet


We have a CPropertySheet that have 5 CPropertyPage inside.

Let say we have something like this

1 2 3 4 5

Then, based on some business logic, when the user click refresh, we would like to have

1 5 2 3 4

We don't want to delete all the CPropertyPage and recreate them in the correct order (with AddPage()), we just want to update the position of the page in the sheet.

Is this possible?

Thanks!


Solution

  • Microsoft's MFC CPropertySheet doesn't have a function to do this, however, if you check the Property Sheet Windows Controls API, you can achieve something similar by removing the page you want to move and then insert it at the desired position.

    To do this, you first need to subclass CPropertySheet and add a function to insert a page to a given order:

    //In the .h of your subclass
    
    //Inserts the page at a given Index
    void InsertPageAt(CPropertyPage* pPageToInsert, int nPos);
    
    //In the .cpp file
    void CPropertySheetControleur::InsertPageAt(CPropertyPage* pPage, int nPos)
    {
        ASSERT_VALID(this);
        ENSURE_VALID(pPage);
        ASSERT_KINDOF(CPropertyPage, pPage);
    
    
        // add page to internal list
        m_pages.InsertAt(nPos, pPage);
    
        // add page externally
        if (m_hWnd != NULL)
        {
            // determine size of PROPSHEETPAGE array
            PROPSHEETPAGE* ppsp = const_cast<PROPSHEETPAGE*>(m_psh.ppsp);
            int nBytes = 0;
            int nNextBytes;
            for (UINT i = 0; i < m_psh.nPages; i++)
            {
                nNextBytes = nBytes + ppsp->dwSize;
                if ((nNextBytes < nBytes) || (nNextBytes < (int)ppsp->dwSize))
                    AfxThrowMemoryException();
                nBytes = nNextBytes;
                (BYTE*&)ppsp += ppsp->dwSize;
            }
    
            nNextBytes = nBytes + pPage->m_psp.dwSize;
            if ((nNextBytes < nBytes) || (nNextBytes < (int)pPage->m_psp.dwSize))
                AfxThrowMemoryException();
    
            // build new prop page array
            ppsp = (PROPSHEETPAGE*)realloc((void*)m_psh.ppsp, nNextBytes);
            if (ppsp == NULL)
                AfxThrowMemoryException();
            m_psh.ppsp = ppsp;
    
            // copy processed PROPSHEETPAGE struct to end
            (BYTE*&)ppsp += nBytes;
            Checked::memcpy_s(ppsp, nNextBytes - nBytes , &pPage->m_psp, pPage->m_psp.dwSize);
            pPage->PreProcessPageTemplate(*ppsp, IsWizard());
            if (!pPage->m_strHeaderTitle.IsEmpty())
            {
                ppsp->pszHeaderTitle = pPage->m_strHeaderTitle;
                ppsp->dwFlags |= PSP_USEHEADERTITLE;
            }
            if (!pPage->m_strHeaderSubTitle.IsEmpty())
            {
                ppsp->pszHeaderSubTitle = pPage->m_strHeaderSubTitle;
                ppsp->dwFlags |= PSP_USEHEADERSUBTITLE;
            }
            HPROPSHEETPAGE hPSP = AfxCreatePropertySheetPage(ppsp);
            if (hPSP == NULL)
                AfxThrowMemoryException();
    
            if (!SendMessage(PSM_INSERTPAGE, nPos, (LPARAM)hPSP))
            {
                AfxDestroyPropertySheetPage(hPSP);
                AfxThrowMemoryException();
            }
            ++m_psh.nPages;
        }
    } 
    

    I based this fonction on the CPropertySheet::AddPage code, but at the end of the function, I substituted the message PSM_ADDPAGE to PSM_INSERTPAGE

    Then, to move a page to a specific position, just remove it, then add it at the desired position.

    pPropertySheet->RemovePage(pPageToAdd);
    pPropertySheet->InsertPageAt(pPageToAdd, nIndex);