简体   繁体   English

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

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

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

The easiest way to enter numbers (especially non-integer numbers) in Windows Mobile (or in a regular Windows application) is to just have a text box that the users type into, and then validate that they've entered a proper number. 在Windows Mobile(或常规Windows应用程序)中输入数字(尤其是非整数)的最简单方法是只有一个用户输入的文本框,然后验证他们输入了正确的数字。

The problem with this approach in Windows Mobile is that the default SIP (Soft Input Panel aka little pop-up keyboard) looks like this: Windows Mobile中这种方法的问题是默认SIP(软输入面板又名小弹出键盘)如下所示:

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

On a real Windows Mobile device, the SIP looks even smaller than this, and it is a gigantic pain in the keister to hit the little number keys at the top correctly. 在真正的Windows Mobile设备上,SIP看起来甚至比这还小,并且正确地敲击顶部的小数字键是一个巨大的痛苦。 What you want to use for this purpose is the Numeric mode, which you get by clicking the "123" button in the upper left corner, and looks like this: 您想要用于此目的的是数字模式,您可以通过单击左上角的“123”按钮获得该模式,如下所示:

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

The problem with this is that there is no (simple) way programatically to make this mode of the SIP appear instead of the regular keyboard. 这样做的问题在于,没有(简单)方式以编程方式使SIP的这种模式出现而不是常规键盘。 To get the SIP to appear in numeric mode, add a reference to your project to Microsoft.WindowsCE.Forms , and then add this code as a class named "SIPHandler" (you will have to change the namespace to your project's namespace): 要使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;

    }
}

Sorry about the length. 抱歉长度。 To pop the SIP up in numeric mode, you just use this line: 要以数字模式弹出SIP,只需使用以下行:

SIPHandler.ShowSIPNumeric();

or to make it appear in regular keyboard mode: 或使其以常规键盘模式显示:

SIPHandler.ShowSIPRegular();

And to hide it again: 并再次隐藏它:

SIPHandler.HideSIP();

The basic trick behind this code is to sort of "peek" the color in the upper left corner to determine whether the SIP is already in regular keyboard or numeric mode, and then to simulate a mouse click (if necessary) in the same corner to ensure that the SIP is in the mode desired. 此代码背后的基本技巧是对左上角的颜色进行“查看”以确定SIP是否已经处于常规键盘或数字模式,然后在同一角落中模拟鼠标单击(如果需要)确保SIP处于所需模式。

Note: this is "borrowed" web code, but I no longer know where I got it from. 注意:这是“借来的”网络代码,但我不知道从哪里获得它。 If anyone on SO knows where this hack came from, please let me know and I'll be happy to attribute it to the original author. 如果有人知道这个黑客来自哪里,请告诉我,我很乐意将其归于原作者。

Update : well, after 2 seconds of Googling, I've found that the proximate source of this code was Daniel Moth: 更新 :好吧,经过2秒的谷歌搜索,我发现这段代码的近似来源是Daniel Moth:

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

... who credits Alex Feinman with the original: ...谁将Alex Feinman归功于原作:

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

Thanks, guys! 多谢你们! This code actually brought me to tears once (I was chopping onions at the time, but that couldn't have been it). 这段代码实际上让我流泪一次(我当时正在切洋葱,但那不可能)。

The MaskedTextBox might be of use. MaskedTextBox可能有用。 Failing that, I recommend using an ordinary TextBox with an OnTextChange event handler that checks to make sure the value entered is actually a number. 如果不这样做,我建议使用带有OnTextChange事件处理程序的普通TextBox,该处理程序检查以确保输入的值实际上是一个数字。 Any non-numerical characters, and you can bang out a message box, or simply remove those characters completely, depending on your needs. 任何非数字字符,您可以敲出一个消息框,或者根据您的需要完全删除这些字符。

The NumericUpDown controls are slow to use sometimes, but they have intrinsic data validation which in some cases is quite useful. NumericUpDown控件有时使用起来很慢,但是它们具有内部数据验证,在某些情况下非常有用。 If the control is one the user is not going to use often, consider using it. 如果控件是用户不经常使用的控件,请考虑使用它。 Otherwise the MaskedTextBox or TextBox is the way to go. 否则,MaskedTextBox或TextBox是要走的路。

Another approach to this problem is to use a multi-level ContextMenu, where the first layer of options covers ranges of numbers, and the second layers let the users pick specific values, like this: 解决此问题的另一种方法是使用多级ContextMenu,其中第一层选项涵盖数字范围,第二层允许用户选择特定值,如下所示:

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

You can create the full menu structure ahead of time (kind of a pain) or just load the structure dynamically depending on the range of values and the resolutions required. 您可以提前创建完整的菜单结构(有点痛苦),或者根据值的范围和所需的分辨率动态加载结构。 You can do this with hundreds of menu items in much less than a second, even on Windows Mobile devices. 即使在Windows Mobile设备上,您也可以在不到一秒的时间内完成数百个菜单项。

This approach also works very well for entering monetary values. 这种方法对于输入货币价值也非常有效。

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

相关问题 单元测试Windows CE / .NET CF应用程序的最佳方法是什么? - What is the best way to unit test a Windows CE / .NET CF app? 如何使用.Net CF 3.5获取PDA / Windows Mobile的用户名? - How to get the UserName of the PDA/Windows Mobile using .Net CF 3.5? 如何检测Windows Mobile 5设备序列号? (.NET CF 3.5) - How to detect Windows Mobile 5 Device Serial Number? (.NET CF 3.5) WinForms:NumericUpDown(.NET CF 3.5)和实数 - WinForms: NumericUpDown (.NET CF 3.5) and real numbers 如何检测用户何时单击Windows Mobile(.NET CF 3.5)中的通知图标 - How can you detect when the user clicks on the notification icon in Windows Mobile (.NET CF 3.5) 运行.NET CF 3.5应用程序时Windows Mobile 6.5文件系统使Motorola MC55崩溃 - Windows Mobile 6.5 file system crash Motorola MC55 when running .NET CF 3.5 application 构建ac#应用程序(CF .NET 3.5)的正确方法,我需要建议 - The right way to build a c#'s app (CF .NET 3.5), i need advice .NET Windows窗体应用程序更新自身的最佳方法是什么? - What's the best way for a .NET windows forms application to update itself? Windows Mobile 6.5-.NET CF连接管理 - Windows Mobile 6.5 - .NET CF connection management 从运行WiN CE 6设备的C#.net CF 3.5向IBM Websphere MQ发送消息的最佳方法 - Best way to send message to IBM Websphere MQ from C# .net CF 3.5 running WiN CE 6 devices
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM