繁体   English   中英

是否可以将列表绑定到 WinForms 中的 ListView?

[英]Is it possible to bind a List to a ListView in WinForms?

我想将 ListView 绑定到List<string><\/code> 。 我正在使用这段代码:

somelistview.DataBindings.Add ("Items", someclass, "SomeList");

ListView 类不支持设计时绑定。 本项目提供了一种替代方案

或者,如果需要数据绑定,可以使用 DataGridView。 当新项目添加到您的列表时,使用 BindingList 和 BindingSource 将更新您的 DataGrid。

var barcodeContract = new BarcodeContract { Barcode = barcodeTxt.Text, Currency = currencyTxt.Text, Price = priceTxt.Text };

        list.Add(barcodeContract);
        var bindingList = new BindingList<BarcodeContract>(list);
        var source = new BindingSource(bindingList, null);
        dataGrid.DataSource = source;

和数据模型类

    public class BarcodeContract
{
    public string Barcode { get; set; }
    public string Price { get; set; }
    public string Currency { get; set; }
}

我使用以下技术将数据绑定到 ListView。

在此处输入图片说明

它支持正确的(不是基于文本的)排序。 在上面的例子中,通过字符串、日期时间和整数。

上面的 ListView 是用以下代码生成的:

var columnMapping = new List<(string ColumnName, Func<Person, object> ValueLookup, Func<Person, string> DisplayStringLookup)>()
{
    ("Name", person => person.Name, person => person.Name),
    ("Date of birth", person => person.DateOfBirth, person => $"{person.DateOfBirth:dd MMM yyyy}"),
    ("Height", person => person.HeightInCentimetres, person => Converter.CentimetresToFeetInchesString(person.HeightInCentimetres))
};

var personListview = new ListViewEx<Person>(columnMapping)
{
    FullRowSelect = true,
    View = View.Details,
    Left = 20,
    Top = 20,
    Width = 500,
    Height = 300,                
};

var people = new[]
{
    new Person("Cathy Smith", DateTime.Parse("1980-05-15"), 165),
    new Person("Bill Wentley", DateTime.Parse("1970-10-30"), 180),
    new Person("Alan Bridges", DateTime.Parse("1990-03-22"), 190),
};

personListview.AddRange(people);

Controls.Add(personListview);

在列映射中,您会注意到您必须指定如何获取项目的(用于排序)以及字符串(用于显示)。

