/// <summary>
        /// Add a category to the list of known categories.
        /// </summary>
        /// <param name="id">The category ID</param>
        /// <param name="parentId">The parent ID. Zero is none (even though 0 is a valid category).</param>
        /// <param name="name">The category display name.</param>
        /// <param name="active">The default active state.</param>
        public void AddCategory(ushort id, ushort parentId, string name, bool active)
        {
            Category cat = new Category();

            cat.ID              = id;
            cat.ParentID        = parentId;
            cat.Name            = name;
            cat.Active          = active;
            _categories[cat.ID] = cat;
            bool parentActive = parentId == 0 || CategoriesState.IsActive(parentId);

            CategoriesState.SetActive(cat.ID, cat.Active && parentActive);
            NotifyNewCategory(cat);
        }
        /// <summary>
        /// Set the active state of all descendants of the category identified by <paramref name="id"/>.
        /// </summary>
        /// <param name="id">The parent category ID.</param>
        /// <param name="active">The new active state.</param>
        private void PropagateActiveToChildren(ushort id, bool active)
        {
            // Skip default category.
            if (id == 0)
            {
                return;
            }

            // Also affect all children.
            foreach (Category cat in ChildCategories(id))
            {
                if (CategoriesState.IsActive(cat.ID) != active)
                {
                    CategoriesState.SetActive(cat.ID, active);
                }
                PropagateActiveToChildren(cat.ID, active);
            }
        }
        /// <summary>
        /// Set the active state of a category.
        /// </summary>
        /// <param name="id">The category ID.</param>
        /// <param name="active">The desired active state.</param>
        /// <remarks>
        /// This invokes the <see cref="OnActivationChange"/> event when <paramref name="active"/>
        /// does not match the category state.
        ///
        /// Unknown <paramref name="id"/> values are ignored.
        /// </remarks>
        public void SetActive(ushort id, bool active)
        {
            Category cat;

            if (_categories.TryGetValue(id, out cat))
            {
                if (cat.Active != active)
                {
                    cat.Active = active;
                    // Update the dictionary.
                    _categories[cat.ID] = cat;
                    // Check hierarchy to determin final state.
                    bool mergedActive = active && CheckHierarchyActive(cat.ParentID);
                    CategoriesState.SetActive(cat.ID, mergedActive);
                    PropagateActiveToChildren(id, mergedActive);
                    if (OnActivationChange != null)
                    {
                        OnActivationChange(id, active);
                    }
                }
            }
        }