65.9K
CodeProject 正在变化。 阅读更多。
Home

Windows Mobile 上的 iPhone 式数据库 GUI

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2010年5月21日

CPOL

6分钟阅读

viewsIcon

36383

downloadIcon

277

从 sdf 文件中的本地移动数据库下载数据。在 Windows Mobile 上创建类似 iPhone 的 GUI 以显示数据。创建搜索表数据的功能。通过添加圆形按钮、振动、玻璃效果等炫酷功能来美化应用程序。了解如何快速检测当前分辨率。

摘要

本文将展示如何

  • 从 sdf 文件中的本地移动数据库下载数据。
  • 在 Windows Mobile 上创建类似 iPhone 的 GUI 以显示数据。
  • 创建搜索表数据的功能。
  • 通过添加圆形按钮、振动、玻璃效果等炫酷功能来美化应用程序。
  • 快速检测当前分辨率。

最后,本文讨论了如何在移动设备上显示大量数据。

您将需要什么

  • Microsoft Visual Studio 2005/2008
  • Windows Mobile SDK(可从 Microsoft 网站免费下载)
  • Bee Mobile iPack - 包含 19 个紧凑框架控件的包(此处下载试用版)。

您将获得

Database Search GUI Database Seach GUI

您可以从本页顶部或 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}Grey1 开始,到 RGB 颜色:{183, 191, 197}Grey2 结束

您会注意到 Visual Studio 如何在设计时自动显示行的设计。另一张图像显示了我们设置的一些属性

Visual Studio designer - row styles TouchList properties

如果光标半径设置为大于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

如您所见,目前还没有任何代码从数据库中读取数据。这是因为实际的数据加载发生在 TouchListGatheringItem 事件处理程序中。每当 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
© . All rights reserved.