完整来源:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace GUI
{
    public class ListViewEx<T> : ListView
    {
        public ListViewEx(IList<(string ColumnName, Func<T, object> ValueLookup, Func<T, string> DisplayStringLookup)> columnInfo) : base()
        {
            ColumnInfo = columnInfo;
            DoubleBuffered = true;

            //Create the columns
            columnInfo
                .Select(ci => ci.ColumnName)
                .ToList()
                .ForEach(columnName =>
                {
                    var col = Columns.Add(columnName);
                    col.Width = -2;
                });

            //Add the sorter
            lvwColumnSorter = new ListViewColumnSorter<T>(columnInfo);
            ListViewItemSorter = lvwColumnSorter;
            ColumnClick += ListViewEx_ColumnClick;
        }

        IList<(string ColumnName, Func<T, object> ValueLookup, Func<T, string> DisplayStringLookup)> ColumnInfo { get; }

        private readonly ListViewColumnSorter<T> lvwColumnSorter;

        public void Add(T item)
        {
            var lvi = Items.Add("");
            lvi.Tag = item;

            RefreshContent();
        }

        public void AddRange(IList<T> items)
        {
            foreach (var item in items)
            {
                Add(item);
            }
        }

        public void Remove(T item)
        {
            if (item == null) return;

            var listviewItem = Items
                        .Cast<ListViewItem>()
                        .Select(lvi => new
                        {
                            ListViewItem = lvi,
                            Obj = (T)lvi.Tag
                        })
                        .FirstOrDefault(lvi => item.Equals(lvi.Obj))
                        .ListViewItem;

            Items.Remove(listviewItem);

            RefreshContent();
        }

        public List<T> GetSelectedItems()
        {
            var result = SelectedItems
                            .OfType<ListViewItem>()
                            .Select(lvi => (T)lvi.Tag)
                            .ToList();

            return result;
        }

        public void RefreshContent()
        {
            var columnsChanged = new List<int>();

            Items
                .Cast<ListViewItem>()
                .Select(lvi => new
                {
                    ListViewItem = lvi,
                    Obj = (T)lvi.Tag
                })
                .ToList()
                .ForEach(lvi =>
                {
                    //Update the contents of this ListViewItem
                    ColumnInfo
                        .Select((column, index) => new
                        {
                            Column = column,
                            Index = index
                        })
                        .ToList()
                        .ForEach(col =>
                        {
                            var newDisplayValue = col.Column.DisplayStringLookup(lvi.Obj);
                            if (lvi.ListViewItem.SubItems.Count <= col.Index)
                            {
                                lvi.ListViewItem.SubItems.Add("");
                            }

                            var subitem = lvi.ListViewItem.SubItems[col.Index];
                            var oldDisplayValue = subitem.Text ?? "";

                            if (!oldDisplayValue.Equals(newDisplayValue))
                            {
                                subitem.Text = newDisplayValue;
                                columnsChanged.Add(col.Index);
                            }
                        });
                });

            columnsChanged.ForEach(col => { Columns[col].Width = -2; });

            //AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
            //AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
        }

        private void ListViewEx_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            if (e.Column == lvwColumnSorter.ColumnToSort)
            {
                if (lvwColumnSorter.SortOrder == SortOrder.Ascending)
                {
                    lvwColumnSorter.SortOrder = SortOrder.Descending;
                }
                else
                {
                    lvwColumnSorter.SortOrder = SortOrder.Ascending;
                }
            }
            else
            {
                lvwColumnSorter.ColumnToSort = e.Column;
                lvwColumnSorter.SortOrder = SortOrder.Ascending;
            }

            Sort();
        }
    }

    public class ListViewColumnSorter<T> : IComparer
    {
        public ListViewColumnSorter(IList<(string ColumnName, Func<T, object> ValueLookup, Func<T, string> DisplayStringLookup)> columnInfo)
        {
            ColumnInfo = columnInfo;
        }

        public int Compare(object x, object y)
        {
            if (x == null || y == null) return 0;

            int compareResult;

            var listviewX = (ListViewItem)x;
            var listviewY = (ListViewItem)y;

            var objX = (T)listviewX.Tag;
            var objY = (T)listviewY.Tag;

            if (objX == null || objY == null) return 0;

            var valueX = ColumnInfo[ColumnToSort].ValueLookup(objX);
            var valueY = ColumnInfo[ColumnToSort].ValueLookup(objY);

            compareResult = Comparer.Default.Compare(valueX, valueY);

            if (SortOrder == SortOrder.Ascending)
            {
                return compareResult;
            }
            else if (SortOrder == SortOrder.Descending)
            {
                return -compareResult;
            }
            else
            {
                return 0;
            }
        }

        public int ColumnToSort { get; set; } = 0;

        public SortOrder SortOrder { get; set; } = SortOrder.Ascending;

        public IList<(string ColumnName, Func<T, object> ValueLookup, Func<T, string> DisplayStringLookup)> ColumnInfo { get; }
    }
}

通过@Fidel 添加到答案<\/a>

如果您只想快速自动映射列,请将此代码添加到ListViewEx<\/code>类:

using System.Reflection;

public ListViewEx() : this(AutoMapColumns()) { }

private static List<(string ColumnName, Func<T, object> ValueLookup, Func<T, string> DisplayStringLookup)> AutoMapColumns()
{
    var mapping = new List<(string ColumnName, Func<T, object> ValueLookup, Func<T, string> DisplayStringLookup)>();

    var props = typeof(T).GetTypeInfo().GetProperties();

    foreach (var prop in props)
    {
        mapping.Add((
            prop.Name,
            (T t) => prop.GetValue(t),
            (T t) => prop.GetValue(t).ToString()
        ));
    }
            
    return mapping;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM