忆龙2009:Microsoft .NET Compact Framework 开发常见问题解答

.NET编程 同时被 2 个专栏收录
17 篇文章 0 订阅
9 篇文章 0 订阅

Microsoft .NET Compact Framework 开发常见问题解答

msdn上的地址

http://www.microsoft.com/china/msdn/library/NetFramework/netcompactframework/debugdestime.mspx

Microsoft .NET Compact Framework 开发的常见问题解答。

这个 FAQ 有部分是通过编辑公共
.NET Compact Framework 新闻组 (microsoft.public.dotnet.framework.compactframework) 贴出的问题和解答而得到的。.NET Compact Framework 团队衷心感谢参加公共新闻组的每个人,感谢他们对本 FAQ 和整个 .NET Compact Framework 开发社区做出的贡献。

要想获得 FAQ 项,请将电子邮件发送到
netcfaq@microsoft.com

*

本页内容

1. 开发1. 开发

2. 图形2. 图形

3. 部署3. 部署

4. 图形用户界面 (GUI):窗体4. 图形用户界面 (GUI):窗体

5. 图形用户界面 (GUI):常规5. 图形用户界面 (GUI):常规

6. 互操作性和本机代码6. 互操作性和本机代码

7. 常规7. 常规

8. 通信和 Web 服务8. 通信和 Web 服务

9. SQL CE 和数据9. SQL CE 和数据

10. 其他信息10. 其他信息

11. 连接11. 连接

12. 基于 Windows Mobile 的 Smartphone12. 基于 Windows Mobile 的 Smartphone

1. 开发

1.1. 什么是 Microsoft .NET Compact Framework?

Microsoft .NET Compact Framework 是针对 Microsoft .NET 计划的智能设备开发框架,是实现 Microsoft 随时随地在任何设备上为客户提供良好体验的目标的关键所在。.NET Compact Framework 将托管代码和 Web 服务带给了智能设备,它允许安全的、可下载的应用程序在诸如个人数字助理 (PDA)、移动电话和机顶盒等设备上运行。

http://msdn.microsoft.com/mobility/prodtechinfo/devtools/netcf/overview/default.aspx

1.2.开发 .NET Compact Framework 应用程序需要什么工具?

Visual Studio .NET 为基于 Windows Mobile 的 Pocket PC 2000、基于 Windows Mobile 的 Pocket PC 2002 和 Windows CE .NET 4.1 设备开发基于 .NET Compact Framework 的应用程序需要 2003 Professional 或更高版本。Visual Studio .NET 2003 附带了 .NET Compact Framework。

http://msdn.microsoft.com/mobility/prodtechinfo/devtools/vstudio/default.aspx

在最新的 Windows Mobile 平台上进行开发还有其他的 SDK 可用:

Windows Mobile 2003 Pocket PC SDK:
http://www.microsoft.com/downloads/details.aspx?familyid=9996b314-0364-4623-9ede-0b5fbb133652&displaylang=en

Windows Mobile 2003 Smartphone SDK:
http://www.microsoft.com/downloads/details.aspx?familyid=a6c4f799-ec5c-427c-807c-4c0f96765a81&displaylang=en

本文将提供用 .NET Compact Framework 1.0 和 Visual Studio .NET 2003 开发健壮的智能客户端设备应用程序的说明。
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/netcfgetstarted.asp

1.3. 哪里可以下载最新的工具和软件?

Visual Studio .NET 2003 试用版可以通过以下地址获得:
http://msdn.microsoft.com/vstudio/productinfo/trial/default.aspx

最新的平台更新和 .NET Compact Framework service pack 可以通过以下地址获得:
http://msdn.microsoft.com/mobility/downloads/default.aspx

1.4. .NET Compact Framework 支持什么设备?

.NET Compact Framework 支持基于 Windows Mobile 2000 的 Pocket PC、基于 Windows Mobile 2002 的 Pocket PC、基于 Windows Mobile 2003 的 Pocket PC、基于 Windows Mobile 的 Smartphone 和运行 Windows CE .NET 4.1 及更高版本的嵌入式系统。

1.5. 以后 .NET Compact Framework 将会支持什么设备?

不久以后,.NET Compact Framework 将会作为一个操作系统 (OS) 组件,在所有的 Microsoft 智能设备中提供,包括将来基于 Windows Mobile 的 Pocket PC 设备、基于 Windows Mobile 的 Pocket PC Phone Edition、基于 Windows Mobile 的 Smartphone、Windows CE for Automotive 和 MSTV。每种特定设备的具体时间选择将由各个产品发布周期确定。

Windows CE .NET 4.1 也支持 .NET Compact Framework,将其作为一个集成的 OS 组件,因此允许 OEM 使用 Platform Builder 工具将 .NET Compact Framework 嵌入到所有装备 Windows CE 的新设备中。

1.6. 调试器在与模拟器建立连接时为什么会失败(错误启动应用程序)?

以下链接是针对调试的安装和疑难解答指南:
http://download.microsoft.com/download/c/d/b/cdbff573-73fb-4f9f-a464-c5adc890e1ae/Readme.htm

1.7. .NET Framework 和 .NET Compact Framework 之间有什么区别?

请参见下面 .NET Framework 和 .NET Compact Framework 之间的比较:
http://msdn.microsoft.com/library/en-us/dv_evtuv/html/etconComparisonsWithNETFramework.asp

.NET Compact Framework 类库比较工具中的信息:
http://msdn.microsoft.com/library/en-us/dv_spchk/html/NET_Compact_Framework.htm

1.8.最新的 .NET Compact Framework Service Pack 有什么新内容?

.NET Compact Framework SP2 提供了针对大量缺陷的补丁。补丁列表可由以下链接获得:
http://www.microsoft.com/downloads/details.aspx?familyid=10600643-09b3-46d8-ba28-bc494bc20d26&displaylang=en

.NET Compact Framework SP1 提供了针对大量缺陷的补丁。补丁列表可由以下链接获得:
http://www.microsoft.com/downloads/details.aspx?familyid=1f62a2a3-7282-4ba9-b26b-2267e972501d&displaylang=en

注: Service Pack 2 (SP2) 替代了 Service Pack 1 (SP1),它包括所有 service pack 的最新更新。

1.9. 在 .NET Compact Framework 开发中,基于 Windows Mobile 的 Pocket PC 和 Windows CE .NET 之间有什么区别?

这篇文章概述了为基于 Windows Mobile 的 Pocket PC 和 Microsoft Windows CE .NET 平台开发基于 Microsoft .NET Compact Framework 的应用程序之间的区别。
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/netcfPPCtoCE.asp

1.10. 在哪里可以找到有关如何创建基于 .NET Compact Framework 的应用程序的更多信息?

下列资源有助于您了解如何创建基于 .NET Compact Framework 的应用程序:

•.NET Compact Framework 快速入门
http://samples.gotdotnet.com/quickstart/compactframework/

•MSDN 移动与嵌入式技术开发人员中心中的 .NET Compact Framework 白皮书:
http://msdn.microsoft.com/mobility/understanding/articles/default.aspx

1.11. .NET Compact Framework 的文档在什么位置?

http://msdn.microsoft.com/library/en-us/dv_evtuv/html/etconNETCompactFramework.asp

1.12. 如何指定在每次调试器运行时不必复制依赖文件?

在 Visual Studio .NET 2003 中,右键单击该项目并选择 Properties。将 Build Action 更改为 None。这样就不会再复制此文件了。如果此文件已修改或者需要再复制,则将 Build Action 更改为 Content

1.13. 如何设置模拟器属性?

在 Visual Studio .NET 2003 中,从菜单中选择 Tools->Options。然后打开 Device Tools 文件夹并选择 Devices。现在应该能看到一个显示设备选择列表的对话框。选择您想要修改的设备,然后按 Configure 按钮。

现在您应该能够看到一个含有几个选项卡的对话框,它允许您访问和修改设置,例如内存和屏幕大小。

1.14. 如何调试 Microsoft .NET Compact Framework 应用程序?

Microsoft .NET Compact Framework 完全集成在 Visual Studio .NET 2003 中,它支持的调试功能与对其他 Visual Studio .NET 应用程序类型可用的调试功能相同。但是,在独立设备或在仿真器中调试运行的应用程序时,用户需要注意一些特殊事项。请参考下列建议以获得最详尽的 .NET Compact Framework 调试体验:
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/CompactFXDebug.asp

1.15. 如何开始使用 Visual Basic .NET 为设备开发应用程序?

了解如何使用用于 Visual Studio .NET 的智能设备扩展 (SDE) 来为支持 .NET Compact Framework 的智能设备构建 Windows 应用程序。这篇文章包括对整个开发、调试和部署过程的检查,并探讨了 .NET Framework 和 .NET Compact Framework 之间的区别。
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/sdeforvb.asp

1.16. 如何将 .NET Compact Framework 程序集安装到全局程序集缓存 (GAC) 中?

http://msdn.microsoft.com/library/en-us/dncfhowto/html/HOWTOGAC.asp

1.17. 当通过 Visual Studio .NET 2003 部署智能设备应用程序时,如何处理“共享冲突”?

这篇文章阐述了阻止通过 Visual Studio .NET 2003 部署应用程序的共享冲突产生的原因,并介绍了解决这一冲突的方法。
http://msdn.microsoft.com/library/en-us/dncfhowto/html/HOWTOSharingviolation.asp

1.18. 公共语言运行库 (CLR) 是什么?

.NET Compact Framework 提供了一个名为公共语言运行库的运行时环境,它运行代码并提供一些可以使开发过程更加轻松的服务。在这篇概述中可以了解更多内容:
http://msdn.microsoft.com/library/en-us/cpguide/html/cpconcommonlanguageruntimeoverview.asp

1.19. 全局程序集缓存 (GAC) 是什么?

