Reputation: 20726
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
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;
}
}
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
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