DataRepeater 虚拟模式的使用

[原文作者]:John Chen

[原文链接]:Using the DataRepeater Virtual Mode

        当在论坛中回答问题的时候,我经常会遇到一个问题,虚拟模式是如何与包含了Visual Basic Power Packs的DataRepeater控件一起工作的?我看到并不是很多人在使用这个强大的功能,所以我再次讨论它是如何工作的,然后通过一个实例来使用它。

        DataRepeater有一个VirtualMode属性,它是做什么用的?

        让我从下面的DataRepeater控件的工作机制图来开始。

clip_image001

                                            图1

         当一个程序启动时,数据从数据库加载到内存中的结构化数据高速缓存(如数据集)。数据高速缓存通过数据绑定机制(如DataRepeater.DataSource = BindingSource)绑定到视图(这里的DataRepeater)。用户通过DataRepeater与数据交互。用户可以滚动视图以显示不同的数据行和修改在不同行的数据。原始数据从数据缓存取出,在视图中显示;修改后的数据又放回到数据缓存中去。只要我们设置数据绑定渠道的属性(像DataRepeater.DataSource = BindingSource),这一切都自动发生。

       使用虚拟模式意味着你不愿使用数据绑定机制,你因为各种原因而想为DataRepeater控件提供你自己的数据管理操作。例如,你可能要提供正在使用的数据,这样你就没有一个可以为DataRepeater用作一般数据源的数据缓存。

       性能是人们选择使用虚拟模式的主要原因之一,尤其是显示大量数据的时候,在DataRepeater控件中,就好像你在控制加载数据并且可以最优化加载速度和内存消耗。

        请注意,性能是一个复杂的问题,它可以被很多因素影响。使用虚拟模式并不能保证你有最佳的结果。例如,如果所有的数据行已经被加载到内存中,像充满TableAdapter.Fill方法的DataSet,你可能不会有虚拟模式的性能增益。

       源于论坛最新的关于DataRepeater虚拟模式用法的问题,接下来,我将给出一个实例来重点介绍如何使用虚拟模式。

约会薄实例

       我的例子是约会薄。它允许你创建电子日程,这个电子日程可以设置在自定义的一周范围内。这是我的新年决心,以更好的管理(开个玩笑)。

       约会薄的界面显示如下:

clip_image002

                                                 图2

        左边是一个每行7天的日历,右边在日历中一行一天地显示约会详情。约会列表页可以像下图右边所示显示成一列。

clip_image003

                                                        图3

         要导航到指定的一周,可以点击左侧面板上的星期,相关的日期就会在右侧面板依次显示出来,然后点击一个指定的日期,在TextBox里填上约会的详细描述,相关日期的颜色就会变成紫色。要删除一个约会,删除文本框中的内容。切换到约会列表视图里,可以很清楚的看到需要关注的约会。

       我用一个简单的数据集来代表日程表。我在这里假定你对DataSet类很熟悉,这个DataSet包含2个表:AppointmentBook和Appointment,如下所示:

clip_image004

                                                 图4

        表AppiontmentBook只包含一个记录用来定义日历的开始日期(必须是星期日)和日历上星期的总数。表Appointment包含约会的日期(以天
为代表从开始日期偏移)和约会的详细信息。对一个特定日期只允许一个约会。我承认这是一个过于简单的数据模型,但是它让我们把目光更多的集中在虚拟模式的使用上,更少关注程序的细节。

该软件允许你创建一个新的约会薄或打开已有的一个。经过应用程序的设置,最后一次打开的文件会被记住。

实例中的DataRepeaters

        在程序中,我用了3个DataRepeaters,都用了虚拟模式。第一个叫WeekCalendarDataRepeater,它是用来表示左边的日历(见图2)。我不会在这个DataRepeater上做任何的数据输入,数据值(字符串值12/27,12/28,etc.)是动态计算的,因此没有必要通过一个数据缓存类来缓存这些值。这是使用虚拟模式的完美例子。在这个例子中,我将说明怎样提供数据给DataRepeater.

        第二个叫DayCalendarDataRepeater,它用来在日历视图中显示和编辑约会信息(图2右手边)。我已经将DataRepeater设置成固定范围,每一行代表一个日期,因此它不会允许你添加或者删除项目(在这里即行)。我将演示如何把数据从DataRepeater取出并存进数据缓存AppointmentDataTable中。你会发现DataRepeater的项和AppointmentDataTable的行并不是一个一对一的关系。Appointment可以由更少的项。这是另一个说明使用VirtualMode比非VirtualMode更合适的好例子。

       第三个DataRepeater叫ApptListDataRepeater,用于以列表显示约会(图3,右手边)。对这一个,没有必要对AppointmentDataTable使用VirtualMode设置DataRepeater.DataSource。然而,我仍然使用VirtualMode来说明添加和删除项的应用。

