Alex
Alex

Reputation: 1367

Disallow ListView to have zero selected items

My project is .NET/WinForms.

I have a list view which is always filled with items. I would like it to have selection always. However, if I click on an empty area below list view items, it looses selection.

The list has multiple selection = true and hide selection = false.

Upvotes: 16

Views: 6786

Answers (6)

Hans Passant
Hans Passant

Reputation: 941635

You need to prevent the native control from seeing the mouse click so it won't unselect an item. Add a new class to your project and paste the code shown below. Compile. Drop it from the top of the toolbox onto your form, replacing the existing one.

using System;
using System.Drawing;
using System.Windows.Forms;

class MyListView : ListView {
    protected override void WndProc(ref Message m) {
        // Swallow mouse messages that are not in the client area
        if (m.Msg >= 0x201 && m.Msg <= 0x209) {
            Point pos = new Point(m.LParam.ToInt32());
            var hit = this.HitTest(pos);
            switch (hit.Location) {
                case ListViewHitTestLocations.AboveClientArea :
                case ListViewHitTestLocations.BelowClientArea :
                case ListViewHitTestLocations.LeftOfClientArea :
                case ListViewHitTestLocations.RightOfClientArea :
                case ListViewHitTestLocations.None :
                    return;
            }
        }
        base.WndProc(ref m);
    }
}

Upvotes: 30

Alex
Alex

Reputation: 21

    private void LV_MouseUp(object sender, MouseEventArgs e)
    {
        if (LV.FocusedItem != null)
        {
            if (LV.SelectedItems.Count == 0)
                LV.FocusedItem.Selected = true;
        }
    }

(no multiselect)

Upvotes: 2

Shaun Luttin
Shaun Luttin

Reputation: 141542

This following works if you do not need multiselect. It has the advantage of not needing to to track which item was last selected.

private void ListViewAny_SelectedIndexChanged(object sender, EventArgs e)
{
    if ((sender as ListView).FocusedItem != null)
    {
        (sender as ListView).FocusedItem.Selected = true;
    }
}

Upvotes: 4

djdd87
djdd87

Reputation: 68476

Like the others have said, the SelectedIndexChanged event is what you should look at, however you should use it in collaboration with the ItemSelectionChanged event. Here's some code I've just cooked up:

// Holds the last selected index
private int _previousIndex = -1;

// Restores the previous selection if there are no selections
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
    if (listView1.SelectedIndices.Count == 0)
    {
        if (_previousIndex >= 0)
        {
            listView1.SelectedIndices.Add(_previousIndex);
        }
    }
}

// Records the last selected index
private void listView1_ItemSelectionChanged(object sender, 
               ListViewItemSelectionChangedEventArgs e)
{
    if (e.IsSelected)
    {
        _previousIndex = e.ItemIndex;
    }
}

For pure code re-use purposes, it'd probably be worthwhile putting this code into a new UserControl and have a property that determines whether or not to allow the last selection to be lost:

public class CustomListView : ListView
{

    protected CustomListView()
    {
        this.SelectedIndexChanged += new EventHandler(CustomListView_SelectedIndexChanged);
        this.ItemSelectionChanged += new ListViewItemSelectionChangedEventHandler(CustomListView_ItemSelectionChanged);
    }

    void CustomListView_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (this.MaintainLastSelection && this.SelectedIndices.Count == 0)
        {
            if (_previousIndex >= 0)
            {
                this.SelectedIndices.Add(_previousIndex);
            }
        }
    }

    void CustomListView_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
    {
        if (e.IsSelected)
        {
            _previousIndex = e.ItemIndex;
        }
    }

    private int _previousIndex = -1;

    public bool MaintainLastSelection
    {
        get { return _maintainLastSelection; }
        set { _maintainLastSelection = value; }
    }
    private bool _maintainLastSelection;

}

Upvotes: 2

Adam Houldsworth
Adam Houldsworth

Reputation: 64487

The ListView has a SelectedIndexChanged event. Listen for this and then query the listView.SelectedItems.Count property - if it's zero, select the first / last selected item.

Upvotes: 0

Marek
Marek

Reputation: 10402

You need to handle the SelectedIndexChanged event of the ListView and in case there is no item selected after this event occurs, programmatically re-select the last known selection.

Upvotes: 0

Related Questions