Click here to Skip to main content
11,702,890 members (73,854 online)
Click here to Skip to main content

Tagged as

An Adaptable Property List Control

, 25 Apr 2003 183.6K 1.2K 81
Rate this:
Please Sign up or sign in to vote.
An object properties list control than can change based on the objects state.
  • Download demo project - 45 Kb
  • Download source files - 19 Kb

    Sample Image - PropertyListCtrl.gif

    Introduction

    In an application I was developing, there was a need to implement some kind of user interface for changing an objects properties for different types of objects. Some objects properties are static, but there are objects whose properties are changing, reflecting their actual state. So I decided to create a Microsoft Visual Basic like control that can display different property items according to an objects state.

    Lets take a simple example. I need to describe the properties of individual items of a form. The items can display simple text, but also a concrete representation from a database. If the item displays only simple text, I do not need to edit the other parameters (object properties) that specify data field and display format.

    In the sample screen above, the Data and Data format categories will be removed from the properties list when the Data binding item is set to no.

    How it works

    The CPropertyListCtrl class implements the neccessary utility for presenting property items and user interaction.

    The CInPlaceEditImp and CInPlaceComboBox classes implement in place controls for editing item values for strings and for list items or enumerations respectively.

    The property data item classes allow for property data item manipulations.

    The CPropertyItemString and CPropertyItemList are classes for basic editing of property data values.

    The CPropertyItemCategory class contains property items of one category.

    The CPropertyItemManager is a container for all the property categories of an object.

    The CPropertyItemManagerAdaptable class supports the mechanism of adaptibility.

    How to use it

    1. Include the source files into your project.
    2. If you need to you can define your own property list item values (enumerations) derived from the class CPropertyItemList and / or implement your own custom property item value derived from the base class CPropertyItem.
    3. Implement your CPropertyItemManager derived property item manager that describes the property items of your object. If the property items can change according to the objects state, derive your property item manager from the class CPropertyItemManagerAdaptable.
    4. Use the CPropertyListCtrl control in your dialog or view and manipulate its property item manager with the SetPropertyItemManager method.

    How to implement your own property item value class

    Derive it from the base class CPropertyItem and implement its get/set methods and its virtual methods:

    • virtual void DrawValue(CDC* pDC, CRect& rect)
      // for drawing a property item value into the CPropertyListCtrl dc context.
    • virtual void CreateInPlaceControl(CWnd* pWndParent, CRect& rect, CWnd*& pWndInPlaceControl)
      // for creating its own suitable in place control for editing its value.
    • virtual void SetData(CWnd* pWndInPlaceControl)
      // for setting its value after the end of editing by an in place control.
    /////////////////////////////////////////////////////////////////////////////
    // CMyPropertyItem
    
    class CMyPropertyItem : public CPropertyItem
    {
    	CMyPropertyItem(const CMyPropertyItem& d);
    	CMyPropertyItem& operator=(const CMyPropertyItem& d);
    
    protected:
    	DECLARE_DYNAMIC(CMyPropertyItem)
    
    public:
    	CMyPropertyItem(MyDataType myData = INI_VALUE);
    	virtual ~CMyPropertyItem();
    
    	// Attributes
    	MyDataTyp& GetData() const;
    	void SetData(MyDataType& myData);
    
    	// Operations
    	virtual void DrawValue(CDC* pDC, CRect& rect);
    	virtual void CreateInPlaceControl(CWnd* pWndParent, <BR>                                     CRect& rect, CWnd*& pWndInPlaceControl);
    	virtual void SetData(CWnd* pWndInPlaceControl);
    
    	// Data
    private:
    	MyDataType m_myData;
    };
    

    And define its GET_ITEM... and SET_ITEM... macros that are used in a conjuction with the BEGIN_ITERATE_PROPERTY_ITEMS macros. For a better understanding of these look at how they are implemented in the CPropertyItemString or CPropertyItemList classes.

    How to define your own property list item value class

    You can use the predefined macros for implementing classes representing property list item values. In this examle the CMyCustomPropertyItemList is defined with two property items.

    /////////////////////////////////////////////////////////////////////////////
    // CMyCustomPropertyItemList
    
    BEGIN_LIST_ITEM_DATA_TYPE(CMyCustomPropertyItemList)
    	LPCTSTR_STRING_ITEM_DATA(_T("A string value here")),
    	ID_STRING_ITEM_DATA(IDS_STRING_VALUE_FROM_RESOURCES)
    END_LIST_ITEM_DATA_TYPE(CMyCustomPropertyItemList)
    

    Or you can implement your own class, derived from the CPropertyItemList class, overriding its virtual LPCTSTR GetItemData(int nItem) const function.

    /////////////////////////////////////////////////////////////////////////////
    // CMyOwnPropertyItemList
    
    class CMyOwnPropertyItemList : public CPropertyItemList
    {
    	....
    public:
    	virtual LPCTSTR GetItemData(int nItem) const;
    }
    

    How to implement your own property item manager class

    In order for the CPropertyListCtrl control to know what items to display, you have to implement your own property item manager describing the property items of your object. If your object property items are static you simply derive your property item manager from the class CPropertyItemManager and in the constructor declare the items using predefined macros :

    /////////////////////////////////////////////////////////////////////////////
    // CMyStaticPropertyItemManager
    
    CMyStaticPropertyItemManager::CMyStaticPropertyItemManager()
    {
     ////////////////////////////////////////////////////////////General 	
     BEGIN_PROPERTY_TAB(_T("General"), true)
        PROPERTY_ITEM(ID_PD_NAME, CPropertyItemString,<BR>                  _T("Name"), true)
        PROPERTY_ITEM(ID_PD_DESCRIPTION, CPropertyItemString,<BR>                  _T("Description"),true)
        PROPERTY_ITEM(ID_PD_BIND_DATA, CPropertyItemListYesNo, <BR>                  _T("Data binding"), true)
     END_PROPERTY_TAB()
    <BR><BR> <BR> <BR> ///////////////////////////////////////////////////////////////////////
     // Data<BR> BEGIN_PROPERTY_TAB(_T("Data"), true)
        PROPERTY_ITEM(ID_PD_DB_NODE, CPropertyItemString, <BR>                  _T("Db data node"), true)
        PROPERTY_ITEM(ID_PD_HISTORY, CPropertyItemListYesNo, <BR>                  _T("History"), true)
     END_PROPERTY_TAB()
    }
    

    You also need to implement get/set methods for accessing property item values of your object. For simple reference access you can use predefined macros.

    bool CMyStaticPropertyItemManager::SetData(const CObject* pData)
    {
    	const CMyData* pMyData = static_cast <const CMyData* > (pData);
    
    	BEGIN_ITERATE_PROPERTY_ITEMS()
    		SET_ITEM_STRING(ID_PD_NAME, pMyData->m_strName)
    		SET_ITEM_STRING(ID_PD_DESCRIPTION, pMyData->m_strDescription)
    		SET_ITEM_LIST(ID_PD_BIND_DATA, pMyData->m_bBindDatabaseData)
    		SET_ITEM_STRING(ID_PD_DB_NODE, pMyData->m_strDbTableColumn)
    		SET_ITEM_LIST(ID_PD_HISTORY, pMyData->m_bCreateHistoryData)
    	END_ITERATE_PROPERTY_ITEMS()
    
    	return true;
    }
    
    bool CMyStaticPropertyItemManager::GetData(CObject* pData) const
    {
    	CMyData* pMyData = static_cast <CMyData* > (pData);
    
    	BEGIN_ITERATE_PROPERTY_ITEMS()
    		GET_ITEM_STRING(ID_PD_NAME, pMyData->m_strName)
    		GET_ITEM_STRING(ID_PD_DESCRIPTION, pMyData->m_strDescription)
    		GET_ITEM_LIST(ID_PD_BIND_DATA, pMyData->m_bBindDatabaseData)
    		GET_ITEM_STRING(ID_PD_DB_NODE, pMyData->m_strDbTableColumn)
    		GET_ITEM_LIST(ID_PD_HISTORY, pMyData->m_bCreateHistoryData)
    	END_ITERATE_PROPERTY_ITEMS()
    
    	return true;
    }
    

    If you want to implement an adaptable property item manager derive it from the class CPropertyItemManagerAdaptable and define a virtual void OnDataChanged(CPropertyItem* pPropertyItem, CPropertyListCtrl* pWndPropertyListCtrl, int nIndex) method for changing a property items state:

    void CMyAdaptablePropertyItemManager::OnDataChanged(CPropertyItem* <BR>          pPropertyItem, CPropertyListCtrl* pWndPropertyListCtrl, int nIndex)
    {
       bool bDoChecking = false;
    
       switch(pPropertyItem->GetPropertyID())
       {
         case ID_PD_BIND_DATA:
         {
          // Yes/No item
          bool bEnableTabs;
          static_cast <CPropertyItemList*>(pPropertyItem)->GetData(bEnableTabs);
    
          // Enable/Disable tabs 1
          CPropertyItemCategory* pPropertyItemTab = GetCategoryTab(1);
    
          if(pPropertyItemTab->SetEnabled(bEnableTabs))
    	bDoChecking = true;
    			
          // Enable/Disable tabs 2
          int nItemType;
          static_cast<CPropertyItemList*>(pPropertyItemTab->GetPropertyItem(<BR>                                       ID_PD_DATA_TYPE))->GetData(nItemType);
    
          pPropertyItemTab = GetCategoryTab(2);
    
          if(pPropertyItemTab->SetEnabled(bEnableTabs && nItemType < 4))
            bDoChecking="true;" 
          } 
          break;
          case ID_PD_DATA_TYPE: { // Enumerate item 
          { 
            int nItemType; 
            static_cast<CPropertyItemList*>(pPropertyItem)->GetData(nItemType);
    
    	// For items 4 (Form) and 5 (Macro) disable tab #2, for others enable
    	CPropertyItemCategory* pPropertyItemTab = GetCategoryTab(2);
    	bDoChecking = pPropertyItemTab->SetEnabled(nItemType <4); 
           } 
           break; 
           default: 
           return; 
         } 
         if(bDoChecking) 
           CheckState(pWndPropertyListCtrl, nIndex, <BR>                  pPropertyItem->GetPropertyID());
    }
    

    Things to Improve

  • Eliminate flicker while showing in place controls.
  • Add further edit controls.
  • If you have any other suggested improvements, please let me know so that I can incorporate them into the next release. If you want to see how I have used this control in my projects, take a look at http://welcome.to/StefanBelopotocan.
  • License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here

    Share

    About the Author

    Stefan Belopotocan
    Software Developer (Senior)
    Slovakia Slovakia
    No Biography provided

    You may also be interested in...

    Comments and Discussions

     
    GeneralNice work,thanks... Pin
    ucc80130-Jan-06 5:45
    memberucc80130-Jan-06 5:45 
    GeneralScrolling with InPlaceComboBoxImp Pin
    Urban Olars13-Jun-04 10:47
    memberUrban Olars13-Jun-04 10:47 
    GeneralRe: Scrolling with InPlaceComboBoxImp Pin
    Urban Olars29-Jun-04 10:07
    memberUrban Olars29-Jun-04 10:07 
    AnswerRe: Scrolling with InPlaceComboBoxImp Pin
    BadJerry16-Jun-15 1:22
    memberBadJerry16-Jun-15 1:22 
    QuestionExcellent - Can it be used in a commercial app? Pin
    prcarp4-Jun-04 10:33
    sussprcarp4-Jun-04 10:33 
    Questionexcellent ! Will it improve ? Pin
    Gilles Diawara1-Apr-04 7:55
    memberGilles Diawara1-Apr-04 7:55 
    Questionhow can I insert a control into the item? Pin
    Anonymous3-Nov-03 22:36
    sussAnonymous3-Nov-03 22:36 
    GeneralProblems using the control Pin
    simbakid23-May-03 5:57
    membersimbakid23-May-03 5:57 
    Hi all, I'm having some big problems using the adaptable side of the property control. Firstly, I had to retrieve a hWnd from dialog list box and set it on my instance of CPropertyCtrl before the control would display. Secondly, I have 2 categories (the first with 4 items, the second with 2 items) that are meant to be displayed as default but the control is showing 8 blank lines and no text. I am trying to use the control under .NET 2003 in a tabbed dialog environment. Following are some small snippets of code:

    The list of categories and items from the constrctor of my adaptable manager derived class:
    // record level property tab
    BEGIN_PROPERTY_TAB(_T("General"), true)
    PROPERTY_ITEM(ID_PD_RECORD_LABEL, CPropertyItemString, _T("Record Label"), true)
    PROPERTY_ITEM(ID_PD_RECORD_LABEL_SEP, CPropertyItemString, _T("Record Label Separator"), true)
    PROPERTY_ITEM(ID_PD_RECORD_VARIABLE, CPropertyItemListRecType, _T("Record type"), true)
    PROPERTY_ITEM(ID_PD_RECORD_CONTINUED, CPropertyItemListYesNo, _T("Continued"), true)
    END_PROPERTY_TAB()

    BEGIN_PROPERTY_TAB(_T("Variable Length Records"), true)
    PROPERTY_ITEM(ID_PD_RECORD_SEP, CPropertyItemString, _T("Separator"), true)
    PROPERTY_ITEM(ID_PD_RECORD_LABEL_POS, CPropertyItemNumber, _T("Label Position"), true)
    END_PROPERTY_TAB()

    // fixed length record properties
    BEGIN_PROPERTY_TAB(_T("Fixed Length Records"), false)
    PROPERTY_ITEM(ID_PD_RECORD_LENGTH, CPropertyItemString, _T("Length"), true)
    PROPERTY_ITEM(ID_PD_RECORD_LABEL_START_POS, CPropertyItemNumber, _T("Label Start Position"), true)
    PROPERTY_ITEM(ID_PD_RECORD_LABEL_LENGTH, CPropertyItemNumber, _T("Label Length"), true)
    END_PROPERTY_TAB()

    // continued record properties
    BEGIN_PROPERTY_TAB(_T("Continuation Records"), false)
    PROPERTY_ITEM(ID_PD_CONTINUE_SEP, CPropertyItemString, _T("Separator"), true)
    PROPERTY_ITEM(ID_PD_CONTINUE_START_POS, CPropertyItemNumber, _T("Label Start Position"), true)
    PROPERTY_ITEM(ID_PD_CONTINUE_LENGTH, CPropertyItemNumber, _T("Label Length"), true)
    END_PROPERTY_TAB()


    The code I had to put in place in my OnInitDialog to make the property control not throw an assertion from afx2win.inl (line 696):
    CListBox * pListBox = (CListBox *)GetDlgItem(IDC_ITEM_PROPERTIES);
    m_cPropertySheet.m_hWnd = pListBox->GetSafeHwnd();


    The assertion test at line 696 in afxwin2.inl is checking for hWnd != NULL.

    I get the feeling that I've missed something so simple but I've been comparing the sample project by Stefan to my code and can see no major differences, apart from my own data structure.

    Any information/hints/tips that anyone can put forward would be greatly appreciated. I would really like to use this control in my application as it would suit my needs perfectly.

    Many thanks in advance.



    GeneralRe: Problems using the control Pin
    Stefan Belopotocan25-May-03 0:04
    memberStefan Belopotocan25-May-03 0:04 
    GeneralRe: Problems using the control Pin
    simbakid26-May-03 23:01
    membersimbakid26-May-03 23:01 
    GeneralRe: Problems using the control Pin
    simbakid27-May-03 23:25
    membersimbakid27-May-03 23:25 
    Generalprograming the addition of the control Pin
    Manuel D. Jiménez23-Jan-03 6:49
    memberManuel D. Jiménez23-Jan-03 6:49 
    GeneralRe: programing the addition of the control Pin
    Stefan Belopotocan23-Jan-03 21:55
    memberStefan Belopotocan23-Jan-03 21:55 
    GeneralThanks, but... Pin
    Manuel D. Jiménez23-Jan-03 22:49
    memberManuel D. Jiménez23-Jan-03 22:49 
    QuestionHow to use this control in docking control like workspace Pin
    Guo Yabing20-Dec-02 13:05
    memberGuo Yabing20-Dec-02 13:05 
    AnswerRe: How to use this control in docking control like workspace Pin
    Stefan Belopotocan23-Jan-03 21:48
    memberStefan Belopotocan23-Jan-03 21:48 
    GeneralBug when more than 256 items Pin
    Mephisto7716-Oct-02 21:09
    memberMephisto7716-Oct-02 21:09 
    GeneralDynamic property item insertion Pin
    soichi hayashi27-Mar-02 5:41
    membersoichi hayashi27-Mar-02 5:41 
    GeneralAnother properties control Pin
    Andreane14-Jan-02 3:53
    memberAndreane14-Jan-02 3:53 
    GeneralAdvertising? Pin
    David Wulff10-Feb-02 15:02
    memberDavid Wulff10-Feb-02 15:02 
    GeneralResizing Issue Pin
    gh7-Nov-01 10:55
    membergh7-Nov-01 10:55 
    QuestionHow can I update data? Pin
    Mac22-Oct-01 10:51
    memberMac22-Oct-01 10:51 
    GeneralExcellent Property Control Pin
    Rod Hamilton17-Sep-01 13:23
    memberRod Hamilton17-Sep-01 13:23 
    Generalgood job! Pin
    Bao Nguyen30-Jun-01 10:48
    memberBao Nguyen30-Jun-01 10:48 
    GeneralRe: good job! Pin
    Manuel D. Jiménez23-Jan-03 0:16
    memberManuel D. Jiménez23-Jan-03 0:16 
    GeneralRe: good job! Pin
    BrightLee15-Nov-03 23:37
    memberBrightLee15-Nov-03 23:37 
    GeneralLicense for your code Pin
    Anonymous7-Jun-01 12:54
    memberAnonymous7-Jun-01 12:54 
    QuestionHow can I GetItemText from ListCtrl by UTF8? Pin
    Anonymous7-Jun-01 5:57
    memberAnonymous7-Jun-01 5:57 
    Generalscroll & display Bug!! Pin
    J.Poul30-Aug-00 21:26
    sussJ.Poul30-Aug-00 21:26 
    GeneralRe: scroll & display Bug!! Pin
    Stefan Belopotocan31-Aug-00 9:48
    sussStefan Belopotocan31-Aug-00 9:48 
    GeneralComboboxes extremely buggy Pin
    Tak5-Aug-00 9:43
    sussTak5-Aug-00 9:43 
    GeneralRe: Comboboxes extremely buggy Pin
    Stefan6-Aug-00 8:31
    sussStefan6-Aug-00 8:31 
    GeneralRe: Update Comboboxes Click Bug Pin
    XudongSoong6-Jul-01 4:52
    memberXudongSoong6-Jul-01 4:52 
    GeneralRe: Update Comboboxes Click Bug Pin
    Gan Chun How23-Jul-01 21:44
    memberGan Chun How23-Jul-01 21:44 
    GeneralRe: Update Comboboxes Click Bug Pin
    Hong hye ran24-Feb-02 19:15
    memberHong hye ran24-Feb-02 19:15 
    GeneralRe: Comboboxes extremely buggy Pin
    Anonymous24-Feb-02 19:08
    memberAnonymous24-Feb-02 19:08 

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

    | Advertise | Privacy | Terms of Use | Mobile
    Web02 | 2.8.150819.1 | Last Updated 26 Apr 2003
    Article Copyright 2000 by Stefan Belopotocan
    Everything else Copyright © CodeProject, 1999-2015
    Layout: fixed | fluid