DataRepeaters的详细应用

       要正确使用DataRepeater,你需要设置DataRepeater.VirtualMode为true,设置DataRepeater.ItemCount并处理以下四项活动:ItemValueNeeded,ItemValuePushed,NewItemNeeded 和ItemsRemoved。让我们用以个例子来深入到细节。

1) 要使用DataRepeater VirtualMode,首先要做的是设置DataRepeater.VirtualMode属性为true。你可以通过属性浏览器或者像如下Form_Load事件处理那样在代码里设置。我将我所有的三个DataRepeater设置成VirtualMode。(部分代码在函数中删除,以提高可读性,其他代码段也是如此。我将在最后提供完整的样本衔接。)

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _

Handles MyBase.Load

‘ Setup the Virtul Mode state for the DataRepeaters

    Me.WeekCalendarDataRepeater.VirtualMode = True

    Me.DayCalendarDataRepeater.VirtualMode = True

    Me.ApptListDataRepeater.VirtualMode = True

End Sub

2) 然后你需要告诉DataRepeater最初有多少项。在实例中,三个DataRepeater 有总周数,天数和约会数在OpenAppointmentBook函数里。

Private Sub OpenAppointmentBook()

    apptDataSet = New AppointmentDataSet()

    apptDataSet.ReadXml(dataFile)

    Dim row1 As AppointmentDataSet.AppointmentBookRow = _

    CType(apptDataSet.AppointmentBook.Rows(0), AppointmentDataSet.AppointmentBookRow)

    day0 = row1.StartDate

    totalWeeks = row1.TotalWeeks

    totalDays = totalWeeks * 7

    Me.WeekCalendarDataRepeater.ItemCount = totalWeeks

    Me.DayCalendarDataRepeater.ItemCount = totalDays

    Me.ApptListDataRepeater.ItemCount = apptDataSet.Appointment.Rows.Count

End Sub

3) 不管DataRepeaterItem说明时候需要,你都提供数据给它(例如,当滚动查看项的时候)。这通过ItemValueNeeded事件。例如,在WeekCalendarDataRepeater,我通过计算约会数和周数来为Label提供值。

Private Sub WeekCalendarDataRepeater_ItemValueNeeded(ByVal sender As Object, ByVal e As _

DataRepeaterItemValueEventArgs) Handles WeekCalendarDataRepeater.ItemValueNeeded

    Dim i As Integer = e.ItemIndex

    If (i >= 0 AndAlso i < TotalWeeks) Then

      Select Case e.Control.Name

        Case "Label1"

             e.Value = GetDate(i, 0)

        Case "Label2"

             e.Value = GetDate(i, 1)

        Case "Label3"

             e.Value = GetDate(i, 2)

        Case "Label4"

             e.Value = GetDate(i, 3)

        Case "Label5"

             e.Value = GetDate(i, 4)

        Case "Label6"

             e.Value = GetDate(i, 5)

        Case "Label7"

             e.Value = GetDate(i, 6)

        Case "WeekLabel"

             e.Value = i.ToString()

      End Select

   End If

End Sub

我没有在WeekCalendarDataRepeater中处理ItemValuePushed事件,所以它只读。

4) 当DataRepeaterItem在DataRepeater更新,你需要处理ItemValuePushed事件来保存数据。例如,在DayCalendarDataRepeater,我们收到来自DataRepeater的ApptTextBox,它存储用户刚输入的或者编辑的约会描述。我们把值存储在数据集中。

Private Sub DayCalendarDataRepeater_ItemValuePushed(ByVal sender As Object, ByVal e As _

DataRepeaterItemValueEventArgs) Handles DayCalendarDataRepeater.ItemValuePushed

    Dim i As Integer = e.ItemIndex

       If (i >= 0) Then

        Select Case e.Control.Name

          Case "ApptTextBox"

             UpdateDataSet(i, CType(e.Value, String))

       End Select

       End If

End Sub

我将WeekCalendarDataRepeater和DayCalendarDataRepeater连同AllowUserToAddItems和AllowUserToDeleteItems设置成false(见图5)所以项数是固定的,我并不需要处理NewItemNeeded和ItemsRemoved事件。

