Windows Mobile 上的 iPhone 式数据库 GUI





5.00/5 (1投票)
从 sdf 文件中的本地移动数据库下载数据。在 Windows Mobile 上创建类似 iPhone 的 GUI 以显示数据。创建搜索表数据的功能。通过添加圆形按钮、振动、玻璃效果等炫酷功能来美化应用程序。了解如何快速检测当前分辨率。
摘要
本文将展示如何
- 从 sdf 文件中的本地移动数据库下载数据。
- 在 Windows Mobile 上创建类似 iPhone 的 GUI 以显示数据。
- 创建搜索表数据的功能。
- 通过添加圆形按钮、振动、玻璃效果等炫酷功能来美化应用程序。
- 快速检测当前分辨率。
最后,本文讨论了如何在移动设备上显示大量数据。
您将需要什么
- Microsoft Visual Studio 2005/2008
- Windows Mobile SDK(可从 Microsoft 网站免费下载)
- Bee Mobile iPack - 包含 19 个紧凑框架控件的包(此处下载试用版)。
您将获得
您可以从本页顶部或 Bee Mobile 网站下载完整的应用程序,包括源代码:
http://beemobile4.net/?mod=samples&productID=11.
优点
- 强大的 Visual Studio 支持,因此编码量少。
- 美观的 GUI
- 节省时间,从而降低成本
- 自动适应纵向/横向
Bee Mobile iPack
将 Bee Mobile iPack 安装到您的计算机后,您应该会在 Visual Studio 的工具箱中看到这些控件。在本文中,我们将使用这些控件:
- TouchList
- SearchBox
- TPanelVista
- TVistaButton
数据库
我们将使用 Microsoft 示例 Northwind.sdf 数据库的 Products 表。它是本页顶部下载的一部分。我们将从 Products 表中显示产品名称和指示产品是否已停产的复选框。如果用户选择一个项目,我们还会显示产品下方的英文名称。
准备 GUI 以显示数据
在一个新的 Visual Studio 智能设备项目中,我们将添加一个 TouchList
控件。将其 Dock
属性设置为“Fill
”。现在我们需要设计 TouchList 控件,即告诉它数据应该是什么样子。这个概念类似于服装设计师的工作。一旦服装设计好,裁缝就会制作服装(它们看起来都一样,因为它们是根据相同的设计定制的),然后不同的人可以穿上这些服装。所以让我们首先设计“服装”。
创建行样式
行样式对于 TouchList
而言,就像服装设计对于服装设计师一样。您可以使用 Visual Studio 设计器创建行样式。我们将创建 3 种不同的行样式——普通、交替和选中。普通将用于非选中奇数索引行,交替用于非选中偶数索引行,选中用于选中行。每个行样式中都有项目样式。项目样式进一步指定行中应显示的数据类型(例如,文本、图像等)及其位置。位置不是以绝对坐标定义的,而是定义为与行边框的距离。这样,图像可以锚定到行的边缘,如果显示方向改变,布局会自动适应变化。我们的行中将有两个文本项目样式(它们的名称是“Name”和“EnglishName”,因为它们指产品名称)和一个图像项目样式(名为“Discontinued”)。
第三种行样式将用于选定的行。TouchList 允许我们在设计时看到图形光标,以便我们可以设计光标的样子。我们将使用渐变填充,从 RGB 颜色:{168, 174, 176} 开始,到 RGB 颜色:{183, 191, 197}
结束
您会注意到 Visual Studio 如何在设计时自动显示行的设计。另一张图像显示了我们设置的一些属性
如果光标半径设置为大于0,则选择光标将具有圆角。Overscrolling是一个很好的功能,它使列表即使在文档的开头/结尾达到时也能滚动,当用户松开手指时,它会逐渐返回。我们可以将图像放入背景或选择渐变填充背景,但对于这种特定设计(简单设计),我选择将其关闭。
添加搜索框
为了让用户能够搜索数据库,我们将在表单顶部添加一个 SearchBox 控件。SearchBox 类似于 TextBox,但包含更多功能,例如美观的外观、清除按钮(用户点击时清除文本)、搜索按钮(放大镜图像,点击时触发事件)以及可以显示提示文本,如果 SearchBox 中没有文本且没有输入焦点,则会显示该提示文本。
TPanelVista 和 TVistaButtons
我们把一个 TPanelVista
放在表单的底部。TPanelVista
是其他控件的容器。它可以有一个带有圆角的渐变填充背景。让我们为渐变填充使用与 TouchList 光标相同的颜色。最后,让我们向面板添加两个 TVistaButton
。TVistaButton 是一个可以透明的按钮。它也有圆角和渐变填充背景。我们只需要指定渐变的颜色。此外,我们可以将 VibratePeriod 属性设置为设备在点击按钮时应振动的毫秒数。TVistaButton
还可以显示其表面的图标或在获得焦点时改变其外观。
用数据填充列表
在连接到数据库并加载数据之前,我们需要找出应用程序可执行文件的路径(因为包含数据库的 sdf 文件将位于同一文件夹中)。我们还将使用一个巧妙的技巧来找出显示器的分辨率(这是我们迄今为止发现的最快方法)
Imports System.IO ' make sure to import the proper namespaces
Imports System.Reflection
Public Class Form1
' Define a few data memebers:
Dim m_sPath As String ' path to the application's executable will be stored here
Dim m_Connection As SqlCeConnection ' Connection to the database.
Dim m_Reader As SqlCeDataReader ' Database reader.
Dim m_OldIndex As Integer ' Index of the last loaded row
' Current resolution (as a multpiple of 240x320)
Dim m_Resolution As New SizeF(1.0F, 1.0F)
Sub New()
Row.DefaultNormalRowStyle = 0 ' default row styles for Touch List
Row.DefaultSelectedRowStyle = 2
' where is my executable ?
m_sPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase)
' This call is required by the Windows Form Designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
m_Resolution = DetectResolution() ' detect the current resolution
m_OldIndex = -1 ' index of the last loaded row (-1 means no rows loaded yet)
End Sub
' This is how we detect the resolution
Private Function DetectResolution() As SizeF
Return New SizeF(Me.CurrentAutoScaleDimensions.Width / 96.0F, _
Me.CurrentAutoScaleDimensions.Height / 96.0F)
End Function
End Class
当表单加载时,我们将创建与数据库的连接(我们将保持打开直到表单关闭)并加载数据
Private Sub Form1_Load(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles MyBase.Load
Try
m_Connection = New SqlCeConnection("Data source=" + m_sPath +
"\\Northwind.sdf")
m_Connection.Open()
LoadItems(String.Empty)
Catch ex As SqlCeException
MessageBox.Show(ex.Message)
Me.Close()
End Try
End Sub
LoadItems
方法使用 SQL 构造查询字符串并创建数据读取器。它还会通知 TouchList
将有新数据集加载到其中。
Private Sub LoadItems(ByRef sName As String)
Dim sQuery, sCountQuery As String
If SearchBox1.Text = String.Empty Then
sQuery = "SELECT [Product ID], [Product Name],
Discontinued FROM Products ORDER BY [Product Name] ASC"
sCountQuery = "SELECT COUNT([Product Name]) FROM Products"
Else
sQuery = "SELECT [Product ID], [Product Name],
Discontinued FROM Products WHERE [Product Name] LIKE '%" +
sName + "%' ORDER BY [Product Name] ASC"
sCountQuery =
"SELECT COUNT([Product Name]) FROM Products WHERE [Product Name] LIKE '%" +
sName + "%'"
End If
Dim cmd As SqlCeCommand = New SqlCeCommand(sQuery, m_Connection)
Dim cmdCount As SqlCeCommand = New SqlCeCommand(sCountQuery, m_Connection)
TouchList1.Rows.Clear()
m_Reader = cmd.ExecuteReader()
TouchList1.AllRowsCount = CType(cmdCount.ExecuteScalar(), Integer)
ApplyRowStyles()
TouchList1.SelectedIndex = 0 ' let the first row be selected
TouchList1.JumpToTheTop() ' scrolls to the very beginning of the document
TouchList1.ForceRefresh() ' refresh the list with new data
End Sub
如您所见,目前还没有任何代码从数据库中读取数据。这是因为实际的数据加载发生在 TouchList
的 GatheringItem
事件处理程序中。每当 TouchList
需要加载另一部分数据时,就会触发此事件。TouchList
只加载它真正需要的数据,例如,如果显示 15 行,则只会从数据库中加载 15 行数据。假设您希望向用户显示的数据库表包含许多行(数千行)。不仅不需要将所有数千行下载到移动设备的内存中(由于其内存和速度限制),而且用户也不太可能希望滚动所有这些行并阅读所有这些行。用户可能正在寻找特定的行或几行。这样,您只需要向他提供一种搜索工具(在这种情况下是 SearchBox 的工作)以及一种机制,让他能够看到有多少记录与搜索查询匹配。用户可以通过滚动条滑块的大小看到这一点。这就是为什么首先计算搜索结果中的行数。
这就是 GatheringItem
事件处理程序的样子
Private Sub TouchList1_GatheringItemEvent(
ByVal sender As System.Object,
ByVal args As BeeMobile.GatheringItemEventArgs) Handles TouchList1.GatheringItemEvent
' if TouchList asks for a row which has not been loaded yet
If m_OldIndex < args.RowIndex Then
m_OldIndex = args.RowIndex
m_Reader.Read()
' if the user clicked a row then the english name has to be fetched
ElseIf args.RowItemStyle.Name = "EnglishName" Then
Dim productID As String =
TouchList1.Rows(args.RowIndex).Items(
"Name").Tag.ToString()
Dim sQuery As String =
"SELECT [English Name] FROM Products WHERE [Product ID]=" +
productID
Using cmd As SqlCeCommand = New SqlCeCommand(sQuery, m_Connection)
Using scdr As SqlCeDataReader = cmd.ExecuteReader()
scdr.Read()
Dim item As RowItemText = New RowItemText()
item.Text = CType(scdr("English Name"), String)
args.Item = item
End Using
End Using
End If
' if TouchList asks for the product name
If args.RowItemStyle.Name = "Name" Then
' then get it from the database reader
Dim item As RowItemText = New RowItemText()
item.Text = CType(m_Reader("Product Name"), String)
item.Tag = CType(m_Reader("Product ID"), Integer)
args.Item = item
' if TouchList asks for the discontinued flag
ElseIf args.RowItemStyle.Name = "Discontinued" Then
' then based on the current resolution we choose a proper image size
Dim item As RowItemImage = New RowItemImage()
If m_Resolution.Width < 2.0F Then
item.TImageList = Me.tImageListQVGA
Else
item.TImageList = Me.tImageList
End If
Dim bDiscontinued As Boolean = CType(m_Reader("Discontinued"),
Boolean)
item.ImageIndex = IIf(bDiscontinued, 1, 0)
args.Item = item
ElseIf args.RowItemStyle.GetType() Is GetType(ItemStyleRectangle) Then
Dim item As RowItemRectangle = New RowItemRectangle()
args.Item = item
End If
End Sub