每台安装公共语言运行库的计算机都有一个机器范围的代码缓存,称为全局程序集缓存。全局程序集缓存中存储的程序集是专门由计算机中的几个应用程序共享的程序集。这篇文章提供了有关 GAC 的更多信息:
http://msdn.microsoft.com/library/en-us/cpguide/html/cpconglobalassemblycache.asp

1.20. 在 .NET Compact Framework 中如何管理内存?

自动内存管理是在托管执行过程中 CLR 提供的服务之一。CLR 垃圾回收器管理应用程序的内存分配和释放,如这篇文章所描述的:
http://msdn.microsoft.com/library/en-us/cpguide/html/cpconautomaticmemorymanagement.asp

1.21. 当网络协议数超过 50 时,为什么就无法部署到设备?

请参见本 FAQ 中标题为“11.4.当网络协议数超过 50 时,为什么无法部署到设备?”的项。

1.22. 为什么有跨平台二进制?

.NET Compact Framework 和执行引擎是完整的 .NET Framework 和 CLR 的一个兼容子集实现。当不存在强名称绑定策略时,针对 .NET Compact Framework 编译的应用程序将会绑定和运行在整个 .NET Framework 上,但有一些重要的例外:

•.NET Compact Framework 程序集由不同的强名称密钥对进行签名,这样 CLR 可以将它们与其全部 .NET 副本区分开来。

•将来发布的完整的 .NET Framework 和 CLR 将包括绑定策略,它可以将完整的 .NET Framework 程序集替换为兼容 .NET Compact Framework 引用。然后在一些常见的情况中,它可以重复使用现有的组件而不需要重新链接。例如,如果您的组件只引用 .NET Compact Framework System 和 System.NET 类,则它可以在 .NET Compact Framework 和整个 .NET Framework 上很好地运行而不需要重新链接。

•如果您的引用功能与 .NET Compact Framework 不同,例如基于 Windows Mobile 的 Pocket PC 特定的 UI 控件,则您的程序将会在与整个 .NET Framework 绑定时失败。

•就像跨平台二进制兼容性简化了中间件组件的开发和部署一样,Microsoft 相信胖客户端应用程序应该利用特定于设备的功能来提高用户体验。这意味着最好的 GUI 代码可能是特定于目标的。

•虽然 Microsoft 已经做出了很大的努力,将特定于设备的功能分解为离散的命名空间和程序集以避免绑定冲突,但可能存在版本 1 无法处理的不兼容分解的情况。在这些情况下,在整个 .NET Framework 中滥用特定于设备的功能将会引发运行时异常而非应用程序加载异常。

1.23. 所有这些 ARM 二进制是些什么?

XScale 支持 ARM v5 指令集,不过它也向后兼容 ARMv4 指令集。它有三个变种:

•ARMv4 -> 它只支持 32 位 ARMv4 指令

•ARMv4T ->“T”代表 Thumb。Thumb 是 ARM 16 位指令模式

•ARMv4I ->“I”代表交互作用 (Interworking)。它允许 32 位指令和 16 位指令共存

对于其他的 ARM 处理器:

•StrongARM (SA1110) -> 只支持 ARMv4 指令

•ARM920T 等 -> 通常支持这三个变种

.NET Compact Framework 将提供三组用于 ARM 的二进制。

•用于基于 Windows Mobile 2000 和基于 Windows Mobile 2002 的 Pocket PC 2002 的 ARMv4。它将运行 ARM 设备(包括 Xscale)的所有 ARM。部署到这些设备中的 cab 只能在名称中包含“arm”。

•用于 Windows CE.NET 的 ARMv4。它将运行在通过 Platform Builder 中的 ARMv4 内核编译的 Windows CE.NET 设备中。它也是用于基于 Windows Mobile 的 Pocket PC 2003 的二进制。为这些设备部署的 cab 在名称中包含“armv4”。

•用于 Windows CE.NET 的 ARMv4T 或 ARMv4I。它将运行在通过 Platform builder 中的 ARMv4T 或 ARMv4I 内核编译的 Windows CE.NET 设备中。部署到这些设备中的 cab 在名称中包含“armv4T”。

1.24. 如何写入设备的注册表中?

Visual Studio .NET 没有附带用于 Windows CE 的远程注册表编辑器。要设置注册表项,可以使用以下工具之一:

•Microsoft Embedded Visual Tools Remote Registry Editor

•Microsoft Windows CE Platform Builder Remote Registry Editor

•基于 PHM Windows Mobile 的 Pocket PC Registry Editor(共享件,可以很容易在网上找到)

1.25. 安装完成后如何防止 .CAB 文件被删除?

将 .CAB 文件的属性设置为只读,可以防止 .CAB 文件被自动删除。

1.26. 如何确定设备中安装的 .NET Compact Framework 的版本?

发行的每个 .NET Compact Framework 版本都有一个不同的 Win32 文件版本号(它是与程序集版本相独立的版本号,对于发行的所有 .NET Compact Framework 第一版(包括 Service Pack),这两者应该是一样的)。

要查看安装的是什么版本,可以使用文件资源管理器,定位于设备的 /Windows 目录,并单击名为 CGACUTIL 的文件。将会弹出一个消息框,显示安装在设备中的 .NET Compact Framework 的 Win32 文件版本。

RTM = 1.0.2268.0SP1 = 1.0.3111.0SP2 Recall = 1.0.3226.0SP2 Beta = 1.0.3227.0SP2 Final = 1.0.3316.0

要以编程方式确定版本,可以使用 System.Environment.Version.ToString()。

要通过桌面安装程序确定版本,请参见本 FAQ 中标题为“3.10.如何通过桌面安装程序检测 .NET Compact Framework 的版本?”的项。

1.27. 如何将文件复制到模拟器中?

一种方式是在开发 PC 中创建一个文件共享,然后通过模拟器中的文件资源管理器连接到该共享。也可以将文件从共享位置复制并粘贴到模拟器的本地文件系统中。另一种方式是将文件添加到智能设备项目中,并将它们的 Build Action 属性设置为“Content”。有关“文件属性”的更多信息,请参阅 Visual Studio .NET 联机文档:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcon/html/vbconfileproperties.asp

以下内容逐步介绍了如何将一个“Content”文件添加到智能设备项目中:

1.打开或创建一个智能设备项目,

2.在“View”菜单中,单击“Solution Explorer”,

3.在“Solution Explorer”中,右键单击您的项目,指向“Add”并单击“Add Existing Item”。浏览至想要的文件并添加到该项目中。

4.在“Solution Explorer”中,右键单击添加的文件并单击“Properties”,

5.如果 Build Action 属性尚未设置,则将它设置为“Content”。

1.28. 为什么基于 Windows Mobile 的 Pocket PC 2002 SDK 安装失败?

表现在“注册组件”时,基于 Windows Mobile 的 Pocket PC 2002 SDK 安装程序挂起。

原因: 在尝试运行模拟器时,未注册的组件导致安装挂起。

解决办法: 在控制台窗口提示中键入:cd /WINNT/system32regsvr32 atl.dll

1.29. 如何调试智能设备应用程序使用的 Web 服务?

您需要将调试器附加到 ASP.NET 辅助进程中。

有关更多信息,请参见以下链接:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtskdebugginganaspdeployedwebapplication.asp

1.30. 什么是 .NET Compact Framework 的足迹?

.NET Compact Framework 存储大小:

•在基于 Windows Mobile 的 Pocket PC 2000/2002 上有 1.55MB (ROM)

•在用于 Pocket PC 2003 或 Windows CE .NET 设备的 Windows Mobile 上有 1.35MB (ROM)

运行 RAM 的要求:

•.5 MB+(取决于应用程序)

典型的应用程序大小:

•5 - 100 KB

1.31. 如何将 imgdecmp.dll 包括在模拟器映像中?

您必须让 OEM 将它包括在设备的映像中。如果您就是 OEM 而且您正在使用 Platform Builder 4.2,则包括 .NET 项目的 OS 依赖项会自动使 imgdecmp.dll 成为模拟器映像的一部分 — 如果这样不行则再引用 cesysgen.bat。另一种方法是设置环境变量“__SYSGEN_IMGDECMP=1”,显式强制该 DLL 包含在映像中。

1.32. 如何以编程方式替换全局程序集缓存 (GAC) 中的程序集?

可以通过以编程方式启动 cgacutil 来直接在 GAC 中安装程序集和从 GAC 中删除程序集。

•使用 -u 选项可以从 GAC 删除程序集

•使用 -i 选项可以在 GAC 中安装程序集

通常最安全的做法是重新安装一个程序集之前先将它删除。

1.33. 如何在台式计算机或便携式计算机中显示基于 Windows Mobile 的 Pocket PC 应用程序而不需要任何设备端配置?

从 Windows Mobile Developer Power Toys 下载 ActiveSync Remote Display:
http://www.microsoft.com/downloads/details.aspx?FamilyId=74473FD6-1DCC-47AA-AB28-6A2B006EDFE9&displaylang=en

1.34. 如何使 Activesync 能够从 Visual Studio .NET 2003 连接到模拟器会话?

请参见本 FAQ 中标题为“11.17.如何使 Activesync 能够从 Visual Studio .NET 2003 连接到模拟器会话?”的项。

1.35. 如何将文件复制到当前连接到桌面 ActiveSync 的设备中?

请参见本 FAQ 中标题为“11.18.如何将文件复制到当前连接到桌面 ActiveSync 的设备中?”的项。

1.36. 如何重点测试用户输入?

从 Windows Mobile Developer Power Toys 下载 Hopper:
http://www.microsoft.com/downloads/details.aspx?FamilyId=74473FD6-1DCC-47AA-AB28-6A2B006EDFE9&displaylang=en

1.37. 从哪里可以获得平台生成器目标控件窗口的 UI 版本?

