using System; using System.Collections.Generic; using System.Linq; using System.Windows.Controls.Primitives; using System.Windows.Input; namespace SLCommandingDemo.Commanding { /// /// Maintains a mapping between ICommand and ButtonBase /// objects, for the ButtonBaseExtensions class. /// internal class CommandToButtonsMap { #region Fields /// /// Maps ICommand objects to lists of ButtonBase objects. Stores the object references /// as WeakReferences, so that the commands and buttons can be garbage collected as necessary. /// readonly Dictionary> _map = new Dictionary>(); #endregion // Fields #region Internal Methods internal void AddButtonToMap(ButtonBase btn, ICommand cmd) { if (!ContainsCommand(cmd)) _map.Add(new WeakReference(cmd), new List()); List weakRefs = GetButtonsFromCommand(cmd); weakRefs.Add(new WeakReference(btn)); } internal bool ContainsCommand(ICommand cmd) { return GetButtonsFromCommand(cmd) != null; } internal void ForEachButton(ICommand cmd, Action callback) { List buttonRefs = GetButtonsFromCommand(cmd); for (int i = buttonRefs.Count - 1; i > -1; --i) { WeakReference weakRef = buttonRefs[i]; ButtonBase btn = weakRef.Target as ButtonBase; if (btn != null) callback(btn); } } internal void RemoveButtonFromMap(ButtonBase btn, ICommand cmd) { List buttonRefs = this.GetButtonsFromCommand(cmd); if (buttonRefs == null) return; for (int i = buttonRefs.Count - 1; i > -1; --i) { WeakReference weakRef = buttonRefs[i]; if (weakRef.Target == btn) { buttonRefs.RemoveAt(i); break; } } } #endregion // Internal Methods #region Private Helpers List GetButtonsFromCommand(ICommand cmd) { this.Prune(); return _map.FirstOrDefault(entry => entry.Key.Target == cmd).Value; } void Prune() { List cmds = _map.Keys.ToList(); for (int cmdIndex = cmds.Count - 1; cmdIndex > -1; --cmdIndex) { WeakReference cmdRef = cmds[cmdIndex]; if (!cmdRef.IsAlive) { _map.Remove(cmdRef); } else { List btns = _map[cmdRef]; for (int btnIndex = btns.Count - 1; btnIndex > -1; --btnIndex) { WeakReference btnRef = btns[btnIndex]; if (!btnRef.IsAlive) btns.RemoveAt(btnIndex); } } } } #endregion // Private Helpers } }