Красивые имена ключей в C # (формы) - PullRequest
6 голосов
/ 03 апреля 2012

У меня есть выпадающий список, который заполняется перечислением Keys (winforms).

Проблема состоит в том, что названия ключей не очень понятны для неопытных пользователей.Например, обычный пользователь может не знать, что означает «OemPipe» или «HanjaMode».Итак, как я могу решить эту проблему и получить более подходящие имена ключей?

Я думаю о создании словаря с ключами и их именами, но заполнение словаря само по себе занимает очень много времени.

Ответы [ 6 ]

7 голосов
/ 03 апреля 2012

Создайте файл ресурсов, который сопоставляет имена ключей с понятной пользователю строкой. Если в файле ресурсов нет значения для конкретного ключа, просто выберите имя ключа (как вы это делаете сейчас), так что вам нужно только определить те из них, которые трудно понять, и вы не сделаете этого. нужно сделать все это заранее.

Это также позволяет вам локализоваться на разные языки, если хотите.

РЕДАКТИРОВАТЬ: Добавлен пример кода. Предполагается, что у вас есть файл ресурсов с именем «KeyNames.resx»

foreach (var key in Enum.GetValues(typeof(Keys)))
{
    var keyName = KeyNames.ResourceManager.GetString(key.ToString());
    if (keyName == null)
        keyName = key.ToString();

    comboBox1.Items.Add(keyName);
}
3 голосов
/ 04 апреля 2012

Я предполагаю, что вы позволяете пользователю назначать ключи из вашего приложения (например, сочетания клавиш или игровые элементы управления).К сожалению, нет простого способа получить понятные описания для ключей (Microsoft не предоставляет один или эквивалентный API), поэтому вам нужно будет создать сопоставление самостоятельно.

Как показывает принятый в настоящее время ответ, использование файла ресурсов является отличным способом сделать это, чтобы обеспечить интернационализацию вашего приложения.

Для справки, здесь приведена полная реализация грубой силыперечисление ключей, которое я написал некоторое время назад: (однако использование файла ресурсов все еще рекомендуется)

