繁体   English   中英

在Windows Mobile中输入数字的最佳方法是什么? (.NET CF 3.5)

[英]What's the best way to enter numbers in Windows Mobile? (.NET CF 3.5)

必须有一个比受约束的数字更新控件更好的方法。

在Windows Mobile(或常规Windows应用程序)中输入数字(尤其是非整数)的最简单方法是只有一个用户输入的文本框,然后验证他们输入了正确的数字。

Windows Mobile中这种方法的问题是默认SIP(软输入面板又名小弹出键盘)如下所示:

替代文字http://img510.imageshack.us/img510/6210/sipreg.jpg

在真正的Windows Mobile设备上,SIP看起来甚至比这还小,并且正确地敲击顶部的小数字键是一个巨大的痛苦。 您想要用于此目的的是数字模式,您可以通过单击左上角的“123”按钮获得该模式,如下所示:

alt text 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处于所需模式。

注意:这是“借来的”网络代码,但我不知道从哪里获得它。 如果有人知道这个黑客来自哪里,请告诉我,我很乐意将其归于原作者。

更新 :好吧,经过2秒的谷歌搜索,我发现这段代码的近似来源是Daniel Moth:

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

...谁将Alex Feinman归功于原作:

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

多谢你们! 这段代码实际上让我流泪一次(我当时正在切洋葱,但那不可能)。

MaskedTextBox可能有用。 如果不这样做,我建议使用带有OnTextChange事件处理程序的普通TextBox,该处理程序检查以确保输入的值实际上是一个数字。 任何非数字字符,您可以敲出一个消息框,或者根据您的需要完全删除这些字符。

NumericUpDown控件有时使用起来很慢,但是它们具有内部数据验证,在某些情况下非常有用。 如果控件是用户不经常使用的控件,请考虑使用它。 否则,MaskedTextBox或TextBox是要走的路。

解决此问题的另一种方法是使用多级ContextMenu,其中第一层选项涵盖数字范围,第二层允许用户选择特定值,如下所示:

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

您可以提前创建完整的菜单结构(有点痛苦),或者根据值的范围和所需的分辨率动态加载结构。 即使在Windows Mobile设备上,您也可以在不到一秒的时间内完成数百个菜单项。

这种方法对于输入货币价值也非常有效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM