簡體   English   中英

綁定到字典的DataGridView

[英]DataGridView bound to a Dictionary

我有一本包含物品和價格的Dictionary 這些項目是唯一的,但會在應用程序的整個生命周期內慢慢添加和更新(也就是說,我事先不知道這些項目字符串)。 我想將此結構綁定到DataGridView,以便可以在Form上顯示更新,例如:

Dictionary<string, double> _priceData = new Dictionary<string, double>();
BindingSource _bindingSource = new BindingSource();
dataGridView1.DataSource = _bindingSource;
_bindingSource.DataSource = _priceData;

但是不能,因為Dictionary不實現IList (或IListSourceIBindingListIBindingListView )。

有沒有辦法做到這一點? 我需要保留唯一的商品列表,還需要更新現有商品的價格,因此我認為Dictionary是理想的數據結構,但是我找不到在表單上顯示數據的方法。


更新:

Marc的以下建議非常有效,但是我仍然不確定執行期間如何更新DataGridView。

我有一個類級變量:

private DictionaryBindingList<string, decimal> bList; 

然后在Main()實例化它:

bList = new DictionaryBindingList<string,decimal>(prices); 
dgv.DataSource = bList; 

然后在程序執行過程中,是否將新條目添加到字典中:

prices.Add("foobar", 234.56M); bList.ResetBindings(); 

我以為那會刷新DataGridView。 為什么不?

或者,在LINQ中,它又好又快:

var _priceDataArray = from row in _priceData select new { Item = row.Key, Price = row.Value };

然后應該可以綁定到“項目”和“價格”列。

要將其用作網格視圖中的數據源,只需跟隨ToArray()

dataGridView1.DataSource = _priceDataArray.ToArray();

Dictionary有兩個問題; 第一個是(如您所發現的)它沒有實現必要的IList / IListSource 第二個原因是,沒有對項目的保證順序(實際上,也沒有索引器),這使得無法通過索引(而不是鍵)進行隨機訪問。

但是...可能有些煙和鏡子是可行的。 如下所示:

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

static class Program
{
    [STAThread]
    static void Main()
    {
        Dictionary<string, decimal> prices =
            new Dictionary<string, decimal>();
        prices.Add("foo", 123.45M);
        prices.Add("bar", 678.90M);

        Application.EnableVisualStyles();
        Form form = new Form();
        DataGridView dgv = new DataGridView();
        dgv.Dock = DockStyle.Fill;
        form.Controls.Add(dgv);
        var bl = prices.ToBindingList();
        dgv.DataSource = bl;
        Button btn = new Button();
        btn.Dock = DockStyle.Bottom;
        btn.Click += delegate
        {
            prices.Add(new Random().Next().ToString(), 0.1M);
            bl.Reset();
        };
        form.Controls.Add(btn);
        Application.Run(form);
    }

    public static DictionaryBindingList<TKey, TValue>
        ToBindingList<TKey, TValue>(this IDictionary<TKey, TValue> data)
    {
        return new DictionaryBindingList<TKey, TValue>(data);
    }
    public sealed class Pair<TKey, TValue>
    {
        private readonly TKey key;
        private readonly IDictionary<TKey, TValue> data;
        public Pair(TKey key, IDictionary<TKey, TValue> data)
        {
            this.key = key;
            this.data = data;
        }
        public TKey Key { get { return key; } }
        public TValue Value
        {
            get
            {
                TValue value;
                data.TryGetValue(key, out value);
                return value;
            }
            set { data[key] = value; }
        }
    }
    public class DictionaryBindingList<TKey, TValue>
        : BindingList<Pair<TKey, TValue>>
    {
        private readonly IDictionary<TKey, TValue> data;
        public DictionaryBindingList(IDictionary<TKey, TValue> data)
        {
            this.data = data;
            Reset();
        }
        public void Reset()
        {
            bool oldRaise = RaiseListChangedEvents;
            RaiseListChangedEvents = false;
            try
            {
                Clear();
                foreach (TKey key in data.Keys)
                {
                    Add(new Pair<TKey, TValue>(key, data));
                }
            }
            finally
            {
                RaiseListChangedEvents = oldRaise;
                ResetBindings();
            }
        }

    }
}