从 Windows Mobile Developer Power Toys 下载 Jshell:
http://www.microsoft.com/downloads/details.aspx?FamilyId=74473FD6-1DCC-47AA-AB28-6A2B006EDFE9&displaylang=en

1.38. 从哪里可以获得用于基于 Windows Mobile 的 Pocket PC 2003 设备的命令外壳?

从 Windows Mobile Developer Power Toys 下载 PPC 命令外壳:
http://www.microsoft.com/downloads/details.aspx?FamilyId=74473FD6-1DCC-47AA-AB28-6A2B006EDFE9&displaylang=en

1.39. 如何获得当前运行进程的详细信息?

从 Windows Mobile Developer Power Toys 下载 RAPI Debug:
http://www.microsoft.com/downloads/details.aspx?FamilyId=74473FD6-1DCC-47AA-AB28-6A2B006EDFE9&displaylang=en

1.40. 如何从桌面远程启动基于 Windows Mobile 的 Pocket PC 上的应用程序?

从 Windows Mobile Developer Power Toys 下载 RAPI Start:
http://www.microsoft.com/downloads/details.aspx?FamilyId=74473FD6-1DCC-47AA-AB28-6A2B006EDFE9&displaylang=en

1.41. 为什么不能加载具有相同名称的不同程序集?

这是设计的原因。您要么必须更改 DLL 的名称,或者如果 DLL 具有强名称,则将它们放在 GAC 中并使用具有完全强名称的 Assembly.Load。

1.42. 如何强制 Visual Studio .NET 2003 连接到较新版本的基于 Windows Mobile 的 Pocket PC 2003 模拟器?

从 Windows Mobile Developer Power Toys 下载 Emulator ActiveSync Connection Tool:
http://www.microsoft.com/downloads/details.aspx?familyid=74473FD6-1DCC-47AA-AB28-6A2B006EDFE9&displaylang=en

它允许 ActiveSync 通过 Visual Studio .NET 2003 连接到您的模拟器会话。为 4.2 模拟器创建一个 ActiveSync 会话,它可以使 Visual Studio 2003 将其视为一个真正的设备(选择 PPC 设备作为部署目标)。

1.43. 为什么我的自定义控件不能正确地显示在工具箱中?

当在 Visual Studio .NET 2003 中为智能设备自定义控件添加设计器支持时,您可能会碰到以下问题:

•在设计时无法将一个图标与控件相关,以便显示在工具箱中

•当添加到工具箱中时,该组件变灰

原因

•使用独立于控件项目的设计项目。Visual Studio .NET 自动将项目的默认命名空间作为位图的名称。“默认命名空间”默认为项目名称。这可能会产生问题,因为设计项目的名称与运行时项目的名称略有差别。

•没有设置正确的 ToolBoxItemFilterAttribute 值

解决方案

提供以下示例:Runtime VS.NET Project:MyProject类名称:MyProject.MyClass设计 VS.NET 项目名称:MyProject.DesignVS.NET 设计项目中的 BitMap 名称:Foo.bmp设计程序集中的位图名称:MyProject.Design.MyClass.bmp— 这样会产生问题,因为该位图需要以下名称:MyProject.MyClass.bmp

在以上示例中,将设计项目的默认命名空间设置为“MyProject”而非“MyProject.Design”就可以解决这个问题。

检查程序集中位图名称的最简单方法是运行 ILDASM 并打开 Manifest。该清单的尾部列出了嵌入式资源。

如果您创建了一个从 Component 类派生的自定义组件,则您的代码必须包括以下语句,这样您的组件才能出现在工具箱中:

ToolBoxItemFilterAttribute("NETCF",ToolBoxItemFilterType.Require)
ToolBoxItemFilterAttribute("System.CF.Windows.Forms", ToolBoxITemFilterType.Custom)

返回页首返回页首

2. 图形

2.1. 如何创建 Graphics 对象?

图形对象根据其用途有几种创建方式:

通过 OnPaint,使用 PaintEventArgs 中提供的对象:

//C#

protected override void OnPaint(PaintEventArgs e)
{  e.Graphics.DrawLine(...);}

'VB

Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)    
e.Graphics.DrawLine(...)
End Sub 'OnPaint

通过代码中的其他区域,该函数是 Control 的一个方法,可以用来创建任何控件的图形对象:

//C#

using System.Drawing;
Graphics g = this.CreateGraphics();

'VB

Imports System.Drawing
Dim g As Graphics = Me.CreateGraphics()

直接在一个位图中绘制:

//C#

using System.Drawing;
Bitmap bm = new Bitmap(10,10);
Graphics g = Graphics.FromImage(bm);

'VB

Imports System.Drawing
Dim bm As New Bitmap(10, 10)
Dim g As Graphics = Graphics.FromImage(bm)
2.2. 可以怎样优化 GDI+ 呈现?

当使用 Graphics 绘画调用时,有几种基本的编码实践可以帮助提高绘画速度:

•只创建一个 Graphics 对象(或者使用来自 OnPaint 中的 PaintEventArgs 的 Graphics 对象)。

•在屏幕外的位图中完成所有绘画,然后拖曳该位图,使它一次全部显示出来。

•只重画图像的更改部分。

•尽可能使绘制的源和目的大小相同(不要拉伸等等)。

也许最重要的实践是保留需要重画的项目的痕迹以便使出现的绘画量尽可能少。例如,如果拖曳光标跨过图像,就不需要重画整个图像。相反,只需重画前一个光标位置覆盖的图像部分。

2.3. 如何在窗体中绘制图像?

此示例显示了如何将一个图形作为窗体的背景图像显示:
http://samples.gotdotnet.com/quickstart/CompactFramework/doc/bkgndimage.aspx

2.4. 如何绘制具有透明度的图像?

绘制有透明度的图像需要一个指定透明颜色的 ImageAttributes 对象。当前,.NET Compact Framework 支持单种颜色的原色调透明度。虽然 SetColorKey 函数允许一个颜色范围,但最小和最大的颜色必须相同,否则会产生运行时 ArgumentException:

//C#

using System.Drawing.Imaging;
ImageAttributes attr = new ImageAttributes();

'VB

Imports System.Drawing.Imaging
Dim attr As New ImageAttributes()

以下代码演示了如何根据图像的左上像素设置透明色调。

//C#

attr.SetColorKey(bmp.GetPixel(0,0), bmp.GetPixel(0,0));

'VB

attr.SetColorKey(bmp.GetPixel(0,0), bmp.GetPixel(0,0))

也可以按照如下所述方法显式设置颜色:

//C#

attr.SetColorKey(Color.FromArgb(255,0,255),Color.FromArgb(255,0,255));
attr.SetColorKey(Color.Fuchsia, Color.Fuchsia);

'VB

attr.SetColorKey(Color.FromArgb(255,0,255),Color.FromArgb(255,0,255))
attr.SetColorKey(Color.Fuchsia, Color.Fuchsia)

然后可以用重载的 Graphics.DrawImage 函数(它将 ImageAttributes 对象作为一个参数)来绘制图像:

//C#

Rectangle dstRect = new Rectangle(0, 0, bmp.Width, bmp.Height); 
g.DrawImage(bmp, dstRect, 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attr);

'VB

Dim dstRect As New Rectangle(0, 0, bmp.Width, bmp.Height)
g.DrawImage(bmp, dstRect, 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attr)
2.5. 当我在 TextBox 中调用 CreateGraphics 时它为什么会失败?

只有 Control 和 Form 类支持 Control.CreateGraphics()。

2.6. 如何确定文本的屏幕大小?

使用 Graphics 方法 MeasureString。以下代码演示了如何在一些文本周围绘制一个框:

//C#

using System.Drawing;
protected override void OnPaint(PaintEventArgs e)
{  
    string s = "Hello World"  Pen pen = new Pen(Color.Fuchsia);  
    Font font = new Font("Arial", 18, FontStyle.Regular);  
    Brush brush = new SolidBrush(Color.Black);  
    SizeF sSize = e.Graphics.MeasureString(s, font);  
    Rectangle r = new Rectangle(9, 199,(int)sSize.Width + 1, (int)sSize.Height + 1);  
    e.Graphics.DrawRectangle(pen, r);  
    e.Graphics.DrawString(s, font, brush, 10.0f, 200.0f);  
    base.OnPaint (e);
}

'VB

Imports System.Drawing
Protected Overrides Sub OnPaint(e As PaintEventArgs)  
    Dim s As String = "Hello World"    
    Dim pen As New Pen(Color.Fuchsia)  
    Dim font As New Font("Arial", 18, FontStyle.Regular)  
    Dim brush = New SolidBrush(Color.Black)  
    Dim sSize As SizeF = e.Graphics.MeasureString(s, font)  
    Dim r As New Rectangle(9, 199, Fix(sSize.Width) + 1, Fix(sSize.Height) + 1)  
    e.Graphics.DrawRectangle(pen, r)  
    e.Graphics.DrawString(s, font, brush, 10F, 200F)  
    MyBase.OnPaint(e)
End Sub 'OnPaint
2.7. 可以设置画笔的宽度吗?

.NET Compact Framework 中不可以设置画笔宽度。有一些替代办法,包括:

•采用 Graphics.FillRectangle 方法绘制实心矩形

•绘制多条并行线

•采用 GAPI 编写自定义图形例程

2.8. 如何缩放图像?

虽然没有对缩放和拉伸单个图像的内在支持,但这些效果也可以很轻松地实现,方法是使用相关的 Graphics 对象创建新的 Bitmap 对象,然后将原有 Bitmap 想要的部分复制到新建对象上。以下示例创建了两个大小相同的位图,其中第二个位图包含第一个位图经放大的中心部分,并假定项目有一个名为 MyImage.bmp 的嵌入式资源。这样的技术也可以用来拉伸图像,方法是修改源和目的矩形以便它们没有保留其原有的纵横比。

//C#

