初学者创建第一个桌面应用程序的技巧






3.24/5 (22投票s)
一篇面向初学者的文章,
引言
首先,本文档完全面向初学者。因此,对于中级和高级程序员没有特别之处。
本文档演示了如何在 .NET 应用程序中设计窗体,对控件应用适当的验证(字段级别和窗体级别),并使用一些函数执行数据库操作。
这些是 .NET 初学者经常遇到的问题的一些技巧。其中一些技巧是我的,有些是我从不同来源获得的。我的目标不是声称拥有这些技巧的所有权,而是作为一个新手,我遇到了这些问题,不得不进行大量的谷歌搜索。所以,为了帮助我的同行程序员,我将它们整理在一起。
背景
我在 .NET 领域有 2.5 年的经验。我的主要职责是在开发桌面应用程序期间指导(或处理)我的下属和新程序员。在此过程中,我发现许多新手会犯一些常见的错误,例如为每个控件编写单独的验证代码,在每个窗体甚至每个过程中创建数据库连接对象(Connection
, DataSet
, DataAdapter
等),随意放置控件等。所以我想与公司外的新手分享这些知识。
Content
本文档包含以下三个主要问题
窗体级验证函数
对于所有类型的验证,我创建一个模块(mdcheking
),其中包含一些 public
变量和函数。首先,我们声明一些 public
变量如下
Public msgboxTitle As String = "My Application Title"
Public MessageBoxMessage As String = "Can not leave mandatory field as blank"
变量 msgboxTitle
保存应用程序的标题,它显示在消息框的标题栏中。变量 MessageBoxMessage
保存我们要提示用户的信息。它包含一个固定字符串,提示用户填写或选择必填字段。
现在我们逐一讨论其他函数(或过程)。这个函数非常简单,但对初学者非常有益。
Public Sub Prompt(ByVal MessageBoxMessage As String, _
Optional ByVal MessageBoxTitle As String = Nothing)
If MessageBoxTitle = Nothing Then
MsgBox(MessageBoxMessage, MsgBoxStyle.Information, msgboxTitle)
Else
MsgBox(MessageBoxMessage, MsgBoxStyle.Information, MessageBoxTitle)
End If
End Sub
上面的函数接受两个参数。第一个参数 MessageBoxMessage
包含我们要显示给用户的信息。第二个参数 MessageBoxTitle
是可选的。在某些情况下,我们想在消息框中显示一个不同的标题,而不是应用程序的标题。所以,在这种情况下,我们为第二个参数提供一些值,否则在调用此方法时无需传递第二个参数。
Public Function IsBlankTextBox(ByRef st As TextBox, _
Optional ByVal PromptMessage As String = Nothing,_
Optional ByVal MessageBoxTitle As String = Nothing) As Boolean
If st.Text.Trim = "" Then
If PromptMessage = Nothing Then
If MessageBoxTitle = Nothing Then
Prompt(MessageBoxMessage)
Else
Prompt(MessageBoxMessage, MessageBoxTitle)
End If
Else
If MessageBoxTitle = Nothing Then
Prompt(PromptMessage)
Else
Prompt(PromptMessage, MessageBoxTitle)
End If
End If
st.Focus()
Return True
Else
Return False
End If
End Function
在上面的函数中,我们检查提供的 TextBox
的 Text
属性是否为空?如果为空,它会提示用户并将焦点设置到相应的字段,并返回 True
,否则返回 False
。它接受三个参数。在第一个参数 st
中,我们以 Byref
的方式提供一个 TextBox
。第二个和第三个参数是可选的。如果提供了最后两个参数,则在消息框中显示提供的消息和标题,否则显示我们的应用程序标题和我们在模块声明部分已声明的消息。
Public Function IsBlankComboBox(ByVal st As ComboBox, _
Optional ByVal PromptMessage As String = Nothing,_
Optional ByVal MessageBoxTitle As String = Nothing) As Boolean
If st.Text.Trim = "" Then
If PromptMessage = Nothing Then
If MessageBoxTitle = Nothing Then
Prompt(MessageBoxMessage)
Else
Prompt(MessageBoxMessage, MessageBoxTitle)
End If
Else
If MessageBoxTitle = Nothing Then
Prompt(PromptMessage)
Else
Prompt(PromptMessage, MessageBoxTitle)
End If
End If
st.Focus()
Return True
Else
Return False
End If
End Function
在上面的函数中,我们检查提供的 ComboBox
的 Text
属性是否为空?如果为空,它会提示用户并将焦点设置到相应的字段,并返回 True
,否则返回 False
。它接受三个参数。在第一个参数 st
中,我们以 Byref
的方式提供一个 ComboBox
。第二个和第三个参数是可选的。如果提供了最后两个参数,则在消息框中显示提供的消息和标题,否则显示我们在模块声明部分已声明的应用程序标题和消息。
Public Sub CheckPressedKeyForAlphabates_
(ByVal key As System.Windows.Forms.KeyPressEventArgs)
If Not (Char.IsControl(key.KeyChar) Or _
Char.IsLetter(key.KeyChar) Or Char.IsWhiteSpace(key.KeyChar) _
Or key.KeyChar = "." Or key.KeyChar = "&") Then
key.Handled = True
End If
End Sub
在上面的函数中,我们只传递一个键,该键被检查是否与任何字母(或任何控件键、空格、小数点或“&”符号)相关,如果是则允许,否则拒绝。此过程不允许任何不在上述指定范围内的其他字符。此过程通常用于 TextBox
的 Keypress
事件。
Public Sub CheckPressedKeyForNumericWithoutDot_
(ByVal key As System.Windows.Forms.KeyPressEventArgs)
If Not (Char.IsControl(key.KeyChar) Or Char.IsNumber(key.KeyChar)) Then
key.Handled = True
End If
End Sub
在上面的函数中,我们只传递一个键,该键被检查是否与任何数字(或任何控件键)相关,如果是则允许,否则拒绝。此过程不允许任何不在上述指定范围内的其他字符。此过程通常用于 TextBox
的 Keypress
事件。
Public Sub CheckPressedKeyForNumericWithDot_
(ByVal key As System.Windows.Forms.KeyPressEventArgs, ByVal str As String)
If str.Contains(".") Then
CheckPressedKeyForNumericWithoutDot(key)
Else
If Not (Char.IsControl(key.KeyChar) Or _
Char.IsNumber(key.KeyChar) Or key.KeyChar = ".") Then
key.Handled = True
End If
End If
End Sub
上面的函数与 CheckPressedKeyForNumericWithoutDot
相同,只是有一个区别。它只允许单个小数点符号。第二个参数包含原始字符串,首先检查它是否包含任何小数点符号?如果包含任何小数点符号,则将 Key 传递给 CheckPressedKeyForNumericWithoutDot
,它只允许数字值;如果第二个参数不包含任何小数点符号,则它允许带小数点的数字值。
Public Sub CheckPhoneNo(ByVal key As System.Windows.Forms.KeyPressEventArgs)
If Not (Char.IsControl(key.KeyChar) Or Char.IsNumber(key.KeyChar) _
Or key.KeyChar = "-" _
Or key.KeyChar = ",") Then
key.Handled = True
End If
End Sub
上面函数的目的是只允许输入电话号码字符。它允许任何数字、逗号 (,) 和连字符 (-)。如果提供的键属于这些字符,则允许,否则拒绝。
Public Function imageToByteArray(ByVal ImageIn As System.Drawing.Image) As Byte()
Dim ms As MemoryStream = New MemoryStream()
Dim FormatImage1 As Imaging.ImageFormat = ImageIn.RawFormat
ImageIn.Save(ms, FormatImage1)
Return ms.ToArray()
End Function
在初学阶段,每个人在想将图像保存到数据库时都会遇到困难(我本人也遇到过这个问题)。所以,我想说首先将图像转换为字节数组,然后将该字节数组存储在数据库中。上面的函数将图像转换为字节数组。
Public Function ByteArrayToimage(ByVal ImageArray As Byte()) As Image
Dim ms As MemoryStream = New MemoryStream(ImageArray)
Dim ReturnImage As Image = Image.FromStream(ms)
Return ReturnImage
End Function
当我们从数据库检索图像数据时,它是原始格式(字节)。只需将此字节数组转换为图像即可使用。上面的函数将字节数组转换为图像。
数据库相关函数
初学者还会犯一些常见的错误。他们会在每个窗体(有时甚至在每个过程中)创建数据库相关的对象(如连接、数据适配器、连接字符串等)。所以在这里我想说明,没有必要在每个窗体上使用数据库相关的对象(和命名空间)。我们可以在类(或模块,我倾向于类)中创建这个对象(以及一些访问数据库的函数)。对于本文档,我使用的是 MSAccess 数据库。因为在初始阶段,每个人都倾向于使用这个简单的数据库。
在类的声明部分,我们创建一些常用的数据库相关变量,如连接对象、连接字符串等。
Private ConnString As String = "Provider=Microsoft.jet.oledb.4.0;_
data source=" & mdChecking.DatabasePath
Private con As OleDbConnection
Private com As OleDbCommand
Private da As OleDbDataAdapter
ConnString
包含数据库提供者和数据源信息。我认为不需要描述所有其他变量,因为你可以从它们的数据类型中轻松猜测出它们的作用。
Public Function ReturnSingleValue(ByVal MyQuery As String) As Object
Try
con = New OleDbConnection(ConnString)
com = New OleDbCommand(MyQuery, con)
con.Open()
Dim result As Object = com.ExecuteScalar
con.Close()
If IsDBNull(result) Then
Return Nothing
End If
Return result
Catch ex As Exception
mdChecking.Prompt(ex.Message.ToString)
If con.State = ConnectionState.Open Then
con.Close()
End If
End Try
Return Nothing
End Function
当我们只需要从数据库表中获取单个值时,我们就使用上面的函数。
Public Function InsertDeleteUpdate(ByVal MyQuery As String) As Long
Try
con = New OleDbConnection(ConnString)
com = New OleDbCommand(MyQuery, con)
con.Open()
Dim RowsAffected As Long
RowsAffected = com.ExecuteNonQuery()
con.Close()
Return RowsAffected
Catch ex As Exception
mdChecking.Prompt(ex.Message.ToString)
If con.State = ConnectionState.Open Then
con.Close()
End If
End Try
Return Nothing
End Function
当我们只需要插入记录、删除记录或更新记录时,我们就使用上面的函数。
Public Function ReturnMultipleValue(ByVal MyQuery As String) As DataSet
Dim ds As DataSet
Try
con = New OleDbConnection(ConnString)
da = New OleDbDataAdapter(MyQuery, con)
ds = New DataSet
con.Open()
da.Fill(ds)
con.Close()
Return ds
Catch ex As Exception
mdChecking.Prompt(ex.Message.ToString)
If con.State = ConnectionState.Open Then
con.Close()
End If
End Try
Return ds
End Function
当我们想要获取多条记录时,我们就使用上面的函数。在上面的函数中,我将记录填充到 Dataset
表中,但是你也可以直接将记录填充到 DataTable
中。
Public Sub ExecuteCommandQuery(ByVal comm As SqlCommand)
Try
con = New SqlConnection(ConnString)
comm.Connection = con
con.Open()
comm.ExecuteNonQuery()
con.Close()
Catch ex As Exception
mdChecking.Prompt(ex.Message.ToString)
If con.State = ConnectionState.Open Then
con.Close()
End If
End Try
End Sub
当我们需要插入、删除或更新记录时,也使用上面的函数。此函数专门用于将图像插入数据库。
用户界面相关技巧
在设计桌面应用程序界面时,也会出现一些问题。我一一指出
- 整个应用程序的字体名称和大小应保持标准。
- 如果你使用菜单栏,则必须有一个窗口菜单。
- 在菜单中使用分隔符对相关字段进行分组。
- 为错误消息、标签和窗体标题使用有意义的标题文本。
- 为每个控件和窗体使用有意义的名称(而不是像
button1
、Textbox1
、form1
等)。 - 为控件和窗体使用前缀(如
Label
的lbl
,TextBox
的txt
,ComboBox
的cmb
,Form
的frm
等)。 - 当任何任务耗时过长时,使用进度条。
- 绝对不要有拼写错误。
- 为必填字段放置红色星号(或错误提供者)。
- 有时两个词由于拼写稍有不同而具有不同的含义。确保你使用了正确的词(例如,Principle 和 Principal,Labor 和 Labour 等)。
- 如果你为国际客户工作,日期应采用正确的格式。
- 颜色应易于眼睛且令人愉悦。除非你需要突出显示某些内容,否则不要使用花哨的颜色。
- 应为所有可能的选项定义热键。
- 检查窗体上每个控件的锚定。
- 在需要时为控件设置停靠。
- 标签顺序应正确(按顺序)。
- 字段顺序应非常相关。(例如,在
Employee
窗体中,你应该将与个人详细信息相关的字段分组,将与官方详细信息相关的字段分组)。 - 如果你使用分组框来分类字段,那么它们与窗体的左右边缘的间距应相等。
- 如果不需要最大化,则将窗体边框设置为固定单边框并禁用最大化按钮。
- 单个窗体应带有与菜单项相同的图标。
- 整个应用程序的按钮高度和宽度应保持标准。
- 如果可能,按钮位置应在整个应用程序中保持标准(例如,关闭按钮的位置在每个窗体中都应保持标准)。
Label
及其对应的控件(TextBox
、ComboBox
等)应垂直居中对齐。- 整个应用程序中标签与其对应控件之间的间隙应保持均匀。
- 如果可能,为
TextBox
设置最大长度。 ComboBox
、CheckListBox
等字段必须排序。- 如果使用了图标,它们看起来应该合理且相关,而不是吸引眼球。
- 如果你使用
Datagridview
,则列标题必须居中对齐。 - 如果你绑定
Datagridview
,则列标题应具有相关的名称(而不是数据库字段名)。 - 在
Datagridview
中,数字字段应右对齐,其余字段应左对齐。 - 如果应用程序是 MDI 应用程序,那么单个窗体的任何更改都应反映到其他相关窗体(例如,有多个窗体打开与员工相关,并且你在每个窗体中使用了
Employee
姓名及其父亲姓名相关的字段,现在如果你在主员工窗体中更改Employee
姓名或父亲姓名,那么这个更改应该反映到所有其他打开的窗体中)。
历史
- 发布日期:2009 年 1 月 4 日