請注意,自定義擴展方法的使用完全是可選的,並且可以在C#2.0等中刪除,只需使用new DictionaryBindingList<string,decimal>(prices)

可能這是最簡單的方法:

Dictionary<char, double> myList = new Dictionary<char, double>();

        dataGridView1.Columns.Add("Key", "KEY");
        dataGridView1.Columns.Add("Values", "VALUES");

        foreach (KeyValuePair<char,double> item in , myList)
        {
            dataGridView1.Rows.Add(item.Key, item.Value);
        }

如果使用這個,則datagridview應該是可排序的。

我認為這可以解決您幾個月前遇到的問題。

使用dictionay來更新商品價格,並且當您完成更新並想在datagrid中顯示時,只需執行此操作即可。 希望對你有幫助

Grd.DataSource=null;
Grd.DataSource = Dictionary.Values.ToList();

對於Dictionary<TKey, TValue>您可以使用以下關鍵字進行綁定: KeyValue

這是ComboBox綁定的示例,但是可以將字典綁定到DataGridView (將列的DataPropertyName設置為KeyValue )。

    ComboBox1.DataSource =
        new BindingSource(Pricelevel.GetPricelevels(), null); // GetPricelevels() returns Dictionary<string, string>

    ComboBox1.ValueMember = "Key";
    ComboBox1.DisplayMember = "Value";

作為Marc建議的擴展,我想提出以下解決方案,該解決方案還允許對字典進行運行時操作:

public class DictionaryBindingList<TKey, TValue> : BindingList<KeyValuePair<TKey, TValue>>
{
    public readonly IDictionary<TKey, TValue> Dictionary;
    public DictionaryBindingList()
    {
        Dictionary = new Dictionary<TKey, TValue>();
    }

    public void Add(TKey key, TValue value)
    {
        base.Add(new KeyValuePair<TKey, TValue>(key, value));
    }

    public void Remove(TKey key)
    {
        var item = this.First(x => x.Key.Equals(key));
        base.Remove(item);
    }

    protected override void InsertItem(int index, KeyValuePair<TKey, TValue> item)
    {
        Dictionary.Add(item.Key, item.Value);
        base.InsertItem(index, item);
    }

    protected override void RemoveItem(int index)
    {
        Dictionary.Remove(this[index].Key);
        base.RemoveItem(index);
    }

    public int IndexOf(TKey key)
    {
        var item = this.FirstOrDefault(x => x.Key.Equals(key));
        return item.Equals(null) ? -1 : base.IndexOf(item);
    }
}

像這樣上課:

class MyRow
{
    public string key;
    public double value;
    public string Key {get {return key;}}
    public string Value {get {return value;}}
}

然后列出它們:

List<MyRow> rows = new List<MyRow>();

然后將它們插入該列表,並與該列表進行數據綁定。

ToArray說一句,如果您有LINQ,我認為有一個ToArray方法可以簡化所有步驟。

作為Bleiers DictionaryBindingList的擴展,我做了一個小改動,以允許Add值覆蓋現有值。 我在WAMP websocket中使用了該方法,因此它可以讓我僅通過更新集合來保持值的更新,接下來我需要將事件綁定到值上。

    public void Add(TKey key, TValue value)
    {
        if (Dictionary.ContainsKey(key))
        {
            int position = IndexOf(key);
            Dictionary.Remove(key);
            Remove(key);
            InsertItem(position, new KeyValuePair<TKey, TValue>(key, value));
            return;
        }
        base.Add(new KeyValuePair<TKey, TValue>(key, value));
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM