views:

171

answers:

2

Hi,

I am trying to create a "KeySet" to modify UIElement behaviour. The idea is to create a special function if, eg. the user clicks on an element while holding a. Or ctrl+a.

My approach so far, first lets create a container for all possible modifiers. If I would simply allow a single key, it would be no problem. I could use a simple Dictionary, with

Dictionary<Keys, Action> _specialActionList
  • If the dictionary is empty, use the default action.
  • If there are entries, check what action to use depending on current pressed keys

And if I wasn't greedy, that would be it... Now of course, I want more. I want to allow multiple keys or modifiers. So I created a wrapper class, wich can be used as Key to my dictionary.

There is an obvious problem when using a more complex class. Currently two different instances would create two different key, and thereby he would never find my function (see code to understand, really obvious)

Now I checked this post: http://stackoverflow.com/questions/638761/c-gethashcode-override-of-object-containing-generic-array which helped a little.

But my question is, is my basic design for the class ok. Should I use a hashset to store the modifier and normal keyboardkeys (instead of Lists). And If so, how would the GetHashCode function look like?

I know, its a lot of code to write (boring hash functions), some tips would be sufficient to get me started. Will post tryouts here...

And here comes the code so far, the Test obviously fails...

        public class KeyModifierSet
    {
        private readonly List<Key> _keys = new List<Key>();
        private readonly List<ModifierKeys> _modifierKeys = new List<ModifierKeys>();

        private static readonly Dictionary<KeyModifierSet, Action> _testDict 
                          = new Dictionary<KeyModifierSet, Action>();

        public static void Test()
        {
            _testDict.Add(new KeyModifierSet(Key.A), () => Debug.WriteLine("nothing"));
            if (!_testDict.ContainsKey(new KeyModifierSet(Key.A))) throw new Exception("Not done yet, help :-)");
        }

        public KeyModifierSet(IEnumerable<Key> keys, IEnumerable<ModifierKeys> modifierKeys)
        {
            foreach (var key in keys)
                _keys.Add(key);

            foreach (var key in modifierKeys)
                _modifierKeys.Add(key);
        }

        public KeyModifierSet(Key key, ModifierKeys modifierKey)
        {
            _keys.Add(key);
            _modifierKeys.Add(modifierKey);
        }

        public KeyModifierSet(Key key)
        {
            _keys.Add(key);
        }
    }
A: 
 _testDict.Add(new KeyModifierSet(Key.A), () => Debug.WriteLine("nothing"));
 if (!_testDict.ContainsKey(new KeyModifierSet(Key.A))) throw new Exception("Not done yet, help :-)");

If I understand your code correctly you would like to test your _testDict Dictionary object for equality using overrided versions of the Object.Equals and Object.GetHashCode methods. As far as I know you will need to create your own custom collection type that overrides these methods.

Webleeuw
A: 

To answer my own (slightly complicated posed) question, here is the solution:

public class KeyModifierSet
{
    internal readonly HashSet<Key> Keys = new HashSet<Key>();
    internal readonly HashSet<ModifierKeys> MKeys = new HashSet<ModifierKeys>();

    public override int GetHashCode()
    {
        int hash = Keys.Count + MKeys.Count;
        foreach (var t in Keys)
        {
            hash *= 17;
            hash = hash + t.GetHashCode();
        }
        foreach (var t in MKeys)
        {
            hash *= 19;
            hash = hash + t.GetHashCode();
        }
        return hash;
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as KeyModifierSet);
    }
    public bool Equals(KeyModifierSet other)
    {
        // Check for null
        if (ReferenceEquals(other, null))
            return false;

        // Check for same reference
        if (ReferenceEquals(this, other))
            return true;

        // Check for same Id and same Values
        return Keys.SetEquals(other.Keys) && MKeys.SetEquals(other.MKeys);
    }



    public KeyModifierSet(ModifierKeys mKey)
    {
        MKeys.Add(mKey);
    }
    public KeyModifierSet(Key key)
    {
        Keys.Add(key);
    }
    public KeyModifierSet(Key key, ModifierKeys mKey)
    {
        Keys.Add(key);
        MKeys.Add(mKey);
    }
    public KeyModifierSet Add(Key key)
    {
        Keys.Add(key);
        return this;
    }
    public KeyModifierSet Add(ModifierKeys key)
    {
        MKeys.Add(key);
        return this;
    }
}
Christian