Home
CodeBlog
Articles
Downloads
Links
Books
About
|
Websites |
Dependency propertiesThe dependency property, in the way I am using in this text, is a property that depends on someone else to be evaluated.I came across of this necessity of dependency properties because I am implementing a HTML render including the CSS (Cascading Style Sheets) that is very suitable for this kind of implementation. For instance: <p style="font-size: large;"><span style="color:blue;">i'm blue and large font</span> i'm large</p>Here, the span element is child of p. If you ask the span element for its FontSize, it will have to ask for its parents until someone returns a value, otherwise a default one will be returned. The implementation is based on a static map that contains a pair of object pointers with a property ID pointing to some value (void*). When the objet does not set a property there is no cost in memory. However, there is some cost in CPU to check in the map if the property exist. The implementation: class CascadingStyle { private: class PropertyKey { const CascadingStyle* m_pCascadingStyle; unsigned int m_id; public: PropertyKey(const CascadingStyle* p, unsigned int id) : m_pCascadingStyle(p), m_id(id) { } bool operator < (const PropertyKey& other) const { if (m_pCascadingStyle == other.m_pCascadingStyle) return m_id < other.m_id; return m_pCascadingStyle < other.m_pCascadingStyle; } }; public: typedef std::map<PropertyKey, void*> PropertyMap; static PropertyMap& GetPropertyMap() { static PropertyMap map; return map; } static void SetProperty(CascadingStyle* p, unsigned int id, void *pv) { std::pair<PropertyMap::iterator, bool> r = GetPropertyMap().insert( std::pair<PropertyKey, void*>(PropertyKey(p, id), pv)); ASSERT(r.second == true); } static PropertyMap::const_iterator FindProperty(const CascadingStyle* p, unsigned int id, bool recursive, CascadingStyle** p2) { if (p2 != 0) *p2 = 0; if (p == NULL) return GetPropertyMap().end(); PropertyMap::const_iterator it = GetPropertyMap().find(PropertyKey(p, id)); if (it == GetPropertyMap().end()) { if (recursive) return FindProperty(p->GetCascadingStyle(), id, true, p2); else return GetPropertyMap().end(); } if (p2 != 0) *p2 = const_cast<CascadingStyle*>(p); ASSERT(it != GetPropertyMap().end()); ASSERT(it->second != NULL); return it; } protected: PropertyMap::const_iterator FindProperty(unsigned int id, bool recursive = true, CascadingStyle** p2 = 0) const { return FindProperty(this, id, recursive, p2); } template<class T> const T& FindProperty(unsigned int id, const T& defaultValue, bool recursive = true, CascadingStyle** p2 = 0) const { PropertyMap::const_iterator it = FindProperty(this, id, recursive, p2); if (it == GetPropertyMap().end()) return defaultValue; ASSERT(it->second != NULL); return *((T*)it->second); } template<class T> void ClearProperty(unsigned int id) { PropertyMap::iterator it = GetPropertyMap().find(PropertyKey(this, id)); if (it != GetPropertyMap().end()) { //remove o valor anterior e deleta delete (T*)(it->second); GetPropertyMap().erase(it); } } template<class T> void SetProperty(unsigned int id, const T& v) { ClearProperty<T>(id); SetProperty(this, id, new T(v)); } public: virtual const CascadingStyle* GetCascadingStyle() const { return NULL; } virtual ~CascadingStyle() {} };Sample of use of this base class //IDs enum CSS { CSS_Background, ... CSS_Color, ... } class Style: public CascadingStyle { Style* m_pParent; virtual const CascadingStyle* GetCascadingStyle() const { return m_pParent; } public: Style(Style* pParent) : m_pParent(pParent) { } virtual ~Style() { Style::Clear(); } public: void Clear() { ClearProperty<COLORREF>(CSS_Color); ClearProperty<COLORREF>(CSS_BackgroundColor); } void SetColor(COLORREF cr) { return SetProperty(CSS_Color, cr); } COLORREF GetColor() const { return FindProperty(CSS_Color, COLORREF(RGB(0,0,0))); } void SetBackgroundColor(COLORREF cr) { return SetProperty(CSS_BackgroundColor, cr); } COLORREF GetBackgroundColor() const { return FindProperty(CSS_BackgroundColor, COLORREF(RGB(255,255,255))); } ... }
|