using System.Drawing;
using System.Reflection;
Bitmap m_bmpOriginal;
Bitmap m_bmpZoom;
private void Form1_Load(object sender, System.EventArgs e)
{    
    Assembly asm = Assembly.GetExecutingAssembly();    
    m_bmpOriginal = new Bitmap(asm.GetManifestResourceStream(asm.GetName().Name
      + ".MyImage.bmp"));    // Take the center quarter of m_bmpOriginal
    // and create stetch it into m_bmpZoom of the same size    
    m_bmpZoom = new Bitmap(m_bmpOriginal.Width, m_bmpOriginal.Height);    
    Graphics gZoom = Graphics.FromImage(m_bmpZoom);        
    Rectangle srcRect = new Rectangle(m_bmpOriginal.Width / 4, m_bmpOriginal.Height / 4,
      m_bmpOriginal.Width / 2, m_bmpOriginal.Height / 2);    
    Rectangle dstRect = new Rectangle(0, 0, m_bmpZoom.Width, m_bmpZoom.Height);    
    gZoom.DrawImage(m_bmpOriginal, dstRect, srcRect, GraphicsUnit.Pixel);
}
 
protected override void OnPaint(PaintEventArgs e)
{    
e.Graphics.DrawImage(m_bmpOriginal, 0, 0);    
e.Graphics.DrawImage(m_bmpZoom, 125, 0);    
base.OnPaint (e);
}

'VB

Imports System.Drawing
Imports System.Reflection
Private m_bmpOriginal As Bitmap
Private m_bmpZoom As Bitmap
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load    
    Dim asm As [Assembly] = [Assembly].GetExecutingAssembly()    
    m_bmpOriginal = New Bitmap(asm.GetManifestResourceStream((asm.GetName().Name _
      + ".MyImage.bmp")))    ' Take the center quarter of m_bmpOriginal
    ' and create stetch it into m_bmpZoom of the same size    
    m_bmpZoom = New Bitmap(m_bmpOriginal.Width, m_bmpOriginal.Height)    
    Dim gZoom As Graphics = Graphics.FromImage(m_bmpZoom)    
    Dim srcRect As New Rectangle(m_bmpOriginal.Width / 4, m_bmpOriginal.Height / 4, _
      m_bmpOriginal.Width / 2, m_bmpOriginal.Height / 2)    
    Dim dstRect As New Rectangle(0, 0, m_bmpZoom.Width, m_bmpZoom.Height)    
    gZoom.DrawImage(m_bmpOriginal, dstRect, srcRect, GraphicsUnit.Pixel)
End Sub 'Form1_Load
 
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)    
    e.Graphics.DrawImage(m_bmpOriginal, 0, 0)    
    e.Graphics.DrawImage(m_bmpZoom, 125, 0)    
    MyBase.OnPaint(e)
End Sub 'OnPaint
2.9. 为什么我不能加载图像?

确保 imgdecmp.dll 位于设备的 Windows 目录。

有关更多信息,请参见本 FAQ 中的主题“ HYPERLINK /l "1.31" 1.31.如何将 imgdemp.dll 包括在模拟器映像中?”。

2.10. 如何使用 GAPI 创建图形引擎?

这篇文章描述了如何创建包装 GAPI (Game API) 的 DLL,使之与 .NET Compact Framework 兼容,并用它来创建和优化托管代码中的基本图形库。
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/WrapGAPI1.asp

这篇文章实现了位图的加载和显示,从而扩展了“Dancing Rectangles”示例。它还实现了一些更高级的功能,例如动画位图、源和目的色调透明和 alpha 值混合处理(也就是半透明)。
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/WrapGAPI2.asp

这篇文章实现了点、线和从 8 位位图转换而来的自定义 1 位字体的绘制,从而扩展了“Dancing Zombies”示例。它还实现了一个重写硬件按钮功能和跟踪按钮状态的输入系统。
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/WrapGAPI3.asp

返回页首返回页首

3. 部署

3.1. 如何创建基于 Windows Mobile 的 Pocket PC 安装应用程序?

这篇文章介绍了如何创建一个 .msi 文件,它可以从桌面运行,并在其他基于 Windows Mobile 的 Pocket PC 设备上安装应用程序。此开发过程是自动化的,所以它可以轻松地构建所有必需的组件并将其包装在 .msi 文件中。这篇文章提供了 C# 和 Microsoft Visual Basic .NET 的示例代码。

http://msdn.microsoft.com/library/en-us/dnnetcomp/html/netcfdeployment.asp

3.2. 应用程序安装中可以包括哪些可重新发布的文件?

您可以将最终用户可重新发布的文件随应用程序提供给您的客户,以便帮助他们更新设备。您不应该解开最终用户可重新发布的文件并将其中的内容发送给您的客户。不过您可以解开开发人员可重新发布的文件并将其中的内容发送给您的客户。

.NET Compact Framework 可重新发布的包可以在这里下载:
http://msdn.microsoft.com/mobility/downloads/updates/default.aspx

3.3. 如何在桌面上创建不需要 .NET Framework 的安装程序?

创建 INF 文件

基于 Windows Mobile 的 Pocket PC 安装程序的主要组件之一是 INF 文件。此文件描述了需要复制哪些文件以及需要为不同的目标平台创建哪些注册表项。

此 INF 文件是一个文本文件,它分成几节。每节都有一个节头,位于方括号中,它可以有几个仅与特定目标硬件类型相关的子节。

只要有子节,子节的优先级就高于父节,所以如果一个值在节及其子节中都进行了设置,则会使用子节中的值。基于这个原因,应该将共享设置放在父节中,而将特定于每个硬件配置的设置放在子节中。

请按照以下步骤创建 INF 文件:

•在 [Version] 节中,将 Provider 值设置为您公司的名称。

•在 [CEStrings] 节中,将. AppName 和 CompanyName 变量设置为应用程序名称和公司名称(不带空格)。

•在 [Strings] 节中,您可能不需要进行任何更改,但要注意不同的 CPU 类型。

•在 [DefaultInstall] 节中,列出应该调用的不同节,方法是将 CopyFiles、AddReg 和 CEShortcuts 值设置为不同的节名。如果有多个节,节名间应该以逗号分隔。

•在 [SourceDiskFiles] 节中,列出要从 [SourceDiskNames] 节复制的各个文件和相应的编号。应该将这些编号看作是组编号,而非物理磁盘编号。通常文件是按类型分组的,例如“声音文件”、“图形文件”、“数据库文件”等等,但如何分组由您决定。

•在 [DestinationDirs] 节中,为 [SourceDiskFiles] 节中的每种文件类型指定一个目标目录。请注意,有一些预定义的变量可供您使用,例如 CE1(指定的目标目录)和 CE2(WINDOWS 目录),所以指定诸如“%CE1%/Database”这样的目录将会在用户安装时选择的目录下创建一个子目录。

•为 [DefaultInstall] 节的 CopyFiles 变量中的每一项创建节(名称必须严格匹配,所以要检查再检查)。在每一节中,指定文件的名称及用于复制文件的属性。属性可以在 eMbedded Visual Tools 文档中找到。

•为 [DefaultInstall] 节的 RegSettings 变量中的每一项创建节。

•为 [DefaultInstall] 节的 Shortcuts 变量中的每一项创建节。%CE17% 预定义变量表示 /WINDOWS/Start Menu 目录。

创建 CAB 文件

Cabinet 文件是高度压缩的文件,由包括在 eMbedded Visual Tools 中的 CABWIZ 实用工具构建。

CABWIZ 实用工具具有以下形式:

CABWIZ  [/err ] /cpu  

/cpu 参数后面的每一项将创建一个文件名为 YOURAPP.CPUTYPE.CAB 的独立 CAB 文件。每个 CAB 文件只包含压缩文件和用于匹配设备类型的设置。

创建 INI 文件

客户的个人计算机并没有读取 CAB 文件的内容;它只是将适当的 CAB 文件复制到基于 Windows Mobile 的 Pocket PC 中,然后由后者读取该 CAB 文件并使用 WCELOAD.EXE 应用程序提取内容。在这台个人计算机中,有一个名为 CEAPPMGR.EXE 的实用工具,它协调设备的安装、将设备类型与每个可用的 CAB 文件类型相匹配、将 CAB 文件发送到设备,并调用基于 Windows Mobile 的 Pocket PC 设备中的 WCELOAD.EXE 应用程序。

请注意,可以指定多个 INI 文件,这样将安装多个组件。这将允许使用基于 Windows Mobile 的 Pocket PC 中的 Remove Programs(位于“System”选项卡的 Settings 下)来删除个别组件。

小结

一旦您使用 CAB 文件、SETUP.INI 文件和一个 SETUP.EXE 文件来调用 CE Application Manager,您只需将这些文件放在光盘、磁盘或 ZIP 文件中,将它们分发给您的客户。理解获取这些文件的所需步骤可能会占用您第一次安装的大量时间,但以后的安装将会很快,因为您只需更改任何前面安装的源文件中的少量值即可。

3.4. 如何创建与基于 Windows Mobile 的 Pocket PC 平台无关的 CAB 文件?

您可以创建一个 .inf 文件,用它生成适合在任何基于 Windows Mobile 的 Pocket PC 设备上安装应用程序的 CAB 文件。具体做法请参见这个示例:
http://samples.gotdotnet.com/quickstart/CompactFramework/doc/cabfile.aspx

3.5. 为什么每种处理器类型都有不同的 CAB 文件?

每个 CAB 都包含一个小型本机可执行文件,它在设备中执行框架依赖项检测。此实用工具特定于处理器/平台,每种处理器类型都必须有单独的 CAB。

3.6. 如何创建一个桌面安装程序来检测目标设备中是否存在 .NET Compact Framework,并在需要时安装它?

MSDN Library 中标题为“Creating an MSI Package that Detects and Updates the .NET Compact Framework”的文章描述了一种可能会用到的技术:
http://msdn.microsoft.com/mobility/understanding/articles/default.aspx?pull=/library/en-us/dnnetcomp/html/netcfdepl.asp

