开发者

Using Linq to filter possible values of System.Windows.Forms.Keys

I'm creating an options dialog using WPF that lists possible keys so that the user can assign the program's hotkey. I'm attempting to filter all of the possible values of the System.Windows.Forms.Keys enumeration down to just A-Z and F1-F12, and then bind that list to a ComboBox.

Here's my code so far:

Regex filter = new Regex("(^[A-Z]$)|(^F[0-9]{1,2}$)");
IEnumerable<Key> keyList = from x in (IEnumerable<Key>)Enum.GetValues(typeof(Keys)) 
                           where filter.Match(x.ToString()).Success
                           select x;
keys.DataContext = keyLi开发者_JS百科st;

After executing this, keyList contains the letter "A" twice and is missing letters "P" through "U." I'm at a loss as to why.

I'm also interested in alternate approaches, if there's a better way.


You had two typos - you were using System.Windows.Input.Key instead of System.Windows.Forms.Keys twice. What an unfortunate typo! I would suggest that unless you really need using directives for both WinForms and WPF in the same file, you avoid having them both there.

Here's a short but complete example that works (based on your code, but with the typos fixed):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms;

class Test
{
    static void Main()        
    {
        Regex filter = new Regex("(^[A-Z]$)|(^F[0-9]{1,2}$)");
        IEnumerable<Keys> keyList = 
            from x in (IEnumerable<Keys>) Enum.GetValues(typeof(Keys)) 
            where filter.Match(x.ToString()).Success
            select x;


        foreach (var key in keyList)
        {
            Console.WriteLine(key);
        }
    }
}

Note that you can write the query expression more easily by using an explicitly typed range variable:

IEnumerable<Keys> keyList = from Keys x in Enum.GetValues(typeof(Keys)) 
                            where filter.Match(x.ToString()).Success
                            select x;

Or use dot notation to start with:

var keyList = Enum.GetValues(typeof(Keys))
                  .Cast<Keys>()
                  .Where(x => filter.Match(x.ToString()).Success);

Alternatively, you could use Unconstrained Melody and get a strongly typed list to start with:

var keyList = Enums.GetValues<Keys>()
                   .Where(x => filter.Match(x.ToString()).Success);


Jon's post pointed out the typos and different namespaces issue. It works for me as well. However, I wanted to point out a few things on the regex side of things.

Your regex can be enhanced. Currently it returns A-Z and F1-F24. To restrict it to F1-12 use this pattern instead: "^([A-Z]|F([1-9]|1[0-2]))$" - notice that I also refactored it to avoid the ^$ anchor repetition.

Additionally, you can use IsMatch instead of Match and Success:

Regex filter = new Regex("^([A-Z]|F([1-9]|1[0-2]))$");
IEnumerable<Keys> keyList =
    from x in (IEnumerable<Keys>)Enum.GetValues(typeof(Keys)) 
    where filter.IsMatch(x.ToString())
    select x;


Have you considered marking the enumeration values with a custom attribute (something like 'HotKeyAttribute')

Than- filtering out the actual enum values by the attribute will be mucj more straightforward. Note that in this case your AttributeTarget should be Field.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