# Insertion Mark

Better ListView: Ultimate .NET ListView replacement control for WinForms (C#, VB.NET)
Download More Info

Better ListView Express does not support groups or hierarchical items, so the insertion mark can be placed on items only in the Express edition.

Insertion mark is a line showing location between items. Better ListView support displaying the insertion mark on various locations with support for groups and item hierarchy:

The basic usage of insertion mark is the same as in regular .NET ListView. Setting InsertionMark property using one of these constructors will give you the classic insertion mark:

- BetterListViewInsertionMark(int index)

- BetterListViewInsertionMark(int index, bool showAfterItem)

- BetterListViewInsertionMark(int index, bool showAfterItem, Color color)

- BetterListViewInsertionMark(int index, bool showAfterItem, Color color, bool enabled)

The last constructor has an extra parameter enabled which adjusts insertion mark color slightly (giving it alpha transparency) to be displayed in an inactive or disabled state.

There are also more general constructors for displaying insertion mark on arbitrary location in item hierarchy and on groups:

- BetterListViewInsertionMark(BetterListViewInsertionLocation insertionLocation)

- BetterListViewInsertionMark(BetterListViewInsertionLocation insertionLocation, Color color)

- BetterListViewInsertionMark(BetterListViewInsertionLocation insertionLocation, Color color, bool enabled)

Instead of index, there is an insertionLocation parameter.

## Insertion Locations

The BetterListViewInsertionLocation type can describe any location in item hierarchy and on groups. The location consists of three properties:

- Address

- DropPart

- Level

Address is a counterpart of index in item hierarchy (see Addressing Elements). It can describe either group or a child item.

DropPart defines relative insertion location to the element specified by the Address. The drop part value can be either Before the element, After the element or Inside the element. For groups, the Inside is the only valid value. Items can display any of the three drop parts. The difference between After and Inside is that with Inside it is possible to create new child items. Otherwise, the location inside item can be substituted by before first child item of that item.

Level specifies target level in item hierarchy. It is valid for Before and After drop parts only. By default, the Level property has value of BetterListViewInsertionLocation.LevelUndefined and thus inheriting level of the currently located item. When set, it overrides the level and the insertion mark can start on smaller offset than the child item. This is used mainly internally for item reordering, when user puts item after the last child item and then moves mouse cursor to the left, to put it after its parent, actually.

## Sample Source Code

The following sample shows how to display insertion mark according to current mouse position (see Hit Test).

C#

    this.listView.BeginUpdate();

    // create groups with items and child items
    BetterListViewGroup groupRecent = new BetterListViewGroup("Recent Items");

    groupRecent.Items.AddRange(
        new[]
        {
            "Ming Dynasty Vase",
            "Collection of Rembrandt",
            "Photos from Prokudin Gorskij"
        });

    groupRecent.Items[1].ChildItems.AddRange(
        new[]
        {
            "The Night Watch",
            "Belshazzar's Feast"
        });

    BetterListViewGroup groupArchived = new BetterListViewGroup("Archived Items");

    groupArchived.Items.AddRange(
        new[]
        {
            "Statue of Zeus",
            "Rare pens from Hamburg and Dresden"
        });

    this.listView.Groups.AddRange(
        new[]
        {
            groupRecent,
            groupArchived
        });

    // set custom color for the insertion mark
    this.listView.ColorInsertionMark = Color.DarkGreen;
    // make the groups visible
    this.listView.ShowGroups = true;

    this.listView.EndUpdate();

    // this will set insertion mark every time hit test changes
    this.listView.HitTestChanged += ListViewHitTestChanged;

Visual Basic

    ListView.BeginUpdate()

    ' create groups with items and child items
    Dim groupRecent As New BetterListViewGroup("Recent Items")

    groupRecent.Items.AddRange(
        New String() {
            "Ming Dynasty Vase",
            "Collection of Rembrandt",
            "Photos from Prokudin Gorskij"
                     })

    groupRecent.Items(1).ChildItems.AddRange(
        New String() {
            "The Night Watch",
            "Belshazzar's Feast"
                     })

    Dim groupArchived As New BetterListViewGroup("Archived Items")

    groupArchived.Items.AddRange(
        New String() {
            "Statue of Zeus",
            "Rare pens from Hamburg and Dresden"
                     })

    ListView.Groups.AddRange(New BetterListViewGroup() {groupRecent, groupArchived})

    ' set custom color for the insertion mark
    ListView.ColorInsertionMark = Color.DarkGreen
    ' make the groups visible
    ListView.ShowGroups = True

    ListView.EndUpdate()

    ' this will set insertion mark every time hit test changes
    AddHandler ListView.HitTestChanged, AddressOf ListViewHitTestChanged

The HitTestInfoChanged event handler determines the actual insertion mark location and sets it:

C#

    void ListViewHitTestChanged(object sender, BetterListViewHitTestChangedEventArgs eventArgs)
    {
        // get current hit test information
        BetterListViewHitTestInfo hitTestInfo = eventArgs.HitTestInfoNew;

        // get address and drop part to assembly an insertion mark location
        BetterListViewAddress address;
        BetterListViewDropPart dropPart;

        if (hitTestInfo.Item != null)
        {
            // the mouse cursor is located on item
            address = hitTestInfo.Item.Address;

            if ((hitTestInfo.ItemPart & BetterListViewHitPart.VCenter) == BetterListViewHitPart.VCenter)
            {
                // the mouse cursor is located in the centre of the item - the insertion mark will point inside the item
                dropPart = BetterListViewDropPart.Inside;
            }
            else
            {
                // the mouse cursor is located on other parts of the item - the insertion mark will point before on after the item
                dropPart = (((hitTestInfo.ItemPart & BetterListViewHitPart.Bottom) == BetterListViewHitPart.Bottom)
                                ? BetterListViewDropPart.After
                                : BetterListViewDropPart.Before);
            }
        }
        else if (
            hitTestInfo.Group != null)
        {
            // the mouse cursor is located on group
            address = hitTestInfo.Group.Address;
            dropPart = BetterListViewDropPart.Inside; //NOTE: only Inside is allowed as drop part on groups
        }
        else
        {
            // the mouse cursor is not located on item nor group
            address = null;
            dropPart = BetterListViewDropPart.Undefined;
        }

        if (address != null)
        {
            // set insertion mark on the constructed location
            this.listView.InsertionMark = new BetterListViewInsertionMark(new BetterListViewInsertionLocation(address, dropPart));
        }
        else
        {
            // reset insertion mark
            this.listView.InsertionMark = BetterListViewInsertionMark.Empty;
        }
    }

Visual Basic

    Sub ListViewHitTestChanged(ByVal sender As Object, ByVal eventArgs As BetterListViewHitTestChangedEventArgs)

        ' get current hit test information
        Dim hitTestInfo As BetterListViewHitTestInfo = eventArgs.HitTestInfoNew

        ' get address and drop part to assembly an insertion mark location
        Dim address As BetterListViewAddress
        Dim dropPart As BetterListViewDropPart

        If hitTestInfo.Item IsNot Nothing Then

            ' the mouse cursor is located on item
            address = hitTestInfo.Item.Address

            If (hitTestInfo.ItemPart And BetterListViewHitPart.VCenter) = BetterListViewHitPart.VCenter Then

                ' the mouse cursor is located in the centre of the item - the insertion mark will point inside the item
                dropPart = BetterListViewDropPart.Inside

            Else

                ' the mouse cursor is located on other parts of the item - the insertion mark will point before on after the item
                dropPart = (If(((hitTestInfo.ItemPart And BetterListViewHitPart.Bottom) = BetterListViewHitPart.Bottom), BetterListViewDropPart.After, BetterListViewDropPart.Before))

            End If

        ElseIf hitTestInfo.Group IsNot Nothing Then

            ' the mouse cursor is located on group
            address = hitTestInfo.Group.Address
            'NOTE: only Inside is allowed as drop part on groups
            dropPart = BetterListViewDropPart.Inside

        Else

            ' the mouse cursor is not located on item nor group
            address = Nothing
            dropPart = BetterListViewDropPart.Undefined

        End If

        If address IsNot Nothing Then

            ' set insertion mark on the constructed location
            ListView.InsertionMark = New BetterListViewInsertionMark(New BetterListViewInsertionLocation(address, dropPart))

        Else

            ' reset insertion mark
            ListView.InsertionMark = BetterListViewInsertionMark.Empty

        End If

    End Sub

Better ListView: Ultimate .NET ListView replacement control for WinForms (C#, VB.NET)
Download More Info