Какой лучший способ ввода цифр в Windows Mobile? (.NET CF 3.5)

Должен быть лучший способ, чем ограниченный числовой элемент управления обновлением.

3 ответа

Самый простой способ ввода чисел (особенно нецелых чисел) в Windows Mobile (или в обычном приложении Windows) состоит в том, чтобы просто иметь текстовое поле, в которое вводят пользователи, и затем проверять, что они ввели правильный номер.

Проблема с этим подходом в Windows Mobile заключается в том, что стандартный SIP (мягкая панель ввода или маленькая всплывающая клавиатура) выглядит следующим образом:

http://img510.imageshack.us/img510/6210/sipreg.jpg

На реальном устройстве Windows Mobile SIP выглядит даже меньше, чем этот, и это огромная боль в том, чтобы правильно нажимать маленькие цифровые клавиши наверху. То, что вы хотите использовать для этой цели, это числовой режим, который вы получаете, нажав кнопку "123" в верхнем левом углу, и выглядит так:

http://img16.imageshack.us/img16/6128/sipnum.jpg

Проблема в том, что нет (простого) способа программно заставить этот режим SIP появляться вместо обычной клавиатуры. Чтобы SIP отображался в числовом режиме, добавьте ссылку на ваш проект в Microsoft.WindowsCE.Forms, а затем добавьте этот код в виде класса с именем "SIPHandler" (вам придется изменить пространство имен на пространство имен вашего проекта):

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
using Microsoft.WindowsCE.Forms;

namespace DeviceApplication1
{
    /// <summary>
    /// Handles showing and hiding of Soft Input Panel (SIP).  Better to use these
    /// methods than having an InputControl on a form.  InputControls behave oddly
    /// if you have multiple forms open.
    /// </summary>
    public class SIPHandler
    {
        public static void ShowSIP()
        {
            SipShowIM(1);
        }

        public static void ShowSIPNumeric()
        {
            SipShowIM(1);
            SetKeyboardToNumeric();
        }

        public static void ShowSIPRegular()
        {
            SipShowIM(1);
            SetKeyboardToRegular();
        }

        public static void HideSIP()
        {
            SipShowIM(0);
        }

        private static void SetKeyboardToRegular()
        {
            // Find the SIP window
            IntPtr hWnd = FindWindow("SipWndClass", null);
            // Go one level below as the actual SIP window is a child
            hWnd = GetWindow(hWnd, GW_CHILD);
            // Obtain its context and get a color sample
            // The premise here is that the numeric mode is controlled by a virtual button in the top left corner
            // Whenever the numeric mode is active, the button background will be of COLOR_WINDOW_TEXT
            IntPtr hDC = GetDC(hWnd);
            int pixel = GetPixel(hDC, 2, 2);
            // Notice that we cannot simply compare the color to the system color as the system color is 24 bit (or palette)
            // and the real color is dithered to 15-16 bits for most devices, so white (0xff, 0xff, 0xff) becomes
            // almost white (oxf8, 0xfc, 0xf8)

            // ken's hack:  here we only want to simulate the click if the keyboard is in numeric mode, in 
            // which case the back color will be WindowText
            //int clrText = (SystemColors.Window.R) | (SystemColors.Window.G << 8) | (SystemColors.Window.B << 16);
            int clrText = (SystemColors.WindowText.R) | (SystemColors.WindowText.G << 8) | (SystemColors.WindowText.B << 16);

            SetPixel(hDC, 2, 2, clrText);
            int pixelNew = GetPixel(hDC, 2, 2);
            // Restore the original pixel
            SetPixel(hDC, 2, 2, pixel);

            if (pixel == pixelNew)
            {
                // Simulate stylus click
                Message msg = Message.Create(hWnd, WM_LBUTTONDOWN, new IntPtr(1), new IntPtr(0x00090009));
                MessageWindow.SendMessage(ref msg);
                msg = Message.Create(hWnd, WM_LBUTTONUP, new IntPtr(0), new IntPtr(0x00090009));
                MessageWindow.SendMessage(ref msg);
            }
            // Free resources
            ReleaseDC(hWnd, hDC);
        }

