精确控制行的拖动行为

为了便于学习本节的内容,可以先打开CaseStudy目录下的文件“ListView.Table”,并参考该文件名为“示例二十二”的窗口。

ListView有个名为“BeforeDropRow”事件,在准备接收拖动过来的行之前触发,这个事件很重要,可以对拖动行为进行精确控制。

BeforeDropRow的e参数有:

Form:     返回触发事件的窗口
Sender:   返回触发事件的控件,也就是准备接收行的ListView
Source:   返回拖动过来的行原来所属的ListView,如果在同一个ListView之间拖动,那么Source就等于Sender
Add:      逻辑型,是否接收拖动过来的行,默认为True,只有在不同的ListView之间拖动时,此参数有意义。
Delete:   逻辑型,是否从原来的ListView删除拖动过来的行,默认为True,只有在不同的ListView之间拖动时,此参数有意义。
OldIndex: 拖动过来的行的原位置。
NewIndex: 新位置,将在此处接收拖动过来的行。
Cancel:   逻辑型,是否取消本次拖动,当然默认为False。

下来用们用一个例子来演示这个事件的用法,任务是设计一个下图所示的窗口:

通过这个窗口,可以以可视化的形式选择或删除活动参与者,也可以活动参与者从一个活动拖到另一个活动,单击保存按钮后,将结果保存在下表中:

设计步骤:

1、窗口的AfterLoad事件代码设置为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

Dim lvw1 As WinForm.ListView = e.Form.Controls("ListView1") '员工列表
Dim
lvw2 As WinForm.ListView = e.Form.Controls("ListView2") '活动一参与者列表
Dim
lvw3 As WinForm.ListView = e.Form.Controls("ListView3") '活动二参与者列表
Dim
lvws() As Winform.ListView = {lvw1,lvw2,lvw3} '看看我们是怎样批量设置某组控件属性的
For
Each lvw As WinForm.ListView In lvws
    lvw.View = ViewMode.
List
    lvw.AllowDrag =
True
    lvw.AllowDrop =
True
    lvw.Images.AddSmallImage("Man", "Man.ico")
'
添加代表男性的一对图标
    lvw.Images.AddSmallImage("Woman", "Woman.ico")
'
添加代表女性的一对图标
Next
For
Each dr As DataRow In DataTables("员工").Select("","性别") '列出所有员工
    Dim vr As WinForm.ListViewRow = lvw1.Rows.Add()
    vr.Text = dr(
"
姓名")
   
vr.Name = dr("姓名") '将ListViewRow的Name属性设置为员工姓名
    If dr("性别") = "男"
Then
        vr.ImageKey =
"Man"
   
Else
        vr.ImageKey =
"Woman"
    End
If

Next
Dim
nms() As String = DataTables("活动").DataRows(0)("参与者").Split(",") '列出活动一参与者
For Each
nm As String In nms
    If
nm > "" Then
        Dim
vr As WinForm.ListViewRow = lvw2.Rows.Add()
       
vr.Text = nm
       
vr.Name = nm
       
vr.ImageKey = lvw1.Rows(nm).ImageKey  '从员工列表(ListView1)获取此员工的图标键值
    End If
Next

nms
= DataTables("活动").DataRows(1)("参与者").Split(",") '列出活动二参与者
For Each
nm As String In nms
    If
nm > "" Then
        Dim
vr As WinForm.ListViewRow = lvw3.Rows.Add()
       
vr.Text = nm
       
vr.Name = nm
       
vr.ImageKey = lvw1.Rows(nm).ImageKey '从员工列表(ListView1)获取此员工的图标键值
    End If
Next

上面的代码中,我首先请你留意第4行到第11行的代码,当我们需要对一组控件进行相同的设置时,可以用这种方法减少代码量;其次留意第15行代码,此行代码将员工列表(ListView1)中的行的Name属性设置为对应员工的姓名,这样我们可以在28、37这两行代码通过员工姓名获取ListView1中这个员工对应的行,然后获取此行的ImageKey属性,并赋值给活动参与者(ListView2和ListView3)中对应行的ImageKey属性。

2、ListView2(活动一参与者)的BeforeDropRow事件代码设置为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

Dim lvw As WinForm.ListView = e.Sender
If
lvw.Rows.Count >= 3  AndAlso e.Source.Name <> lvw.Name Then '如果已经有三人,而且是从其他ListView拖动过来.
    Messagebox.show(
"
每项活动最多允许三人参与!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)
    e.Cancel = True
'
取消本次拖动
    Return

End
If
If
e.Source.Name"ListView1" '如果是从员工列表中拖过来的行
    e.Delete = False
'
不要删除原来的项目
End
If
Dim
itm As WinForm.ListViewRowe.Source.Rows(e.OldIndex) '获取要拖动过来的行
If
e.Source.Name <> e.Sender.Name Then '如果是从其他ListView中拖动过来的
    If e.Sender.Rows.Contains(itm.Name)
'
判断活动一是否已经包括此员工
        MessageBox.Show(
"
此员工已经报名参加活动一,无需重复报名!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)
       
e.Cancel = True '取消本次拖动
    End If

End
If

首先留意第7行代码,意思是如果是从员工列表拖动过来的,那么就不需要删除原来的行;这里隐藏了另一个意思: 如果是从活动二参与者拖动过来的行,那么就原来的行就删除;也就是说,从员工列表拖动员工到活动参与者,是复制的动作,而从一个活动参与者列表拖动员工到另一个活动参与者,是移动的动作;这个看似复杂的判断,就这么三行代码搞定了。
其次请留意第11行的代码是如何判断某员工已经参与此项活动的,这就是行有Name属性的好处,当然你可以遍历判断,但是要多写几行代码。

3、ListView3(活动而参与者)的BeforeDropRow事件代码和ListView2完全相同,就不重复说明了。

4、最后将ListView1(员工列表)的BeforeDropRow事件设置为:

e.Add = False

这简单的一行代码的意思是:从活动参与者拖动员工回到员工列表时,会将此员工从活动参与者列表中删除,但不会在员工列表中再增加此员工,是一种直接删除的动作。

到这里我们总结一些,这一个例子用拖动实现了三种操作:

1、复制,从员工列表拖动员工到活动参与者列表
2、删除,从活动参与者列表拖动员工回员工列表
3、移动,从一个活动参与者列表拖动员工到另一个活动参与者列表

此外还进行了一些条件判断,例如每项活动最多允许3人参加,防止重复报名等。


本页地址:http://www.foxtable.com/webhelp/topics/2828.htm