3.7. 如何将 .NET Compact Framework Service Pack 部署到模拟器中?

从以下地址下载“Developer”版本的 service pack 并安装到您的桌面开发 PC 中(下载的标题如下所示:“Microsoft® .NET Compact Framework 1.0 SPx Developer Redistributable”)
http://msdn.microsoft.com/mobility/downloads/updates/default.aspx

然后将适当的 .NET Compact Framework cab 文件复制到模拟器中(按照下一段)。在模拟器中通过 File Explorer 指向 PC 中的一个共享,然后将该 cab 复制并粘贴到模拟器文件系统中的某个位置。现在从 File Explorer 启动该 cab 文件,如果询问是否覆盖所有项,则回答“是”。

模拟器
CAB 文件

Windows Mobile 2002 for Pocket PC

netcf.core.ppc3.x86.cab

Windows Mobile 2003 for Pocket PC

netcf.core.wce4.x86.cab

Windows Mobile 2003 for Smartphone

不支持 RAM 安装

3.8. 如何将 SQL Server CE 包含在我的应用程序安装中?

要随一个应用程序安装 SQL Server CE,只需将恰当的 SQL Server CE CAB 文件作为应用程序安装的一部分加以安装。有两组与 SQL Server CE 相关的 cab。

开发人员 CAB 包括查询分析器和错误字符串。此 CAB 不应该包括在应用程序部署中。它包含在两个实际的文件中,一个用于基于 Windows Mobile 的 Pocket PC,一个用于 Windows CE 4.x 设备:

sqlce.dev.ppc3..cabsqlce.dev.wce4..cab

SQL Server CE CAB,它包括引擎、客户端代理和托管扩展,因为利用 System.Data.SqlServerCe 组件的应用程序需要客户端代理。此 CAB 也包含在两个实际的文件中,一个用于基于 Windows Mobile 的 Pocket PC,一个用于 Windows CE 4.x 设备:

sqlce.ppc3..cabsqlce.wce4..cab

访问 SQL Server 的应用程序,也就是利用 System.Data.SqlClient 组件的应用程序应该部署该“sql”CAB。此 CAB 也包含在两个实际的文件中,一个用于基于 Windows Mobile 的 Pocket PC,一个用于 Windows CE 4.x 设备:

sql.ppc3..cabsql.wce4..cab

所有这些 CAB 都包含在 Visual Studio .NET 2003 Professional Edtion 安装中。默认位置为:

/Program Files/Microsoft Visual Studio .NET 2003/CompactFrameworkSDK/v1.0.5000/Windows CE/...

3.9. 如何在启动时运行我的应用程序?

•在 /Windows/Startup 中安装应用程序的快捷方式

•在 HKLM/Init 中添加一个注册表项

•P/Invoke CeRunAppAtEvent

3.10. 如何通过桌面安装程序检测 .NET Compact Framework 的版本?

请参考文章“Creating an MSI Package that Detects and Updates the .NET Compact Framework”:
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/netcfdepl.asp

具体为:

检测 Microsoft .NET Compact Framework您需要创建一个 .dll,它可以作为自定义操作从 MSI 文件调用。

首先使用 CeRapiInitEx 连接到设备。

使用 CeFindAllFiles 搜索设备的 Windows 目录中是否存在 GAC_mscorlib_*.dll。如果存在,则设备中已经安装了某种风格的 .NET Compact Framework。

查询设备注册表并枚举 HKLM/SOFTWARE/Microsoft/.NETCompactFramework 中的值。您应该找到表示现有 .NET Compact Framework 的内部版本的注册表项。(比如 1.0.2268.00:REG_DWORD:0)。此版本是由所有 .cab 安装创建的,并包含在以后所有 ROM 安装中。最初 ROM 安装的 RTM .NET Compact Framework 缺少这一项,所以如果您没有找到它,就假定它的值为 1.0.2268.0。

有关版本号的更多信息,请参见本 FAQ 中标题为“1.26.如何确定设备中安装的 .NET Compact Framework 的版本”的项。

返回页首返回页首

4. 图形用户界面 (GUI):窗体

4.1. 如何创建全屏窗体?

 

您需要将 WindowState 属性设置为 Maximized。要创建“不可见”窗体,如同在窗体中的一个全屏图像,您还需要将 FormBorderStyle 设置为 None、关闭 ControlBox,并删除窗体中的任何菜单实例。

//C#

this.WindowState = FormWindowState.Maximized;
this.FormBorderStyle = FormBorderStyle.None;
this.ControlBox = false;this.Menu = null;

'VB

Me.WindowState = FormWindowState.Maximized
Me.FormBorderStyle = FormBorderStyle.None
Me.ControlBox = FalseMe.Menu = Nothing
4.2. 何时应该使用窗体构造函数,何时应该使用 Load 函数?

对于任何涉及 UI 的窗体,最好使用窗体的 load 函数。在构造函数中加载和创建数据和控件的实例通常是安全的。然而,任何涉及 UI 元素的控件或窗体的初始化都应该在 load 函数中完成。例如,在构造函数中创建控件的实例并添加到窗体中是安全的,但控件位置的设置就应该在 load 函数中完成。

4.3.如何将智能最小化按钮替换为关闭按钮?

将窗口风格转换为关闭而非智能最小化可以通过 IDE 中的设计器属性来完成,或者以编程方式完成。(x) 按钮将应用程序智能最小化,而 (ok) 按钮则将其关闭。

通过设计器转换窗口风格的方法是:在 Visual Studio IDE 中,打开窗体设计器,查看 Properties。右键单击窗体并选择 Properties。在 Window Style 节中,将 MinimizeBox 设置为 False

在代码中转换窗口风格的方法是:只需将以下的代码行添加到窗体的 load 函数中:

//C#

this.MinimizeBox = false;

'VB

Me.MinimizeBox = False
4.4. 如何创建适用于 .NET Compact Framework 的 Multiple Form Application Framework?

这篇文章讨论了如何为您的基于 .NET Compact Framework 的应用程序创建有效的用户界面引擎:
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/netcfuiframework.asp

4.5. 如何提高基于 .NET Compact Framework 的应用程序窗体加载性能?

了解如何通过这些简单的优化技术降低 .NET Compact Framework Windows 窗体应用程序加载所需要的时间:
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/netcfimproveformloadperf.asp

4.6. 如何在运行时修改窗体风格?

这个快速入门描述了一些代码语句,它们用于更改基于 Windows Mobile 的 Pocket PC 应用程序中的窗体的外观和行为:
http://samples.gotdotnet.com/quickstart/CompactFramework/doc/ppcformproperties.aspx

4.7. 如何滚动窗体内容?

这个快速入门介绍了如何使用水平和垂直滚动条控件来滚动和下拉窗体中的图像:
http://samples.gotdotnet.com/quickstart/CompactFramework/doc/scrolling.aspx

4.8. 如何生成浮动窗体?它看起来像是窗体始终全屏显示。

具有边框的顶级窗体始终全屏显示,不能移动和调整大小。无边框窗体或子窗体可以移动和调整大小。

使用:Form.BorderStyle = BorderStyle.None;

4.9.如何强制一个窗体保持最小化?

请参阅本 FAQ 中的主题“6.6.如何强制一个窗体保持最小化?”。

4.10. 我有一个含有许多控件的智能设备窗体。为什么会在运行时得到“NotSupportedException”?

如果您有一个含有许多控件的窗体,当您运行应用程序时可能会得到 NotSupportedException。如果您在调试器下运行,则可能会发现异常是由调用窗体构造函数中的 InitializeComponent() 引发的。您最可能遇到的一个事实是 Compact Framework CLR 硬性限制每个方法只有 64KB JITed 代码。这意味着当 CLR 将 IL 转换为方法(在本例中为 InitializeComponent 方法)时,产生的本机代码必须少于 64KB。如果产生的本机代码大于此值,则会引发 NotSupportedException。也可能出现的情况是,当在调试器下运行(例如通过 F5)时会看到异常,但不带调试器运行(通过 Ctrl-F5)时不会有异常。当 JITed 代码的大小非常接近于 64KB 限制时就会出现这种情况,因为调试器在运行时需要生成其他一些代码。

也可能出现的情况是,在设备中会产生这种异常,但在模拟器中不会(或反之),因为处理器家族之间 JITed 代码的大小有所不同(例如,许多基于 Windows Mobile 的 Pocket PC 设备使用 ARM 指令,而模拟器使用 x86 指令)。

超出此限制之前,窗体中可含有的控件数并没有一个固定的值。这是因为设计器生成的代码量因控件而异。例如,Button 控件通常生成的代码少于 TabControl 生成的代码,这取决于控件属性的设置方式。如果您通过属性网格中的生成器为控件填充集合,则拥有集合的控件(比如 ListBox 或 TreeView 控件)会生成大量代码。另外,本地化窗体(其 Localizable 属性设置为 True)中控件生成的代码会比非本地化窗体多,因为 InitializeComponent 中生成的代码会根据来自资源文件的值设置属性,而不是使用硬编码的值。

如果您碰到这种问题,有几种不同的技术可以使用:

•将一个窗体分割成多个窗体。将大量控件放在一个窗体中对窗体加载和应用程序启动时间也有不利的影响。如果可能,要将 UI 分在两个或更多的窗体中。

•不要通过设计时生成器填充大的内部控件集合。例如,如果您在 TreeView 控件的 Nodes 集合中添加许多节点,就会在 InitializeComponent 方法中额外添加大量代码。如果可能,应该移动这些代码,使集合填充到构造函数或 Form.Load 事件处理程序中。这种技术的缺点是集合将无法很容易地通过设计器编辑,但有助于调整生成代码的大小。

