Windows Mobile UI 设计

勾安翔
2023-12-01

一、概述:
      Windows Mobile 是基于Windows CE操作系统的,是针对小内存和有限资源的移动设备而进行的开发,因此在开发过程中同PC的开发有很大的区别。特别是UI的开发,要针对手持设备进行开发,同时要符合手持设备的习惯操作。下面就我在开发过程中对UI开发的认识进行一些叙述。

二、Pocket PC UI 设计:(用户界面设计)
1、标准控件的使用:
     Pocket PC 可以使用.Net Compact Framework中的所有控件,有Listview,TreeView,Button,Label等等,支持的所有控件可见Microsoft Visual Studio .NET 2003中或可查看msdn进行查看。所有控件的用法可查询msdn。下面就InputPanel控件和Panel控件的主要用途进行一些简单的叙述。
     1InputPanel控件:
       由于大部分的Pocket PC 设备都是不带键盘的,因些所有的输入全靠SIP(Soft Input Panel)来进行操作。在.Net的程序中只要加Menubar,就会出现SIP的按纽。但是在SIP出现之后就会覆盖屏幕的下面。这样当在SIP的显示的地方有控件或者是有显示内容时就会被覆盖掉,不能进行查看或者说操作。在实际的编程过程中可以采用两种方法来进行:第一种,也是最简单的一种,在设计程序的时候把SIP的位置给空出来;第二种,就是通过在Form中加入InputPane控件,在InputPaneEnableChange事件中处理当InputPanel的状态发生变化时视图所做的变化操作。
如图所示:
 
    
代码示例:
   
private void inpSIP_EnabledChanged(object sender, System.EventArgs e)

         {

              if (inpSIP.Enabled)

              {

                   tabControl.Height = 246 - inpSIP.Bounds.Height;

              }

              else

              {

                   tabControl.Height = 246;

              }

         }

另外还有一种情况就是我不想在Form中增加Inputpanel控件,但在我还想在当我的输入框取得焦点时能够显示SIP,这种情况的解决方法是我们通过P/Invoke技术,调用本地的SIP操作函数SipShowIM()来实现,具体的代码如下:
class Sip
{
     ///<summary>

         /// SIP constants (as defined in SIPAPI.h)

         ///</summary>

         private const int SIPF_ON = 0x00000001;

         private const int SIPF_OFF = 0x00000000;

 

         ///<summary>

         /// P/Invoke native Api SipShowIM

         ///</summary>

         ///<param name="dwFlag"></param>

         ///<returns></returns>

         [ DllImport("coredll.dll", EntryPoint="SipShowIM") ]

         private extern static bool showSIP(int dwFlag);

 

         public static bool showSIP()

         {

              return showSIP(Sip.SIPF_ON);

         }

 

         public static bool hideSIP()

         {

              return showSIP(SIPF_OFF);

}

}
     在文件的顶部增加using System.Runtime.InteropServices;

     使用方法为:比如对于TexBox来说,当TextBox取得焦点时,在TextBox控件的GotFocus事件中实现SIP的显示,在LostFocus中实现SIP的隐藏,代码如下:
private void textBox_GotFocus(object sender, System.EventArgs e)

     {

         Sip.showSIP();

     }

     private void textBox_LostFocus(object sender, System.EventArgs e)

     {

Sip.hideSIP();
}
     (2)Panel控件的应用
     Panel控件是一个容器,它可以包含其它的控件,主要应用有:
     1)我最多的应用就是当在一个Form中可能会有几种显示样式时,我就增加几个Panel,每个Panel中加入其所需的控件,当我需要显示某一样式时通过
     panel1.Visible = false;

panel2.Visible = true; 来实现。
      2)设置一些不能直接设置背景色的控件的背景色。比如设置Label控件的背景色.把Label控件改入到Panel控件当中,设置Panel的背景色就可以了。

     3)实现Form的滚动,当一个Form要显示很多控件时,就会出现需要滚动显示,对于.Net 2003来说不能实现自动的滚动,这就要借助于Panel来实现。关于本点的实现可以参见 3Form滚动的实现

 

2Form中的一些主要实现方式:

    (1Form最小化和关闭的实现:

       主要是得用Form属性MinimizeBox来实现,

       this.MinimizeBox = false; // 关闭
       this.MinimizeBox = true;  //最小化
    (2)非全屏Form的实现:

新建一个Form,分别设置属性FormBorderStyle,ControlBox等的值如下所示:

this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;

this.ControlBox = false;

this.ClientSize = new System.Drawing.Size(224, 88);  // 设置Form的大小

然后在Load事件中设置Form显示的位置,如下例(Form居中显示):

private void Form_Load(object sender, System.EventArgs e)

         {

              Rectangle screen = Screen.PrimaryScreen.Bounds;

              this.Location = new Point((screen.Width - this.Width) / 2,

                   (screen.Height - this.Height ) / 2);

}

(3)Form的强制最小化实现:

首先重写Form的onGotFocus方法,然后查找窗体的窗口,最后用ShowWindow(hwnd, SW_MINIMIZE)来最小化窗口。

代码示例如下:

using System.Runtime.InteropServices;

[DllImport("CoreDll")]

public static extern IntPtr FindWindow(string className,string WindowsName);

[DllImport("CoreDll")]

public static extern bool ShowWindow(IntPtr hwnd,int nCmdShow);

const int SW_MINIMIZE = 6;

protected override void OnGotFocus(EventArgs e)

{

IntPtr hwnd = FindWindow(null, this.Text);

ShowWindow(hwnd, SW_MINIMIZE); 

base.OnGotFocus(e);

}

(4)父窗口与子窗口之间的关系:

在.Net里当一个窗口产生一个子窗口后,如果常时间不操作或者是一小心回到home screen,这时当你再打开程序关闭子窗口时,会返回到home screen,而不是你想要的父窗口,对于这种情况的处理,最好的方法是把父窗口的指针传入到子窗口中,然后在子窗口关闭时,在子窗口的Closing事件中调用父窗口的show方法来显示父窗口,代码示例片段如下:

父窗口:

public class Form1 : System.Windows.Forms.Form

{

……..

private void menuItem3_Click(object sender, System.EventArgs e)

             {

                   CustomerForm fmCustom = new CustomerForm(this);

                   fmCustom.ShowDialog();

                   this.textBox1.Focus();  // 这点很重要

}

}

子窗口:

public class CustomerForm : System.Windows.Forms.Form

{

     private Form parentForm;

              public CustomerForm(Form parentForm)

              {

                   InitializeComponent();

 

                   this.parentForm = parentForm;

     }

private void CustomerForm_Closing(object sender, CancelEventArgs e)

              {

                   parentForm.Show();

     }

}

注:我见意子窗口的产生最后用模态对话框,即ShowDialog,这样可以避免过多的子窗口的产生,造成内存的浪费。另外,对于窗口返回后,指定要接受焦点的控件,并且这点很重要。

3、Form滚动的实现:

由于.Net 的Form不支持自动滚动,因些要实现Form的滚动要借助于Panel来实现。在Form中加入一个Panel控件,加入一个vScrollBar控件,设置vScrollBar1控件的高度为Form的高度或者说你Panel的设度,如果你的滚动范围不是整个Form,设为Panel的高度,反之也可为Form的高度。然后根据需要设置vScrollBar的LargeChange和Maximum属性,通过在vScrollBar的ValueChanged事件中设置Panel的位置来实现滚动。如下所示:
private void vScrollBar_ValueChanged(object sender, System.EventArgs e)

     {

         vScrollBar.Top = -vScrollBar.Value * 44;  // 44为每滚动一次Panel要移动的大小。

}
具体的可参见\\192.168.20.199机器上VSS下的windows mobile\sample中的CustomForm.cs文件,此示例是Smartphone的,但也可用于Pocket PC,对于Smartphone里还有另一种实现方法,见(ScrollForm.cs),稍后将会详细介绍。

4、Pocket PC UI的整体设计:

       1)由于mobile的资源有限,因此在UI的设计时,控件不要过多,同是还要保证可以

     用手操作,且不会出现误操作,比如:button控件不能过小且紧挨等。当某一功能有过多的操作时,可以将一些常用的或者说主要的操作放到首页面上,然后增加一个More或者高级按按钮来显示其它的操作。也可以借助TabControl来进行分类显示。

如下图所示:

    

       2)尽量减少输入操作,而增加方便用户操作的选择操作。

       比如:设置->区域设置如图:

        

3)尽量对控件进行动态的创建。由于现在的Pocket PC 增加了横屏显示,以及高分辨率的出现,这样为了便于程序能够运行在各种各样Pocket PC上,在开发的过程中要尽量的考虑这些因素。这点也是今后开发过程中最需要注意的一点。

 

三、           Smartphone UI 设计:
   
SmartphoneUI设计相对于Pocket PC 来说又有一定的差异,首先Smartphone不支持触笔的操作,增加了键盘操作,并且所有的操作都是通过键盘来完成。这样就限制了Smartphone对一些控件的支持度。在Smartphone的开发中有许多控件不支持,比如:Button,TabControl,Inputpanel等等。所有在Microsoft Visual Studio .NET 2003Tools box中显示恢色的控件我们都不能使用,对于一些特定的控件要我们自己来进行开发。
1Smartphone MenuBar设计习惯
Smartphone MenuBar有两个Item,左键主要是常用操作,并且不支持子菜单,右键为菜单项,可以在其中设置任何菜单操作。另外,我们可以在一个Form中设置多个主菜单,当根据需要时进行切换。切换方式为:
         this.Menu = this.mainMenu1;  // mainMenu1为你当前需要的menu。

2)设置基于 Windows Mobile Smartphone 输入模式:
代码示例如下:

public class Win32Pinvoke

     {

         public enum InputMode

         {

              Spell = 0,

              T9 = 1,

              Numbers = 2,

              Text = 3

         }

         // Constants required for interop

         const int GW_CHILD = 5;

         const uint EM_SETINPUTMODE = 0x00DE;

 

         [DllImport("coredll.dll", EntryPoint="GetCapture")]

         private static extern IntPtr GetCapture();

         [DllImport("coredll.dll", EntryPoint="GetWindow")]

         private static extern IntPtr GetWindow(IntPtr hWnd, int uCmd);

         [DllImport("coredll.dll", EntryPoint="SendMessage")]

         private static extern uint SendMessage(IntPtr hWnd, uint msg, uint wParam,

              uint lParam);

 

         public static void SetInputMode(Control ctrl, InputMode mode)

         {

              // Get the handle for the current control

              ctrl.Capture = true;

              IntPtr h = GetCapture();

              ctrl.Capture = false;

              // Get the child window for the control

              IntPtr hEditbox = GetWindow(h, GW_CHILD);

              // Set the input mode

              SendMessage(hEditbox, EM_SETINPUTMODE, 0, (uint)mode);

         }

}

使用方法如下:

private void textBox_GotFocus(object sender, System.EventArgs e)

     {

              Win32Pinvoke.SetInputMode(this.textBox,Win32Pinvoke.InputMode.Numbers);

}

3Smartphone中控件的Tab顺序:

Smartphone中控件的Tab顺序和加入控件的顺序一致,比如:有件:TextBox1,TextBox2,Textbox3,我们想要Tab顺序为3->2->1,那么我们在Form中加入的顺序就应该为

this.Controls.Add(this.TextBox3);

              this.Controls.Add(this.TextBox2);

         this.Controls.Add(this.TextBox1);

对于VS2003自动生成的代码,我们需要在InitializeComponent()函数中手动更改他们的顺序。

 

4Form滚动的实现:

Smartphone的滚动的实现有两种方式:一种是没有接受输入焦点控件的实现,我称其为Label滚动;另一种是有接受输入焦点的控件的实现,我称为TextBox滚动。

1Label滚动:见(Pocket PC UI 设计第三点Form滚动的实现)这点最主要的一点是焦点要在VScrollBar上,在FormLoad事件中要指定vScrollBar.Focus(),这样就可以响影导航键里上下键的操作。

2) TextBox滚动:同样是利用PanelVScrollBar来实现,不同的地方就是当每次可接受焦点的控件接受到焦点时,要计算当前Panel的显示位置。

代码示例:

public ScrollForm()

         {

              //

              // Windows 窗体设计器支持所必需的

              //

              InitializeComponent();

 

              //

              // TODO: 在 InitializeComponent 调用后添加任何构造函数代码

              //

              this.vScrollBar1.Height = this.ClientSize.Height;

              this.vScrollBar1.Minimum = 0;

              this.vScrollBar1.Maximum = this.panel1.Height - this.ClientSize.Height;

}

///<summary>

         ///设置当前的显示位置.

         ///</summary>

///<param name="topSender">当前接受焦点的控件的顶层控件,比如一个TextBox上的解释性Label控件</param>

         ///<param name="bottomSender">当前接受焦点的控件</param>

         private void SetScrollPosition(object topSender, object bottomSender)

         {

              //get bounds of controls to focus on

              int top = ((Control)topSender).Top - 2;

              int bottom = ((Control)bottomSender).Bottom;

              int height = bottom - top;

 

              //get scroll position

              int pos = this.vScrollBar1.Value;

 

              //check if control is within view

              if (pos < top && bottom < (pos+this.ClientSize.Height))

              {

                   //do nothing

                   return;

              }

 

              //check if control is above view

              if (bottom < pos + height)

              {

                   //scroll up to view, ensuring the topSender is first visible on form

                   this.vScrollBar1.Value = top;

              }

 

              //check if control is below view

              if (bottom > (pos+this.ClientSize.Height))

              {

                   //scroll down to view, ensuring the bottomSender is last visible on form

                   this.vScrollBar1.Value = bottom - this.ClientSize.Height;

              }

 

              // Set the panel position on the form, to redraw the application

              this.panel1.Top = -this.vScrollBar1.Value;

 

              return;

         }

使用如下:

private void textBox1_GotFocus(object sender, System.EventArgs e)

         {

              SetScrollPosition(this.label1,sender);

}
(5)Form中的一些主要实现方式:

本节可参见Pocket PC UI 设计中的第二点Form中的一些主要实现方式

 类似资料: