必须有一种比受约束的数字更新控件更好的方法。
答案 0 :(得分:11)
在Windows Mobile(或常规Windows应用程序)中输入数字(尤其是非整数)的最简单方法是只有一个用户输入的文本框,然后验证它们是否已输入正确的号。
Windows Mobile中这种方法的问题在于默认的SIP(Soft Input Panel又名小弹出式键盘)如下所示:
alt text 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处于所需的模式。
注意:这是“借来的”网络代码,但我不知道从哪里获得它。如果SO上有人知道这个黑客的来源,请告诉我,我很乐意将其归于原作者。
更新:好吧,经过2秒的Google搜索,我发现此代码的近似来源是Daniel Moth:
http://www.danielmoth.com/Blog/InputPanelEx.cs
......他将Alex Feinman归功于原作:
http://www.alexfeinman.com/download.asp?doc=IMSwitch.zip
谢谢,伙计们!这个代码实际上让我流泪一次(我当时正在切洋葱,但那不可能是它)。
答案 1 :(得分:2)
MaskedTextBox可能有用。如果不这样做,我建议使用带有OnTextChange事件处理程序的普通TextBox,该处理程序检查以确保输入的值实际上是一个数字。任何非数字字符,您可以敲出一个消息框,或者根据您的需要完全删除这些字符。
NumericUpDown控件有时使用起来很慢,但是它们具有内部数据验证,在某些情况下非常有用。如果控件是用户不经常使用的控件,请考虑使用它。否则,MaskedTextBox或TextBox即可。
答案 2 :(得分:1)
解决此问题的另一种方法是使用多级ContextMenu,其中第一层选项涵盖数字范围,第二层让用户选择特定值,如下所示:
alt text http://img19.imageshack.us/img19/6329/dropdowns.jpg
您可以提前创建完整的菜单结构(有点痛苦),或者根据值的范围和所需的分辨率动态加载结构。即使在Windows Mobile设备上,您也可以在不到一秒的时间内完成数百个菜单项。
这种方法也很适合输入货币价值。