•不要将自己的代码添加到 InitializeComponent 方法中。这通常是一个很好的指导原则,因为在这个方法中修改或添加由设计器生成的代码是不受支持的。这样做也会导致设计器中出现意外行为。如果您要将自己的自定义启动代码添加到窗体中,就应该将它放在构造函数或 Form.Load 事件处理程序中。

•在运行时以编程方式初始化类似的控件。例如,如果您创建了 12 个 Button 控件,它们只有 Text 和 Position 属性不同,则您可以考虑通过一个循环来创建和初始化,而不是让这 12 个控件都在设计器生成的代码中创建和初始化。另外,如果您自己编写代码实现,不要将代码放在 InitializeComponent 中。

修改 InitializeComponent 的一个令人遗憾的负面影响是:在 InitializeComponent 外的代码中实例化的任何控件都无法使用窗体设计器编辑。另外,如果您手动编辑 InitializeComponent 中的代码,则会发现设计器可能无法正确解释您修改过的代码,从而不再呈现窗体。基于这些原因,最好选择上面列出的不修改 InitializeComponent 的解决办法。

4.11. 哪种关闭窗体的方法更合适:Application.Exit 还是 Form.Close?

Application.Exit 是一种强行退出方式,就像 Win32 的 PostQuitMessage()。它意味着放弃所有消息泵,展开调用堆栈,并将执行返回给系统。

在 Windows(Win32 或 .NET)中关闭应用程序的正确方式是关闭它的主应用程序窗口(例如 Form.Close)。主消息泵结束后依然存在的任何窗口都需要手动关闭。在应用程序退出之前通过调用 Form.Close 或 Form.Dispose 来关闭窗口是清除窗口的良好做法,但这需要您有意识地去做。我们需要记住,.NET Framework 的 OnClosing() 是 Win32 的托管版本的 WM_CLOSE,而非 WM_DESTROY。

另外,如果您使用 form.Close(),通过处理 OnClosing 或 OnClosed 事件,就可以让您的应用程序清理内容、关闭文件等。如果您通过 Application.Exit 强行退出应用程序,就无法调用这些事件。

4.12. 为什么会在用于 Smartphone 的 Windows Mobile 2003 中显示一个消息框,它含有 Abort、Retry 和 Fail 组合按钮或 Yes、No、Cancel 组合按钮,或者因为默认按钮导致 NotSupportedException 而有第三种按钮?

用于 Smartphone 的 Windows Mobile 2003 只支持有 1 个或 2 个按钮的消息框。

4.13 如何获得基于 Windows Mobile 的 Pocket PC 开始菜单中最近使用过的 (MRU) 列表中的一个图标?

为您的应用程序创建一个快捷方式,放在 /windows/start menu/programs 中的某个位置。当通过这个快捷方式启动您的应用程序时,它的图标就会出现在 MRU 列表中。

4.14 如何将一个窗体放在屏幕中央?

要显示一个非全屏窗体,请确保窗体的 FormBorderStyle 属性设置为 FormBorderStyle.None。要使窗体位于中央,请将以下代码添加到窗体的 FormLoad 事件处理程序中:将 FormBorderStyle 设置为 FormBorderStyle.None,然后:

//c#

Rectangle screen = Screen.PrimaryScreen.Bounds;
this.Location = new Point((screen.Width - this.Width) / 2,  (screen.Height - this.Height ) / 2);

'VB

Dim theScreen As RectangletheScreen = Screen.PrimaryScreen.Bounds()
Me.Location = New Point((theScreen.Width - Me.Width) / 2, _  (theScreen.Height - Me.Height) / 2)
4.15 为什么我不能显示一个已经关闭了的窗体?

一旦一个窗体关闭,它就会被处置,因此可能被系统回收垃圾,所以试图显示已关闭的窗体是不安全的。一种替代的解决方案是使用 Form.Hide 和 Form.Show 来分别隐藏和显示窗体。

4.16 如何启用一个应用程序的多个实例?

.NET Compact Framework 不支持多实例。以下代码示例提供了一种解决方案,它允许当启动应用程序时(但是已有一个运行着的实例)实例化而非最大化应用程序。

注:并非所有版本的 OS(包括未来版本)都支持以下代码,也不保证在所有这些版本中都能工作。

// C#

using System.Runtime.InteropServices;
using System.Reflection;
private void Form1_Load(object sender, System.EventArgs e)
{    
    this.Text = string.Format("Form {0}", new Random().Next());
}
 
[DllImport("CoreDll")]public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("CoreDll")]public static extern int SetWindowText(IntPtr hWnd, string lpString);
protected override void OnResize(EventArgs e)
{
    Assembly asm = System.Reflection.Assembly.GetExecutingAssembly();
    IntPtr hWnd = FindWindow("#NETCF_AGL_PARK_",      asm.GetModules()[0].FullyQualifiedName);
    if (hWnd != IntPtr.Zero)
        SetWindowText(hWnd, "#42");
    base.OnResize (e);
}'
 
VB
Imports System.Runtime.InteropServices
Imports System.Reflection
Private Sub Form1_Load(ByVal sender As Object, _  ByVal e As System.EventArgs) Handles MyBase.Load
    Me.Text = String.Format("Form {0}", New Random().Next())
End Sub 'Form1_Load _Public 
Shared Function FindWindow(ByVal lpClassName As String, _  ByVal lpWindowName As String) As IntPtr
End Function _Public 
Shared Function SetWindowText(ByVal hWnd As IntPtr, _  ByVal lpString As String) As Integer
End Function
Protected Overrides Sub OnResize(ByVal e As EventArgs)
    Dim asm As [Assembly] = System.Reflection.Assembly.GetExecutingAssembly()
    Dim hWnd As IntPtr = FindWindow("#NETCF_AGL_PARK_", _
      asm.GetModules()(0).FullyQualifiedName)
    If hWnd.ToInt32() <> IntPtr.Zero.ToInt32() Then
        SetWindowText(hWnd, "#42")
    End If
    MyBase.OnResize(e)
End Sub 'OnResize

返回页首返回页首

5. 图形用户界面 (GUI):常规

5.1. 如何创建图像按钮或多行文本按钮?

创建图像按钮或多行文本按钮需要一个自定义控件。自定义控件可以用必需的自定义数据来进行按钮的绘制。有关创建自定义控件的更多信息,请参见以下链接:
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/customctrlscompactfx.asp

这个快速入门描述了如何创建图像按钮:
http://samples.gotdotnet.com/quickstart/CompactFramework/doc/picturebutton.aspx

5.2. TextBox.AcceptsReturn 如何在 .NET Compact Framework 中工作?

虽然您可以将 AcceptsReturn 设置为 false,但它始终是按 true 来操作的。如果您想用 ENTER 键来激活特定按钮,您可以从 TextBox 派生一个类,当 KeyPress 事件发生时,提供 ENTER 的事件处理代码。

5.3. 当数据加载到 ComboBox 中时,为什么没有触发 SelectedIndexChanged 事件?

这是一个已知的问题,将在 .NET Compact Framework 今后的版本中解决。

5.4. Show 和 ShowDialog 之间有什么区别?

ShowDialog 以模式方式显示窗体,这意味着它是一个模块化的函数调用,只有当窗体关闭时才返回。此方法返回一个 DialogResult 枚举类型,它指明关闭情况。

Show 是一个显示控件的非模块化函数,它会立即返回而且没有返回结果。显示控件等同于将 Visible 属性设置为 true。当调用 Show 方法后,Visible 属性会返回 true 值直到 Hide 方法被调用。

5.5. 为什么我不能创建 ContextMenu 分隔符?

这是一个已知的 bug,即当在 ContextMenu 控件中添加一个 ContextMenu 项后,将它设为分隔符就会引发 NotSupportedException。问题在于 WinCE 有一个限制,即当 ContextMenu 的父级是一个控件时,向该 ContextMenu 添加一个菜单项后就不允许将该菜单项标记(更改)为分隔符。在 Visual Studio 2003 中,设计器分割设备项目的代码与在桌面上类似,都会产生这种问题。可以这样来解决:在一个独立于 InitilizeComponent 的方法中添加 ContextMenu。

5.6. 当我在运行时向 ToolBar 分配一个 ImageList 时,为什么图像没有显示?

您可以将 ImageList 分配给 ToolBar,通常在窗体的 load 函数中进行,但要确保再次应用 ToolBar 按钮的图像索引。在本机 ToolBar 控件中,不支持在设置 ToolBar 的 ImageList 之前设置 ToolBar 按钮的图像索引。

5.7. 如何设置等待光标?

这是将光标更改为等待光标的代码:

//C#

Cursor.Current = Cursors.WaitCursor;

'VB

Cursor.Current = Cursors.WaitCursor

这是将光标重新更改为默认光标的代码:

//C#

Cursor.Current = Cursors.Default;

'VB

Cursor.Current = Cursors.Default
5.8. 如何在菜单项中显示“and”符 (&)?

.NET Compact Framework 当前不支持这种能力。使用“&&”不会在菜单项的文本中出现“and”符。

5.9. 如何创建基于 Microsoft .NET Compact Framework 的动画控件?

这篇文章将向您介绍如何构建基于 .NET Compact Framework 的动画控件:
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/animationcontrol.asp

5.10. 如何为 .NET Compact Framework 创建自定义控件?

了解如何为 .NET Compact Framework 创建控件会提高您在 .NET Framework 中创建控件的能力。这篇文章还包括一个创建自定义控件的代码示例:
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/customctrlscompactfx.asp

5.11. 如何创建基于 Microsoft .NET Compact Framework 的图像按钮?

这篇文章讨论了创建基于 .NET Compact Framework 的图像按钮的方法:
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/ImageButton.asp

5.12. 如何使用 Microsoft .NET Compact Framework MessageWindow 类?

了解如何使用 .NET Compact Framework MessageWindow 类来创建 NotifyIcon:
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/messagewindow.asp

鼠标指针单击定义为 Rectangle 结构的自定义控件时,或者当鼠标单击 Panel 控件时,这个快速入门使用 MessageWindow 来向窗体发送消息:
http://samples.gotdotnet.com/quickstart/CompactFramework/doc/messagewindow.aspx

5.13. 如何向 DataGrid 添加行和列?

这个快速入门介绍了如何在运行时向 DataGrid 控件添加或删除行和列:
http://samples.gotdotnet.com/quickstart/CompactFramework/doc/datagridadding.aspx

5.14. 如何在 DataGrid 中实现单元格编辑?

.NET Compact Framework 中的 DataGrid 控件提供了完整的 .NET Framework 中的 DataGrid 控件的几乎全部功能。.NET Compact Framework 版本的 DataGrid 的一个主要区别在于它无法在运行时在 DataGrid 中编辑单元格。这个快速入门介绍了一种以编程方式编辑单元格的方法:
http://samples.gotdotnet.com/quickstart/CompactFramework/doc/datagridediting.aspx

5.15. 如何设置 DataGrid 的 DataSource?

.NET Compact Framework 中的 DataGrid 控件提供了完整 .NET Framework 中 DataGrid 控件的几乎全部功能。.NET Compact Framework 版本的一个主要区别在于它无法将控件的 DataSource 设置为 DataSet。
http://samples.gotdotnet.com/quickstart/CompactFramework/doc/datagrid.aspx

5.16. 如何对 DataGrid 的列进行排序?

.NET Compact Framework 中的 DataGrid 控件提供了完整 .NET Framework 中 DataGrid 控件的几乎全部功能。.NET Compact Framework 版本的 DataGrid 的一个主要区别在于它无法在运行时对列排序。
http://samples.gotdotnet.com/quickstart/CompactFramework/doc/datagridsorting.aspx

5.17. 如何对 ListView 项目进行排序?

.NET Compact Framework 不支持 ListView.Sort 方法,但您仍然可以对项目排序。这个快速入门定义了 IComparable 接口的实现,可以将它用于 ArrayList.Sort 方法:
http://samples.gotdotnet.com/quickstart/CompactFramework/doc/listviewsort.aspx

5.18. 如何使用 InputPanel Component (SIP)?

这个快速入门介绍了如何启动和禁用基于 Windows Mobile 的 Pocket PC 中的软输入面板 (SIP),以及当 SIP 显示时如何调整选项卡控件的大小使之适应窗体区域的改变:
http://samples.gotdotnet.com/quickstart/CompactFramework/doc/inputpanel.aspx

多个窗体应该共享同一个 InputPanel 对象。可以这样实现:在主窗体中创建 InputPanel,再将它传递给后续窗体或向其他需要利用该 SIP 的窗体公开一些 SIP 控件方法或属性。

5.19. 如何创建自定义事件?

这个快速入门描述了如何派生 Button 类及重写方法来实现双击事件。当在 SystemInformation.DoubleClickTime 值(它是在双击有效的鼠标点击期间允许的毫秒数)的范围内点击一次后又点击一次时就会引发此自定义事件。
http://samples.gotdotnet.com/quickstart/CompactFramework/doc/btndclick.aspx

.NET Compact Framework 不支持控件(包括 Windows.Forms.Control 基类)的 OnEnter 和 OnLeave 方法。然而,因为支持 Control.OnMouseMove 方法,所以您可以使用它和 Control.Capture 属性来确定鼠标进入或离开控件的时间。
http://samples.gotdotnet.com/quickstart/CompactFramework/doc/enterleave.aspx

5.20. 如何创建所有者描述的列表框?

您可以使用 .NET Compact Framework 来创建所有者描述的列表框。.NET Compact Framework 不支持列表框和其他控件的 DrawMode、DrawItem 及其他绘制成员,但您可以编程实现该功能。这个快速入门提供了一个自定义控件类来创建所有者描述的列表框,并将控件实现为列表框来选择字体。
http://samples.gotdotnet.com/quickstart/CompactFramework/doc/ownerdrawnlistbox.aspx

5.21. 如何创建 true/false 复选框?

这个快速入门扩展了 Windows.Forms.CheckBox 控件的功能,从而可以创建 True/False 复选框:
http://samples.gotdotnet.com/quickstart/CompactFramework/doc/tfcheckbox.aspx

5.22. 当我设置 InputPanel.Enabled = true 时,为什么会产生异常?

InputPanel 组件要求 MainMenu 控件位于窗体中,并且要求窗体在屏幕上可见。

5.23. 为什么我的自定义控件不会自动继承其父级的字体?

.NET Compact Framework 中不支持这种行为。

5.24. 当我手动键入新文本时,为什么 NumericUpDown 和 DomainUpDown 控件不会激发它们的 ValueChanged 和 SelectedItemChanged 事件?

只有当用户在代码中更改控件的值时才会激发 ValueChanged 和 SelectedItemChanged 事件,或者通过向上/向下箭头的方式激发。用户在控件中输入文本时不会激发这些事件。

5.25. 为什么 NumericUpDown 控件增加的值不是设置的增加值?

当按下向上或向下箭头之后,如果下一个值不是增量的倍数,则它会在这个方向上继续往前(向上或向下),直到发现增量的下一个倍数为止。

5.26. 为什么我无法将 StatusBar 控件放在窗体的任何位置?它好像总要跑到底部?

StatusBar 控件始终停靠在窗体的底部。它的大小不能更改。

5.27. 为什么我的自定义控件不会自动继承其父级的背景颜色?

.NET Compact Framework 中不支持这种行为。解决办法是重写 OnParentChanged 方法并手动设置颜色:

//C#

protected override void OnParentChanged(EventArgs e)
{
  base.OnParentChanged(e);
  this.BackColor = Parent.BackColor;
}

'VB

Protected Overrides Sub OnParentChanged(ByVal e As EventArgs)
  MyBase.OnParentChanged(e)
  Me.BackColor = Parent.BackColor
End Sub 'OnParentChanged
5.28. 为什么 NumericUpDown 控件虽然能够接受小数值,但好像不能使用任何大于 2^16 的数值?

虽然数值形式的 NumericUpDown 控件接受小数值,但 .NET Compact Framework 将此控件的值视为整数。例如,指定值 10.23,则控件会将它计算为 10。另外,当此控件在基于 Windows Mobile 的 Pocket PC 上实现时,它不接受大于 16 位有符号整数的值。

5.29. 为什么我不能在 DomainUpDown 控件中键入文本以及让它选择相关的项目?

DomainUpDown 控件不对键入控件的文本执行检验(不像完整的 .NET Framework)。当您键入一些新的文本并按下向上/向下箭头时,它在更改前就移到了下一项。

5.30. 为什么 OpenFileDialog 限制为“My Documents”文件夹?

OpenFileDialog 的初始目录限制为“My Documents”文件夹或其任何子文件夹。基于 Windows Mobile 的 Pocket PC 操作系统强加的这个限制是为了帮助用户将文件组织在标准目录中。

5.31. 如何能够不通过菜单激活 SIP (InputPanel)?

SIP 可以通过 P/Invoke 函数“SipShowIM”来激活,如下所示。

//C#

using System.Runtime.InteropServices;
const uint SIPF_OFF = 0x0;
const uint SIPF_ON = 0x1;
[DllImport("coredll.dll")]private extern static void SipShowIM(uint dwFlag);

'VB

Imports System.Runtime.InteropServices
Const SIPF_OFF As Integer = &H0
Const SIPF_ON As Integer = &H1
_Private Shared Function SipShowIM(ByVal dwFlag As Integer) As IntegerEnd Function
5.32. 如何向 TreeView 中的每个节点添加一个子节点?

向所有节点添加子节点是这样实现的:循环访问 TreeView 中的所有节点,并向每个节点添加新节点。

//C#

foreach (TreeNode node in treeView1.Nodes)
{
    node.Nodes.Add(new TreeNode("SubNode"));
}

'VB

Dim node As TreeNodeFor Each node In  treeView1.Nodes
    node.Nodes.Add(New TreeNode("SubNode"))
Next node
5.33. 如何确定 DataGrid 中的行或列的数目?

DataGrid 中的行数和列数可以通过数据源本身确定。例如:

//C#

DataSet ds = new DataSet();
int numRows = ds.Tables[0].Rows.Count;
int numCols = ds.Tables[0].Columns.Count;

'VB

Dim ds As New DataSet()
Dim numRows As Integer = ds.Tables(0).Rows.Count
Dim numCols As Integer = ds.Tables(0).Columns.Count

如果 DataGrid 绑定到 DataView,您还可以使用 DataView.Count。

5.34. 如何创建所有者描述的 Listbox?

请参见 .NET Compact Framework QuickStarts、Implementing Events 主题:
http://samples.gotdotnet.com/quickstart/compactframework/doc/btndclick.aspx

5.35. 如何在 .NET Compact Framework 中实现 Control.GetNextControl?

.NET Compact Framework 中的控件的 Tab 键顺序与 Form.Controls 集合中的控件的顺序直接对应。因此,可以这样实现 GetNextControl:确定指定控件的索引,并确定它在集合中的邻居。

//C#

public Control GetNextControl(Control ctl, bool forward)
{
    int curIndex = this.Controls.IndexOf(ctl);
    if (forward)
    {
        if (curIndex < this.Controls.Count)
            curIndex++;
        else
            curIndex = 0;
    }
    else
    {
        if (curIndex > 0)
            curIndex—;
        else
            curIndex = this.Controls.Count - 1;
    }
    return this.Controls[curIndex];
}

'VB

Public Function GetNextControl(ByVal ctl As Control, _  ByVal forward As Boolean) As Control
    Dim curIndex As Integer = Me.Controls.IndexOf(ctl)
    If forward Then
        If curIndex < Me.Controls.Count Then
            curIndex += 1
        Else
            curIndex = 0
        End If
    Else
        If curIndex > 0 Then
            curIndex –= 1
        Else
            curIndex = Me.Controls.Count – 1
        End If
    End If
    Return Me.Controls(curIndex)
