FrozenHeart
FrozenHeart

Reputation: 20726

How to change ListBox to ListView in WinForms application

I have a ListBox control in my WinForms application that scrolls to the first element every time when I update it via the following code:

listBox.DataSource = new BindingSource(someDicrionary, null);

According to the answer for this question, it's a feature, not a bug, and we should use ListView control instead of ListBox to avoid such behavior.

Unfortunately, I have a lot of code that relies on a ListBox interface and changing ListBox to the ListView control results in a lot of errors. For example, I don't have such properties like DataSource, DisplayMember and ValueMember in ListView, so I don't know how to bind it properly.

There is also no IndexFromPoint method in ListView which I need to get an item under cursor and I need properties like SelectedItem and SelectedIndex for later usage (for example, in the right-clicking event).

What is the best way to change ListBox to ListView in my case?

Is there any other workaround to get rid off this flickering btw?

Upvotes: 2

Views: 1485

Answers (2)

Reza Aghaei
Reza Aghaei

Reputation: 125197

If you really want to do such change, the best way is creating a UserControl that hosts a ListView and implement such properties and methods for your UserControl.

For example:

//Just for sample, you should add some checks and raise some events and throw some exceptions.
public int SelectedIndex
{
    get
    {
        var selectedIndex = -1;
        if (this.listView1.SelectedItems.Count == 1)
            selectedIndex = this.listView1.SelectedItems[0].Index;
        return selectedIndex;
    }
    set
    {
        this.listView1.SelectedItems.Cast<ListViewItem>()
            .ToList().ForEach(item =>
            {
                item.Selected = false;
            });
        this.listView1.Items[value].Selected = true;
    }
}

Implementing user control is for being independent from ListView and not to expose ListView members. But if it is not a concern for you, you can inherit from ListView and add properties and methods that you want to it, for example:

public int IndexFromPoint(Point p)
{
    return this.IndexFromPoint(p.X, p.Y);
}
public int IndexFromPoint(int x, int y)
{
    var item = this.HitTest(x, y).Item;
    if (item != null)
        return item.Index;

    return -1;
}

private string displayMember;
[Editor("System.Windows.Forms.Design.DataMemberFieldEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
[TypeConverter("System.Windows.Forms.Design.DataMemberFieldConverter, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
public string DisplayMember
{
    get
    {
        return displayMember;
    }
    set
    {
        displayMember = value;
    }
}

private string valueMember;
[Editor("System.Windows.Forms.Design.DataMemberFieldEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
[TypeConverter("System.Windows.Forms.Design.DataMemberFieldConverter, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
public string ValueMember
{
    get
    {
        return valueMember;
    }
    set
    {
        valueMember = value;
    }
}

Edit


As another alternative that sounds good; you can create a WPF UserControl that hosts a WPF ListBox that seems doesn't suffer from that scroll problem. This way you can host your usercontrol in windows forms using an ElementHost control.
As I tested when you add new items to it, the scroll remains where it is now.

Upvotes: 2

rheitzman
rheitzman

Reputation: 2297

Perhaps some ideas you may find useful - in VB but easily translated to C#

Flicker addressed by the begin/end. Selecting the proper row would need some attention obviously.

    lb1.BeginUpdate()
    lb1.Sorted = True
    Dim dv As DataTable = Gen.GetDataTable("Select Facility_Name from Facility")
    lb1.DisplayMember = "Facility_name"
    lb1.ValueMember = "Facility_name"
    lb1.DataSource = dv
    lb1.SelectedIndex = 40
    lb1.EndUpdate()

Upvotes: 0

Related Questions