public static string GetDescription(Keys key)
{
    switch (key)
    {
        //letters
        case Keys.A: case Keys.B: case Keys.C: case Keys.D: case Keys.E: case Keys.F:
        case Keys.G: case Keys.H: case Keys.I: case Keys.J: case Keys.K: case Keys.L:
        case Keys.M: case Keys.N: case Keys.O: case Keys.P: case Keys.Q: case Keys.R:
        case Keys.S: case Keys.T: case Keys.U: case Keys.V: case Keys.W: case Keys.X:
        case Keys.Y: case Keys.Z:
            return Enum.GetName(typeof(Keys), key);

        //digits
        case Keys.D0: 
            return "0";
        case Keys.NumPad0:
            return "Number Pad 0";
        case Keys.D1: 
            return "1";
        case Keys.NumPad1:
            return "Number Pad 1";
        case Keys.D2: 
            return "2";
        case Keys.NumPad2:
            return "Number Pad 2";
        case Keys.D3: 
            return "3";
        case Keys.NumPad3:
            return "Number Pad 3";
        case Keys.D4: 
            return "4";
        case Keys.NumPad4:
            return "Number Pad 4";
        case Keys.D5: 
            return "5";
        case Keys.NumPad5:
            return "Number Pad 5";
        case Keys.D6: 
            return "6";
        case Keys.NumPad6:
            return "Number Pad 6";
        case Keys.D7: 
            return "7";
        case Keys.NumPad7:
            return "Number Pad 7";
        case Keys.D8: 
            return "8";
        case Keys.NumPad8:
            return "Number Pad 8";
        case Keys.D9: 
            return "9";
        case Keys.NumPad9:
            return "Number Pad 9";

        //punctuation
        case Keys.Add:
            return "Number Pad +";
        case Keys.Subtract:
            return "Number Pad -";
        case Keys.Divide:
            return "Number Pad /";
        case Keys.Multiply:
            return "Number Pad *";
        case Keys.Space:
            return "Spacebar";
        case Keys.Decimal:
            return "Number Pad .";

        //function
        case Keys.F1:   case Keys.F2:   case Keys.F3:   case Keys.F4:   case Keys.F5:
        case Keys.F6:   case Keys.F7:   case Keys.F8:   case Keys.F9:   case Keys.F10:
        case Keys.F11:  case Keys.F12:  case Keys.F13:  case Keys.F14:  case Keys.F15:
        case Keys.F16:  case Keys.F17:  case Keys.F18:  case Keys.F19:  case Keys.F20:
        case Keys.F21:  case Keys.F22:  case Keys.F23:  case Keys.F24:
            return Enum.GetName(typeof(Keys), key);

        //navigation
        case Keys.Up:
            return "Up Arrow";
        case Keys.Down:
            return "Down Arrow";
        case Keys.Left:
            return "Left Arrow";
        case Keys.Right:
            return "Right Arrow";
        case Keys.Prior:
            return "Page Up";
        case Keys.Next:
            return "Page Down";
        case Keys.Home:
            return "Home";
        case Keys.End:
            return "End";

        //control keys
        case Keys.Back:
            return "Backspace";
        case Keys.Tab:
            return "Tab";
        case Keys.Escape:
            return "Escape";
        case Keys.Enter:
            return "Enter";
        case Keys.Shift:    case Keys.ShiftKey:
            return "Shift";
        case Keys.LShiftKey:
            return "Shift (Left)";
        case Keys.RShiftKey:
            return "Shift (Right)";
        case Keys.Control: case Keys.ControlKey:
            return "Control";
        case Keys.LControlKey:
            return "Control (Left)";
        case Keys.RControlKey:
            return "Control (Right)";
        case Keys.Menu: case Keys.Alt:
            return "Alt";
        case Keys.LMenu:
            return "Alt (Left)";
        case Keys.RMenu:
            return "Alt (Right)";
        case Keys.Pause:
            return "Pause";
        case Keys.CapsLock:
            return "Caps Lock";
        case Keys.NumLock:
            return "Num Lock";
        case Keys.Scroll:
            return "Scroll Lock";
        case Keys.PrintScreen:
            return "Print Screen";
        case Keys.Insert:
            return "Insert";
        case Keys.Delete:
            return "Delete";
        case Keys.Help:
            return "Help";
        case Keys.LWin:
            return "Windows (Left)";
        case Keys.RWin:
            return "Windows (Right)";
        case Keys.Apps:
            return "Context Menu";

        //browser keys
        case Keys.BrowserBack:
            return "Browser Back";
        case Keys.BrowserFavorites:
            return "Browser Favorites";
        case Keys.BrowserForward:
            return "Browser Forward";
        case Keys.BrowserHome:
            return "Browser Home";
        case Keys.BrowserRefresh:
            return "Browser Refresh";
        case Keys.BrowserSearch:
            return "Browser Search";
        case Keys.BrowserStop:
            return "Browser Stop";

        //media keys
        case Keys.VolumeDown:
            return "Volume Down";
        case Keys.VolumeMute:
            return "Volume Mute";
        case Keys.VolumeUp:
            return "Volume Up";
        case Keys.MediaNextTrack:
            return "Next Track";
        case Keys.Play:
        case Keys.MediaPlayPause:
            return "Play";
        case Keys.MediaPreviousTrack:
            return "Previous Track";
        case Keys.MediaStop:
            return "Stop";
        case Keys.SelectMedia:
            return "Select Media";

        //IME keys
        case Keys.HanjaMode:    case Keys.JunjaMode:    case Keys.HangulMode:
        case Keys.FinalMode:    //duplicate values: Hanguel, Kana, Kanji  
        case Keys.IMEAccept:    case Keys.IMEConvert:   //duplicate: IMEAceept
        case Keys.IMEModeChange: case Keys.IMENonconvert:
            return null;

        //special keys
        case Keys.LaunchMail:
            return "Launch Mail";
        case Keys.LaunchApplication1:
            return "Launch Favorite Application 1";
        case Keys.LaunchApplication2:
            return "Launch Favorite Application 2";
        case Keys.Zoom:
            return "Zoom";

        //oem keys 
        case Keys.OemSemicolon: //oem1
            return ";";
        case Keys.OemQuestion:  //oem2
            return "?";
        case Keys.Oemtilde:     //oem3
            return "~";
        case Keys.OemOpenBrackets:  //oem4
            return "[";
        case Keys.OemPipe:  //oem5
            return "|";
        case Keys.OemCloseBrackets:    //oem6
            return "]";
        case Keys.OemQuotes:        //oem7
            return "'";
        case Keys.OemBackslash: //oem102
            return "/";
        case Keys.Oemplus:
            return "+";
        case Keys.OemMinus:
            return "-";
        case Keys.Oemcomma:
            return ",";
        case Keys.OemPeriod:
            return ".";

        //unsupported oem keys
        case Keys.Oem8:
        case Keys.OemClear:
            return null;

        //unsupported other keys
        case Keys.None:     case Keys.LButton:  case Keys.RButton:  case Keys.MButton:
        case Keys.XButton1: case Keys.XButton2: case Keys.Clear:    case Keys.Sleep:
        case Keys.Cancel:   case Keys.LineFeed: case Keys.Select:   case Keys.Print:
        case Keys.Execute:  case Keys.Separator: case Keys.ProcessKey: case Keys.Packet:
        case Keys.Attn:     case Keys.Crsel:    case Keys.Exsel:    case Keys.EraseEof:
        case Keys.NoName:   case Keys.Pa1:      case Keys.KeyCode:  case Keys.Modifiers:
            return null;

        default:
            throw new NotSupportedException(Enum.GetName(typeof(Keys), key));
    }
}