clip_image005

图5

5) 在AppListDataRepeater,我需要添加和删除约会。我使用AddButton和RemoveButton来执行添加或删除操作。点击AddButton的代码如下所示。主要的语句是ApptListDataRepeater.AddNew()。添加了错误处理代码以便如果发生什么错误它不会添加一个新行。

Private Sub ApptListDataRepeater_AddButton_Click(ByVal sender As System.Object, ByVal e As _

System.EventArgs) Handles AddButton.Click

    Dim oldCount = ApptListDataRepeater.ItemCount

    Try

      ApptListDataRepeater.AddNew()

   Catch er As Exception

     If (er.GetType.FullName <> GetType(CancleException).FullName) Then

       MessageBox.Show(er.Message)

     End If

‘ Remove the last added row

     If (ApptListDataRepeater.ItemCount > oldCount) Then

       ApptListDataRepeater.ItemCount = oldCount

       Me.TotalApptsLabel.Text = apptDataSet.Appointment.Rows.Count.ToString()

     End If

    End Try

End Sub

上面的代码将触发DataRepeater执行NewItemNeeded事件。我们如下处理:

Private Sub ApptListDataRepeater_NewItemNeeded(ByVal sender As Object, ByVal e As System.EventArgs) _

Handles ApptListDataRepeater.NewItemNeeded

‘Raise a dialog to get a date an appoint

      Dim appointmentForm As New NewAppointmentForm

      If (appointmentForm.ShowDialog(Me) = Windows.Forms.DialogResult.OK) Then

        Me.apptDataSet.Appointment.AddAppointmentRow(appointmentForm.AppointmentDate.Subtract(day0).Days, _

             appointmentForm.Description)

        RefreshDataRepeater(Me.DayCalendarDataRepeater)

        RefreshDataRepeater(Me.WeekCalendarDataRepeater)

     Else

       Throw New CancleException

     End If

End Sub

我使用一种新的形式输入日期和详细信息用以构成一个新的约会数据项。

6) 要删除一个项,你可以使用DataRepeater.RemoveAt(index)如下:

Private Sub ApptListDataRepeater_DeleteButton_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles DeleteButton.Click

       ApptListDataRepeater.RemoveAt(ApptListDataRepeater.CurrentItemIndex)

End Sub

你还可以使用删除键达到同样的效果。同时,你需要处理ItemsRemoved事件如下:

Private Sub ApptListDataRepeater_ItemsRemoved(ByVal sender As Object, ByVal e As _

DataRepeaterAddRemoveItemsEventArgs) Handles ApptListDataRepeater.ItemsRemoved

       If (e.ItemIndex >= 0 AndAlso e.ItemIndex < apptDataSet.Appointment.Rows.Count) Then

           apptDataSet.Appointment.Rows.RemoveAt(e.ItemIndex)

       End If

End Sub

7) 最后,在我的例子中,你可能会看到我有一个函数来刷新DataRepeater。

Private Sub RefreshDataRepeater(ByRef repeater As DataRepeater)

        Debug.Assert(repeater IsNot Nothing, "repeater is not set")

        repeater.BeginResetItemTemplate()

        repeater.EndResetItemTemplate()

End Sub

当你想要DataRepeater来刷新数据的时候,例如这个例子中的DataSet,你会需要这个。请注意,DataRepeater.Invalidate是用来强行控制重绘,它不会更新数据。

小结

这里是一个对DataRepeater VirtualMode使用的小结:

1) 设置 DataRepeater.VirtualMode = true

2) 设置DataRepeater.ItemCount.

3) 处理DataRepeater.ItemValueNeeded事件来发布DataRepeater

4) 如果数据变化,调用DataRepeater.BeginResetItemTemplate和EndResetItemTemplete来刷新DataRepeater

5) 处理ItemValuePushed来保存DataRepeater中的变化

6) 调用DataRepeater.AddNew来添加一个新项并处理NewItemNeeded事件以提供新的值

7) 调用DataRepeater.RemoveAt(index)来删除一个DataRepeaterItem并处理ItemsRemoved事件来从外部数据存储中删除值。

有关完整的实例代码,请在MSDN Code Gallery里check out

http://code.msdn.microsoft.com/AppintmentBook

有关DataRepeater虚拟模式的更多信息,请参照此处的MSDN文档。

《DataRepeater 虚拟模式的使用》有1个想法

发表评论