        private static void SetKeyboardToNumeric()
        {
            // Find the SIP window
            IntPtr hWnd = FindWindow("SipWndClass", null);
            // Go one level below as the actual SIP window is a child
            hWnd = GetWindow(hWnd, GW_CHILD);
            // Obtain its context and get a color sample
            // The premise here is that the numeric mode is controlled by a virtual button in the top left corner
            // Whenever the numeric mode is active, the button background will be of COLOR_WINDOW_TEXT
            IntPtr hDC = GetDC(hWnd);
            int pixel = GetPixel(hDC, 2, 2);
            // Notice that we cannot simply compare the color to the system color as the system color is 24 bit (or palette)
            // and the real color is dithered to 15-16 bits for most devices, so white (0xff, 0xff, 0xff) becomes
            // almost white (oxf8, 0xfc, 0xf8)
            int clrText = (SystemColors.Window.R) | (SystemColors.Window.G << 8) | (SystemColors.Window.B << 16);
            SetPixel(hDC, 2, 2, clrText);
            int pixelNew = GetPixel(hDC, 2, 2);
            // Restore the original pixel
            SetPixel(hDC, 2, 2, pixel);

            if (pixel == pixelNew)
            {
                // Simulate stylus click
                Message msg = Message.Create(hWnd, WM_LBUTTONDOWN, new IntPtr(1), new IntPtr(0x00090009));
                MessageWindow.SendMessage(ref msg);
                msg = Message.Create(hWnd, WM_LBUTTONUP, new IntPtr(0), new IntPtr(0x00090009));
                MessageWindow.SendMessage(ref msg);
            }
            // Free resources
            ReleaseDC(hWnd, hDC);
        }

        [DllImport("coredll.dll")]
        private extern static bool SipShowIM(int dwFlag);

        [DllImport("coredll.dll")]
        private extern static IntPtr FindWindow(string wndClass, string caption);

        [DllImport("coredll.dll")]
        private extern static IntPtr GetWindow(IntPtr hWnd, int nType);

        [DllImport("coredll.dll")]
        private extern static int GetPixel(IntPtr hdc, int nXPos, int nYPos);

        [DllImport("coredll.dll")]
        private extern static void SetPixel(IntPtr hdc, int nXPos, int nYPos, int clr);

        [DllImport("coredll.dll")]
        private extern static IntPtr GetDC(IntPtr hWnd);

        [DllImport("coredll.dll")]
        private extern static void ReleaseDC(IntPtr hWnd, IntPtr hDC);

        [DllImport("coredll.dll")]
        private static extern bool SipSetCurrentIM(byte[] clsid);

        const int WM_LBUTTONDOWN = 0x0201;
        const int WM_LBUTTONUP = 0x0202;
        const int GW_CHILD = 5;

    }
}

Извините за длину. Чтобы открыть SIP в числовом режиме, просто используйте эту строку:

SIPHandler.ShowSIPNumeric();

или чтобы он появился в обычном режиме клавиатуры:

SIPHandler.ShowSIPRegular();

И чтобы скрыть это снова:

SIPHandler.HideSIP();

Основная хитрость этого кода заключается в том, чтобы отсортировать "цвет" в верхнем левом углу, чтобы определить, находится ли SIP в обычном режиме клавиатуры или в числовом режиме, а затем смоделировать щелчок мыши (если необходимо) в том же углу, чтобы убедитесь, что SIP находится в желаемом режиме.

Примечание: это "заимствованный" веб-код, но я больше не знаю, откуда я его взял. Если кто-то в SO знает, откуда взялся этот взлом, пожалуйста, дайте мне знать, и я буду рад приписать его первоначальному автору.

Обновление: хорошо, после 2 секунд поиска в Google, я обнаружил, что приблизительным источником этого кода был Даниэль Мот:

http://www.danielmoth.com/Blog/InputPanelEx.cs

... кто приписывает Алексу Фейнману оригинал:

http://www.alexfeinman.com/download.asp?doc=IMSwitch.zip

Спасибо, парни! Этот код на самом деле довел меня до слез (однажды я нарезал лук, но этого не могло быть).

MaskedTextBox может быть полезным. В противном случае я рекомендую использовать обычный TextBox с обработчиком события OnTextChange, который проверяет, является ли введенное значение действительно числом. Любые нечисловые символы, и вы можете выбить окно сообщения, или просто полностью удалить эти символы, в зависимости от ваших потребностей.

Элементы управления NumericUpDown иногда используются медленно, но они имеют встроенную проверку данных, которая в некоторых случаях весьма полезна. Если элемент управления является тем, который пользователь не собирается использовать часто, рассмотрите возможность его использования. В противном случае MaskedTextBox или TextBox это путь.

Другой подход к этой проблеме заключается в использовании многоуровневого ContextMenu, где первый уровень параметров охватывает диапазоны чисел, а вторые уровни позволяют пользователям выбирать конкретные значения, например:

http://img19.imageshack.us/img19/6329/dropdowns.jpg

Вы можете заранее создать полную структуру меню (что-то вроде боли) или просто динамически загружать структуру в зависимости от диапазона значений и требуемых разрешений. Вы можете сделать это с сотнями пунктов меню намного меньше чем за секунду, даже на устройствах Windows Mobile.

Этот подход также очень хорошо подходит для ввода денежных величин.

Другие вопросы по тегам