【问题标题】:How to change ListBox to ListView in WinForms application如何在 WinForms 应用程序中将 ListBox 更改为 ListView
【发布时间】:2015-12-04 07:08:57
【问题描述】:

我的 WinForms 应用程序中有一个 ListBox 控件,每次我通过以下代码更新它时,它都会滚动到第一个元素:

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

根据this问题的答案,这是一个功能,而不是一个错误,我们应该使用ListView控制而不是ListBox来避免这种行为。

不幸的是,我有很多代码依赖于ListBox 接口,将ListBox 更改为ListView 控件会导致很多错误。比如我在ListView中没有DataSourceDisplayMemberValueMember这样的属性,所以不知道如何正确绑定。

ListView 中也没有 IndexFromPoint 方法,我需要在光标下获取一个项目,并且我需要 SelectedItemSelectedIndex 等属性以供以后使用(例如,在右键单击事件中) .

在我的情况下,将 ListBox 更改为 ListView 的最佳方法是什么?

是否有任何其他解决方法可以摆脱这种闪烁的顺便说一句?

【问题讨论】:

  • ListView 是一个可怕的控件恕我直言。好的,如果您需要带图像的特殊显示模式,但如果您使用的是普通列表,那么 ListBox 将是 IMO 的优势。

标签: c# winforms listview listbox


【解决方案1】:

如果你真的想做这样的改变,最好的方法是创建一个UserControl,它承载一个ListView,并为你的UserControl实现这样的属性和方法。

例如:

//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;
    }
}

实现用户控制是为了独立于ListView,而不是暴露ListView成员。但是如果你不关心它,你可以从ListView继承并添加你想要的属性和方法,例如:

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;
    }
}

编辑


作为另一种听起来不错的选择;您可以创建一个WPF UserControl 来托管一个似乎不受滚动问题影响的WPF ListBox。这样您就可以使用ElementHost 控件在Windows 窗体中托管您的用户控件。
正如我在您向其中添加新项目时测试的那样,滚动条保持在现在的位置。

【讨论】:

  • 老实说,我不想要它,但我没有看到任何其他选项可以避免 ListBox 控件中的这种闪烁行为
  • 感谢您的回答,但是来自 WPF 的 ListBox 没有很多其他东西——例如,IndexFromPoint 方法。我需要在我的解决方案中有一个单独的 DLL 项目,然后仅用于此控件
【解决方案2】:

也许您会发现一些有用的想法 - 在 VB 中但很容易转换为 C#

由开始/结束处理的闪烁。选择正确的行显然需要注意。

    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()

【讨论】:

  • 那么它的诀窍是什么?为什么要在BeginUpdateEndUpdate 调用之间放置“绑定”代码,SelectedIndex 中的 40 是什么意思?
  • 通过我的测试,开始/结束消除了闪烁。 SelectedInex 只是为了展示如何将列表移动到给定点 - 40 只是一个测试
  • 无论如何我都不明白SelectedIndex 的部分。我不需要将列表移动到给定点,我需要一个在更改其DataSource 时不会闪烁的控件
  • 抱歉 - 我在使用 ListBox 而不是 ListView 回答问题时遇到了麻烦。
猜你喜欢
  • 1970-01-01
  • 2020-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多