« Data Binding | Index | Embedded Controls » |
The basic Drag and Drop functionality allows user to move data between two controls: drag source and drop target. Regular .NET ListView does support this basic Drag and Drop functionality, but not any additional (and often pleasant) features based on Drag and Drop.
Better ListView adds these features:
Item reordering
Drop highlighting
Insertion marks
Three properties are essential for setting up Better ListView as a drag source:
Used when Drag and Drop operation is initiated. This tells the Drag and Drop mechanism, what effects on mouse cursor can be shown while dragging some data.
Simply switches the ability of Better ListView to behave as drag source.
Sets the behavior of item reordering.
Item reordering is enabled by setting ItemReorderMode property to either Enabled or Custom. The difference between these values is that on Enabled Better ListView does all the item reordering automatically (items will be actually reordered in the list), but Custom shows only the effect, fires item reorder events and the actual reordering is expected to be done externally. This is practical - for example - when one displays confirmation dialog to proceed reordering or just needs to deny the reordering in some cases.
This image shows item reordering in action:
There are two effect available while dragging over Better ListView.
DropHighlight looks like a hot state of an item. It shows when user is dragging data over an item. It is useful when data are to be dropped on a certain item:
InsertionMark is a line showing target position between neighboring items. It is useful for inserting data in the list or item reordering:
When the InsertionMark effect is turned on, the insertion mark is updated when mouse drags over the control. You may need to set custom location of insertion mark in certain situations. In that case, set the BetterListViewDragDropEffectSettingEventArgs.UpdateInsertionMark property to false in the DragDropEffectSetting event handler.
There are two properties governing the effect during Drag and Drop operation: ItemDropDisplayInternal and ItemDropDisplayExternal.
Internal drop display is used when source and target of the drag-drop operation is the same. This effect is InsertionMark by default and refers to item reordering.
External drop display is used when data are dragged from another control. This effect is DropHighlight by default. DropHighlight can be disabled on selected items by setting AllowDropHighlight property to false.
If you need to show different effects on specific items, you can use properties BetterListViewItem.CustomDropDisplayInternal and BetterListViewItem.CustomDropDisplayExternal. Their values are initially set to BetterListViewDragDropDisplay.Default, which means that the values are derived from ItemDropDisplayInternal and ItemDropDisplayExternal properties instead (see Internal and External Drop Display).
Items can be dragged between different Better ListViews, other controls and even across application domains (between applications). Better ListView uses its own structure of type BetterListViewItemDragData.
BetterListViewItemDragData contains both dragged item indices and cloned items. Items are cloned because when the dragged data crosses application domain, it is serialized and must not contain any reference to source Better ListView since such objects cannot be transferred through this channel. For the purpose of indentifying drag source control, BetterListViewItemDragData contains globally-unique ID of the Better ListView (BetterListView.DragSourceID property).
When doing item reordering, insertion location is available in CheckItemReorder even data (BetterListViewCheckItemReorderEventArgs.InsertionLocation) so that you can decide whether to disable insertion mark or do other action depending on current insertion location.
During Drag and Drop, however, there is no such data readily available. The same functionality can be still achieved using GetDropInfo method. This method return insertion location depending on current drag effect setting (drop highlight, insertion mark). The parameters are screen coordinates of mouse cursor position (these are readily available in the DragDropEffectSetting event handler, which you can use during Drag and Drop operation).
C#
//
// setup the first Better ListView
//
this.listView1.BeginUpdate();
this.listView1.Items.AddRange(
new[]
{
"A Fork",
"A Spoon",
"A Knife"
});
this.listView1.AutoSizeItemsInDetailsView = true;
this.listView1.EndUpdate();
// allow dragging items from this list
this.listView1.AllowDrag = true;
// allow dropping items on this list
this.listView1.AllowDrop = true;
// show insertion mark when dragging over this list
this.listView1.ItemDropDisplayExternal = BetterListViewDragDropDisplay.InsertionMark;
// this event has to be handled to properly set some effect (e.g. 'Move') when dragging
this.listView1.DragDropEffectSetting += ListViewDragDropEffectSetting;
// this event tells us that user dropped data on some item of the Better ListView (DragDrop event is more general than this)
this.listView1.ItemDrop += ListViewItemDrop;
// handle the case when user drops item(s) on empty list - in that case ItemDrop is not raised and we should use DragDrop
this.listView1.DragDrop += ListViewDragDrop;
//
// setup the second Better ListView
//
this.listView2.BeginUpdate();
this.listView2.Items.AddRange(
new[]
{
"A Chair",
"A Table",
"A Wardrobe"
});
this.listView2.AllowDrag = true;
this.listView2.AllowDrop = true;
this.listView2.ItemDropDisplayExternal = BetterListViewDragDropDisplay.InsertionMark;
this.listView2.AutoSizeItemsInDetailsView = true;
this.listView2.EndUpdate();
this.listView2.DragDropEffectSetting += ListViewDragDropEffectSetting;
this.listView2.ItemDrop += ListViewItemDrop;
this.listView2.DragDrop += ListViewDragDrop;
Visual Basic
'
' setup the first Better ListView
'
ListView1.BeginUpdate()
ListView1.Items.AddRange(
New String() {
"A Fork",
"A Spoon",
"A Knife"
})
ListView1.AutoSizeItemsInDetailsView = True
ListView1.EndUpdate()
' allow dragging items from this list
ListView1.AllowDrag = True
' allow dropping items on this list
ListView1.AllowDrop = True
' show insertion mark when dragging over this list
ListView1.ItemDropDisplayExternal = BetterListViewDragDropDisplay.InsertionMark
' this event has to be handled to properly set some effect (e.g. 'Move') when dragging
AddHandler ListView1.DragDropEffectSetting, AddressOf ListViewDragDropEffectSetting
' this event tells us that user dropped data on some item of the Better ListView (DragDrop event is more general than this)
AddHandler ListView1.ItemDrop, AddressOf ListViewItemDrop
' handle the case when user drops item(s) on empty list - in that case ItemDrop is not raised and we should use DragDrop
AddHandler ListView1.DragDrop, AddressOf ListViewDragDrop
'
' setup the second Better ListView
'
ListView2.BeginUpdate()
ListView2.Items.AddRange(
New String() {
"A Chair",
"A Table",
"A Wardrobe"
})
ListView2.AllowDrag = True
ListView2.AllowDrop = True
ListView2.ItemDropDisplayExternal = BetterListViewDragDropDisplay.InsertionMark
ListView2.AutoSizeItemsInDetailsView = True
ListView2.EndUpdate()
AddHandler ListView2.DragDropEffectSetting, AddressOf ListViewDragDropEffectSetting
AddHandler ListView2.ItemDrop, AddressOf ListViewItemDrop
AddHandler ListView2.DragDrop, AddressOf ListViewDragDrop
Source code for the ListViewDragDropEffectSetting event:
C#
void ListViewDragDropEffectSetting(object sender, BetterListViewDragDropEffectSettingEventArgs eventArgs)
{
BetterListViewItemDragData itemDragData = (BetterListViewItemDragData)eventArgs.Data.GetData(typeof(BetterListViewItemDragData));
Control child = GetChildAtPoint(PointToClient(new Point(eventArgs.X, eventArgs.Y)));
if (child is BetterListView &&
((BetterListView)child).DragSourceID == itemDragData.DragSourceID) // check whether the data comes from this cotnrol
{
// do not allow dropping on the source control
eventArgs.Effect = DragDropEffects.None;
}
else
{
eventArgs.Effect = DragDropEffects.Move;
}
}
Visual Basic
Sub ListViewDragDropEffectSetting(ByVal sender As Object, ByVal eventArgs As BetterListViewDragDropEffectSettingEventArgs)
Dim itemDragData As BetterListViewItemDragData = DirectCast(eventArgs.Data.GetData(GetType(BetterListViewItemDragData)), BetterListViewItemDragData)
Dim child As Control = GetChildAtPoint(PointToClient(New Point(eventArgs.X, eventArgs.Y)))
If TypeOf child Is BetterListView.BetterListView AndAlso DirectCast(child, BetterListView.BetterListView).DragSourceID = itemDragData.DragSourceID Then
' check whether the data comes from this cotnrol
' do not allow dropping on the source control
eventArgs.Effect = DragDropEffects.None
Else
eventArgs.Effect = DragDropEffects.Move
End If
End Sub
Source code for the ListViewItemDrop event:
C#
void ListViewItemDrop(object sender, BetterListViewItemDropEventArgs eventArgs)
{
BetterListViewItemDragData itemDragData = (BetterListViewItemDragData)eventArgs.Data.GetData(typeof(BetterListViewItemDragData));
BetterListView listViewSource = GetSourceList(itemDragData);
BetterListView listViewTarget = GetTargetList(itemDragData);
// remove items from the source list
listViewSource.Items.RemoveRange(itemDragData.Items);
// insert items to the target list (either before or after the target item, depending on the insertion location)
listViewTarget.Items.InsertRange(
(eventArgs.ItemDropPart == BetterListViewDropPart.After)
? (eventArgs.Item.Index + 1)
: eventArgs.Item.Index,
itemDragData.Items);
}
Visual Basic
Sub ListViewItemDrop(ByVal sender As Object, ByVal eventArgs As BetterListViewItemDropEventArgs)
Dim itemDragData As BetterListViewItemDragData = DirectCast(eventArgs.Data.GetData(GetType(BetterListViewItemDragData)), BetterListViewItemDragData)
Dim listViewSource As BetterListView.BetterListView = GetSourceList(itemDragData)
Dim listViewTarget As BetterListView.BetterListView = GetTargetList(itemDragData)
' remove items from the source list
listViewSource.Items.RemoveRange(itemDragData.Items)
' insert items to the target list (either before or after the target item, depending on the insertion location)
listViewTarget.Items.InsertRange(If((eventArgs.ItemDropPart = BetterListViewDropPart.After), (eventArgs.Item.Index + 1), eventArgs.Item.Index), itemDragData.Items)
End Sub
Source code for the ListViewDragDrop event:
C#
void ListViewDragDrop(object sender, DragEventArgs e)
{
BetterListViewItemDragData itemDragData = (BetterListViewItemDragData)e.Data.GetData(typeof(BetterListViewItemDragData));
BetterListView listViewSource = GetSourceList(itemDragData);
BetterListView listViewTarget = GetTargetList(itemDragData);
if (listViewTarget.Items.Count == 0)
{
// remove items from the source list
listViewSource.Items.RemoveRange(itemDragData.Items);
// add items to the target list
listViewTarget.Items.AddRange(itemDragData.Items);
}
}
Visual Basic
Sub ListViewDragDrop(ByVal sender As Object, ByVal e As DragEventArgs)
Dim itemDragData As BetterListViewItemDragData = DirectCast(e.Data.GetData(GetType(BetterListViewItemDragData)), BetterListViewItemDragData)
Dim listViewSource As BetterListView.BetterListView = GetSourceList(itemDragData)
Dim listViewTarget As BetterListView.BetterListView = GetTargetList(itemDragData)
If listViewTarget.Items.Count = 0 Then
' remove items from the source list
listViewSource.Items.RemoveRange(itemDragData.Items)
' add items to the target list
listViewTarget.Items.AddRange(itemDragData.Items)
End If
End Sub
Source code for the GetSourceList and GetTargetList methods:
C#
BetterListView GetSourceList(BetterListViewItemDragData itemDragData)
{
return ((itemDragData.DragSourceID == this.listView1.DragSourceID) // check whether the data comes from the first ListView
? this.listView1
: this.listView2);
}
BetterListView GetTargetList(BetterListViewItemDragData itemDragData)
{
return ((itemDragData.DragSourceID == this.listView1.DragSourceID) // check whether the data comes from the first ListView
? this.listView2
: this.listView1);
}
Visual Basic
Function GetSourceList(ByVal itemDragData As BetterListViewItemDragData) As BetterListView.BetterListView
' check whether the data comes from the first ListView
Return (If((itemDragData.DragSourceID = ListView1.DragSourceID), ListView1, ListView2))
End Function
Function GetTargetList(ByVal itemDragData As BetterListViewItemDragData) As BetterListView.BetterListView
' check whether the data comes from the first ListView
Return (If((itemDragData.DragSourceID = ListView1.DragSourceID), ListView2, ListView1))
End Function
« Data Binding | Index | Embedded Controls » |
Better ListView Documentation | Copyright © 2010-2012 ComponentOwl.com |