Вы можете преобразовать его в файл ресурсов, запустив следующую программу, а затем добавив файл output.resx в свой файл.application как ресурс.

static void Main(string[] args)
{
    using(ResXResourceWriter writer = new ResXResourceWriter("output.resx"))
    {
        //since there are duplicate values, we need to clumsily look at each name, then parse
        foreach (string name in Enum.GetNames(typeof(Keys)))
        {
            object value = Enum.Parse(typeof(Keys), name);
            string description = GetDescription((Keys)value); 

            if (description != null)
                writer.AddResource(new ResXDataNode(name, description));
        }
    }
}

Это даст вам файл ресурса, который можно использовать в порядке, объясненном в принятом ответе.

1 голос
/ 03 апреля 2012

«Oem» означает «Производитель оригинального оборудования».Другими словами, такая компания, которая делает клавиатуры.Эти имена являются особыми, потому что на «обычной» клавиатуре нет выделенной клавиши для генерации | или включения радикалов ханджа на корейском языке (догадываюсь).Для получения | требуется удерживать клавишу Shift на большинстве макетов.Некоторые производители клавиатур могут добавлять клавиши в стандартную раскладку, которые делают это.

Что должно дать вам некоторую паузу, эти клавиши вряд ли будут доступны на клавиатуре пользователя, поэтому представление их в качестве возможных сочетаний клавиш бесполезно.Что еще более важно, использование строки, которую вы получаете из ключей, само по себе является плохой идеей.Если вам когда-нибудь понадобится локализовать ваше приложение, это вызовет у вас головную боль, поэтому другие 5 с лишним миллиардов человек в этом мире станут платными клиентами.

1 голос
/ 03 апреля 2012

Если вы хотите предоставить описание только для некоторых ключей, вы можете зациклить System.Windows.Forms.Keys и предоставить метод, который по умолчанию имеет имя перечисления Key:

private void Form1_Load(object sender, EventArgs e)
{
   foreach (System.Windows.Forms.Keys key in Enum.GetValues(typeof(System.Windows.Forms.Keys)))
   {
       comboBoxKeys.Items.Add(new { Value = key, Description = GetDescription(key) });
   }

   comboBoxKeys.DisplayMember = "Description";
}

private string GetDescription(System.Windows.Forms.Keys key)
{
    switch(key)
    {
        case Keys.OemPipe:
            return "Better oem pipe description";

        case Keys.HanjaMode:
            return "Ninja mode";

        default:
            return key.ToString(); // default name
    }
}
0 голосов
/ 03 апреля 2012

Вы можете назначать атрибуты перечислениям.Это лучший способ.В противном случае вам придётся поддерживать параллельные словари или растущий список switch-case операторов.

Вот как вы можете разметить перечисление:

public enum MyEnums
{
    [Description("OEM Pipe")]
    OemPipe,

    [Description("Hanja Mode")]
    HanjaMode
}

Вы можете получить Description атрибут с помощью метода расширения:

public static string ToEnumDescription(this Enum value)
{
    FieldInfo fi = value.GetType().GetField(value.ToString());

    DescriptionAttribute[] attributes =
        (DescriptionAttribute[])fi.GetCustomAttributes(
        typeof(DescriptionAttribute),
        false);

    if (attributes != null &&
        attributes.Length > 0)
        return attributes[0].Description;
    else
        return value.ToString();
}

Чтобы фактически получить описание перечисления, вы бы назвали его так:

var enumAsText = theEnum.ToEnumDescription();

Вы также можете сделать это:

MyEnums.OemPipe.ToEnumDescription();
0 голосов
/ 03 апреля 2012

Нет способа самостоятельно написать код.Вот подход, который вы могли бы использовать, который, вероятно, близок к минимальным требуемым усилиям:

string GetBaseKeyDescription(Keys k) {
    switch (k & ~Keys.Modifiers) {
        case Keys.OemPipe:
            return "Pipe |";
        case Keys.OemPeriod:
            return "Dot .";
        case Keys.HanjaMode:
            return "(Description of HanjaMode key)";
        default:
            return k.ToString();
    }
}

Я не уверен, нужен ли вам бит & ~Keys.Modifiers или нет - если вы это сделаете, вы будетевозможно, мне захочется написать больше кода для работы с модификаторами, но я уже делал подобные вещи раньше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...