End Function 'GetNextControl
5.36. 当用户单击树视图节点时,如何才能得到通知?

TreeView 不支持 Click 事件,不过有一个解决办法,那就是使用 AfterSelect 事件来代替。

5.37. 如何设置全屏多行编辑控件窗口的标题?

这在当前版本的 .NET Compact Framework 中不支持。

5.38. 当我将 ComboBox.SelectedValue 设置为 validItemInCollection 时,为什么不能看到选定的有效项?

只有当控件被数据绑定时,设置 SelectedValue 属性才有效。

5.39. 如何检测发生“tap & hold”的位置,以便在自定义控件中生成上下文菜单?

处理 ContextMenu.Popup 事件,然后使用“Control.MousePosition”查询当前鼠标坐标。

5.40. 为什么滚动条的值永远不会被设置为最大值?

与 NumericUpDown 控件类似,可达的最大值是缩略图上面的第一个空行。更具体地说,根据编辑器属性,它等于:

Maximum - (LargeChange + 1)。
5.41. 如何通过 Tab 键从自定义控件回到前一个控件?

当检测到 Keys.Up 键时,在 KeyDown 事件处理程序中调用 this.Parent.Controls(this.Parent.GetChildIndex(customcontrol) - 1).Focus()。

5.42. 如何添加具有透明度的工具栏按钮?

图标支持透明,不过在 Visual Studio .NET 2003 设计器中有一个已知的 bug,它会创建不正确的代码并使得图标不透明。一种解决办法是在 InitializeComponent 外面的 ImageList 中添加一个图标文件,并将图标文件作为内容或嵌入式资源添加到项目中。以下代码演示了这种做法:

//C#

using System.Drawing;
using System.IO;
using System.Reflection;// Loaded as content example
private void Form1_Load(object sender, System.EventArgs e)
{
    this.imageList1.Images.Add(new Icon(File.Open("fullFileName.ico",
      FileMode.Open)));
    this.toolBar1.Buttons[0].ImageIndex = 0;
}// Loaded as a resource example
private void Form1_Load(object sender, System.EventArgs e)
{
    this.imageList1.Images.Add(new
      Icon(Assembly.GetExecutingAssembly().GetManifestResourceStream(
      ".filename.ico")));
    this.toolBar1.Buttons[0].ImageIndex = 0;
}

'VB

Imports System.Drawing
Imports System.IO
Imports System.Reflection' Loaded as content example
Private Sub Form1_Load1(ByVal sender As Object, ByVal e As System.EventArgs)
    Me.imageList1.Images.Add(New Icon(File.Open("fullFileName.ico", _
      FileMode.Open)))
    Me.toolBar1.Buttons(0).ImageIndex = 0
End Sub 'Form1_Load1
' Loaded as a resource example
Private Sub Form1_Load2(ByVal sender As Object, ByVal e As System.EventArgs)
    Me.imageList1.Images.Add(New _
      Icon([Assembly].GetExecutingAssembly().GetManifestResourceStream( _
      ".filename.ico")))
    Me.toolBar1.Buttons(0).ImageIndex = 0
End Sub 'Form1_Load2
5.43. 如何允许在 ListView 控件中有多重选择?

将 ListView 控件的 CheckBoxes 属性设置为 True,这样可以在列表中的每一项旁边显示一个 CheckBox,从而允许用户选择多个项。

也可以使用 P/Invoke 来设置 ListView 的功能,以便接受多重选择。有关这一点的示例,请参见本 FAQ 中标题为“6.24.如何允许一个控件接受多重选择?”的项。

返回页首返回页首

6. 互操作性和本机代码

6.1. 如何调用位于本机 DLL 中的函数?

本机 DLL 函数可以通过平台调用 (P/Invoke) 来调用。这些文章将提供有关这种技术的说明和更多信息:

•了解如何使用 .NET Compact Framework 的平台调用 (P/Invoke) 功能:
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/netcfintrointerp.asp

•探讨 .NET Compact Framework 中的高级互操作性。
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/netcfadvinterop.asp

•学习如何创建可通过平台调用在智能设备应用程序中使用的非托管函数。
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/unmanagedfuncs.asp

•了解如何使用 .NET Compact Framework 在托管和非托管代码之间封送数据。
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/netcfmarshallingtypes.asp

•了解如何使用 dumpbin.exe 作为在基于 Microsoft .NET Compact Framework 的应用程序中声明 P/Invoke 的手段。
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/netcfdumpbinpinvoke.asp

6.2. 如何将 dumpbin.exe 作为声明 P/Invoke 的手段?

请参见本 FAQ 中的主题“6.1.如何调用位于本机 DLL 中的函数?”。

6.3. 如何编写基于 Microsoft .NET Compact Framework 的应用程序的非托管函数?

请参见本 FAQ 中的主题“6.1.如何调用位于本机 DLL 中的函数?”。

6.4. 如何进行 P/Invoke GetTickCount?

不需要 P/Invoke GetTickCount 函数,原因是 Environment.TickCount 就可以实现。有关更多信息,请参见本 FAQ 中的主题“7.2.如何计算准确的时间间隔?”。

6.5. 如何确定一个设备有多少可用内存?

可以 P/Invoke GetSystemMemoryDivision 和 GlobalMemorySystem 函数来确定内存如何在程序和存储中划分与分配。

可以在 API 引用文档中找到参数定义。

//C#

using System.Runtime.InteropServices;
public class MEMORYSTATUS
{
  public uint dwLength;
  public uint dwMemoryLoad;
  public uint dwTotalPhys;
  public uint dwAvailPhys;
  public uint dwTotalPageFile;
  public uint dwAvailPageFile;
  public uint dwTotalVirtual;
  public uint dwAvailVirtual;
}
[DllImport("CoreDll.dll")]public static extern void GlobalMemoryStatus(  MEMORYSTATUS lpBuffer);
[DllImport("CoreDll.dll")]public static extern int GetSystemMemoryDivision(  ref uint lpdwStorePages,  ref uint lpdwRamPages,  ref uint lpdwPageSize);
public void Test()
{
  uint storePages = 0;
  uint ramPages = 0;
  uint pageSize = 0;
  int res = GetSystemMemoryDivision(ref storePages, ref ramPages, ref pageSize);
  MEMORYSTATUS memStatus = new MEMORYSTATUS();
  GlobalMemoryStatus(memStatus);
}

'VB

Imports System.Runtime.InteropServices
Public Structure MEMORYSTATUS  
Public dwLength As UInt32  
Public dwMemoryLoad As UInt32  
Public dwTotalPhys As UInt32  
Public dwAvailPhys As UInt32  
Public dwTotalPageFile As UInt32  
Public dwAvailPageFile As UInt32  
Public dwTotalVirtual As UInt32  
Public dwAvailVirtual As UInt32
End Structure 'MEMORYSTATUS 
_Private Shared Sub GlobalMemoryStatus(ByRef ms As MEMORYSTATUS)
End Sub 
_Public Shared Function GetSystemMemoryDivision( _  ByRef lpdwStorePages As UInt32, _  ByRef lpdwRamPages As UInt32, _  ByRef lpdwPageSize As UInt32) As Integer
End Function
Public Shared Sub Test()
  Dim storePages As UInt32
  Dim ramPages As UInt32
  Dim pageSize As UInt32
  Dim res As Integer = GetSystemMemoryDivision(storePages, ramPages, pageSize)
  Dim memStatus As New MEMORYSTATUS
  GlobalMemoryStatus(memStatus)
End Sub 'Test
6.6. 如何强制一个窗体保持最小化?

1.重写窗体的 OnGotFocus 方法。

2.查找窗体的窗口。

3.调用 ShowWindow(hwnd, SW_MINIMIZE) 来强制窗体最小化。

//C#

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);
}

'VB

Imports System.Runtime.InteropServices 
_Public Shared Function FindWindow(ByVal className As String, _  ByVal WindowsName As String) As IntPtr
End Function 
_Public Shared Function ShowWindow(ByVal hwnd As IntPtr, _  ByVal nCmdShow As Integer) As Boolean
End Function
Private Const SW_MINIMIZE As Integer = 6
Protected Overrides Sub OnGotFocus(ByVal e As EventArgs)
  Dim hwnd As IntPtr = FindWindow(Nothing, Me.Text)
  ShowWindow(hwnd, SW_MINIMIZE)
  MyBase.OnGotFocus(e)
End Sub 'OnGotFocus
6.7. 如何在 .NET Compact Framework 中,在平台调用 (P/Invoke) 期间封送处理类型?

请参见本 FAQ 中的主题“6.1.如何调用位于本机 DLL 中的函数?”。

6.8. 如何获得一个控件或窗体的句柄 (HWND)?

实际上有几种使用 P/Invoke 的方法可以访问控件的 HWND 句柄。下面显示了其中两种方法,一种使用 GetCapture,另一种使用 FindWindow。

//C#

[DllImport("coredll.dll"]public static extern IntPtr GetCapture();
[DllImport("coredll.dll")]public static extern IntPtr FindWindow(String lpClassName, String lpWindowName);
this.Text = "FindMe";
IntPtr hwnd1 = FindWindow(null, "FindMe");
this.Capture = true;
IntPtr hwnd2 = GetCapture();
this.Capture = false;

'VB

_Public Shared Function GetCapture() As IntPtr
End Function 
_Public Shared Function FindWindow(ByVal lpClassName As String, _  ByVal lpWindowName As String) As IntPtr
End Function
Me.Text = "FindMe"
Dim deskWin As IntPtr = FindWindow(Nothing, "FindMe")
Me.Capture = True
Dim hwnd As IntPtr = GetCapture()
Me.Capture = False
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值