2

簡単な例:

BindingList<Dog> dogs = kennel.Dogs;

// Works great!
listBoxDogs.DataSource = dogs;

// Confuses me.
listViewDogs.? = dogs;

listViewDogs.DataBindingsプロパティを調べましたが、DataSourceを使用してlistBoxコントロールで表示されているのと同様の動作を引き出すことができませんでした。

listViewDogs.Itemsコレクションを更新してから、dogs.ListChangedイベントをキャッチし、listViewDogs.Itemsコレクションを手動で操作するより良い方法が必要です。

私は何が欠けていますか?

4

2 に答える 2

1

残念ながら、リストビューはそのような方法でのデータバインディングをサポートしていません。

これは、新しいコントロールを作成して実装する方法のチュートリアルです。

http://www.codeproject.com/KB/list/ListView_DataBinding.aspx

ps。そこにはもっとたくさんあります!

于 2011-01-20T16:32:23.620 に答える
1

さて、受け入れられた答えからのCodeProjectの例はひどいです。

それで、

そこにはもっとたくさんあります!

しかしここで?

待って、これが1つです。私は、より単純でテスト済みの方法を実装しました。最も重要なのは、の拡張機能をすぐに使用できるようにすることListViewです。

まあ、それは実際にはバインド可能ではありませんがINotifyCollectionChanged、基礎となる型が実装さINotifyPropertyChangedれているを実装するジェネリッククラスをサポートしますObservableCollection<T> where T : INotifyPropertyChanged

public class BindableListView : ListView
{
    private const string DataCategoryName = "Data";


    private INotifyCollectionChanged _collection;
    [Category(DataCategoryName)]
    public INotifyCollectionChanged Collection
    {
        get { return _collection; }
        set
        {
            if (_collection != null) _collection.CollectionChanged -= CollectionChanged;
            _collection = value;
            BindObject(_collection);
            if (_collection != null) _collection.CollectionChanged += CollectionChanged;
        }
    }

    private const bool DefaultDefaultBrowsableState = false;
    [Category(DataCategoryName)]
    [DefaultValue(DefaultDefaultBrowsableState)]
    public bool DefaultBrowsableState { get; set; } = DefaultDefaultBrowsableState;


    private void BindObject(object obj)
    {
        Clear();
        if (obj != null)
        {
            Columns.AddRange(obj.GetType().GetGenericArguments().FirstOrDefault()?.GetProperties().Where(p =>
            {
                return p.GetCustomAttributes(true).OfType<BrowsableAttribute>().FirstOrDefault()?.Browsable ?? DefaultBrowsableState;
            }).Select(p =>
            {
                return new ColumnHeader()
                {
                    Name = p.Name,
                    Text = p.GetCustomAttributes(true).OfType<DisplayNameAttribute>().FirstOrDefault()?.DisplayName ?? p.Name
                };
            }).ToArray());
            AddItems(obj as System.Collections.IEnumerable);
            AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
            AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
        }
    }

    private void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        switch (e.Action)
        {
            case NotifyCollectionChangedAction.Add:
                AddItems(e.NewItems);
                break;
            case NotifyCollectionChangedAction.Remove:
                foreach (var oldItem in e.OldItems)
                {
                    if (Items.OfType<ListViewItem>().FirstOrDefault(item => Equals(item.Tag, oldItem)) is ListViewItem itemToRemove)
                    {
                        UnregisterItem(oldItem);
                        Items.Remove(itemToRemove);
                    }
                }
                break;
            case NotifyCollectionChangedAction.Replace:
                if (e.OldItems.Count == e.NewItems.Count)
                {
                    var count = e.OldItems.Count;
                    for (var i = 0; i < count; i++)
                    {
                        var itemPair = new { Old = e.OldItems[i], New = e.NewItems[i] };
                        if (Items.OfType<ListViewItem>().FirstOrDefault(item => Equals(item.Tag, itemPair.Old)) is ListViewItem itemToReplace)
                        {
                            UnregisterItem(itemPair.Old);
                            RegisterItem(itemPair.New);
                            itemToReplace.Tag = itemPair.New;
                            foreach (ColumnHeader column in Columns)
                            {
                                itemToReplace.SubItems[column.Index].Text = itemPair.New.GetType().GetProperty(column.Name).GetValue(itemToReplace)?.ToString();
                            }
                        }
                    }
                }
                break;
            case NotifyCollectionChangedAction.Move:
                foreach (var oldItem in e.OldItems)
                {
                    if (Items.OfType<ListViewItem>().FirstOrDefault(item => Equals(item.Tag, oldItem)) is ListViewItem itemToMove)
                    {
                        Items.Remove(itemToMove);
                        Items.Insert(e.NewStartingIndex, itemToMove);
                    }
                }
                break;
            case NotifyCollectionChangedAction.Reset:
                Items.Clear();
                break;
            default:
                break;
        }
        AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
        AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
    }

    private void AddItems(System.Collections.IEnumerable items)
    {
        Items.AddRange((items ?? Enumerable.Empty<object>()).OfType<object>().Select(item =>
        {
            RegisterItem(item);
            return new ListViewItem(Columns.OfType<ColumnHeader>().Select(column =>
            {
                return item.GetType().GetProperty(column.Name).GetValue(item)?.ToString() ?? "";
            }).ToArray())
            {
                Tag = item
            };
        }).ToArray());
    }

    private void RegisterItem(object item)
    {
        if(item is INotifyPropertyChanged observableItem) observableItem.PropertyChanged += ObservableItem_PropertyChanged;
    }

    private void UnregisterItem(object item)
    {
        if (item is INotifyPropertyChanged observableItem) observableItem.PropertyChanged -= ObservableItem_PropertyChanged;
    }

    private void ObservableItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (Items.OfType<ListViewItem>().FirstOrDefault(itm => Equals(itm.Tag, sender)) is ListViewItem item)
        {
            if (Columns[e.PropertyName] is ColumnHeader column)
                item.SubItems[column.Index].Text = sender.GetType().GetProperty(e.PropertyName).GetValue(sender)?.ToString();
        }
    }
}

このクラスの使用について知っておくべきことは2つだけです。

  1. Out of the boxの主な違いは、タイプがListView呼ばれる新しいプロパティです。コレクションを操作することはできますが、お勧めしません。データソースとして提供しているオブジェクトはインターフェイスを実装しており、その基になるタイプもを実装していることが期待されます。プロパティをこれらのインターフェイスに制限しなかった理由は、プロパティを評価するときに追加のキャストを避けたかったためです。予期しない動作を回避するために、これらのインターフェイスのチェックをいつでも追加して、ArgumentExceptionをスローできます。CollectionINotifyCollectionChangedItemsIEnumerableINotifyPropertyChangedCollection

  2. DefaultBrowsableState指定されていないデータソースオブジェクトのプロパティを表す列のデフォルトの可視性を設定するという追加のプロパティがありBrowsableAttributeます。この理由は、 (などの)ListViewを使用する別のコントロールと一緒にこれを使用し、他のコントロールでの可視性を維持しながらリスト内の一部のプロパティを非表示にする場合です。次に、をfalseに設定し、リストに表示するすべてのプロパティに属性を追加できます。BrowsableAttributePropertyGridDefaultBrowsableState[Browsable(true)]

于 2018-07-30T23:15:19.460 に答える