DataGridView 绑定到字典 [英] DataGridView bound to a Dictionary

查看:33
本文介绍了DataGridView 绑定到字典的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含商品和价格的 Dictionary.这些项目是独一无二的,但会在应用程序的整个生命周期中慢慢添加和更新(也就是说,我事先不知道项目字符串).我想将此结构绑定到 DataGridView,以便我可以在我的表单上显示更新,例如:

字典_priceData = new Dictionary();BindingSource _bindingSource = new BindingSource();dataGridView1.DataSource = _bindingSource;_bindingSource.DataSource = _priceData;

但不能,因为 Dictionary 没有实现 IList(或 IListSourceIBindingListIBindingListView).

有没有办法做到这一点?我需要保留一个唯一的项目列表,但也要更新现有项目的价格,所以 Dictionary 是我认为的理想数据结构,但我找不到在我的表格.

<小时>

更新:

Marc 在下面的建议非常有效,但我仍然不确定如何在执行期间更新 DataGridView.

我有一个类级变量:

private DictionaryBindingList列表;

然后在Main()中实例化:

bList = new DictionaryBindingList(prices);dgv.DataSource = bList;

然后在程序执行期间如果有新条目添加到字典中:

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

我认为这会刷新 DataGridView.为什么不呢?

解决方案

Dictionary 有几个问题;第一个是(如您所见)它没有实现必要的 IList/IListSource.第二个是项目没有保证的顺序(实际上,没有索引器),使得通过索引(而不是通过键)进行随机访问是不可能的.

然而......它可能是可行的,有一些烟雾和镜子;类似于以下内容:

使用系统;使用 System.Collections.Generic;使用 System.ComponentModel;使用 System.Windows.Forms;静态类程序{[STAThread]静态无效主(){字典<字符串,十进制>价格 =新字典<字符串,十进制>();价格.Add("foo", 123.45M);price.Add("bar", 678.90M);Application.EnableVisualStyles();表格表格=新表格();DataGridView dgv = 新 DataGridView();dgv.Dock = DockStyle.Fill;form.Controls.Add(dgv);var bl = 价格.ToBindingList();dgv.DataSource = bl;Button btn = new Button();btn.Dock = DockStyle.Bottom;btn.Click += 委托{价格.添加(新随机().Next().ToString(), 0.1M);bl.Reset();};form.Controls.Add(btn);Application.Run(form);}public static DictionaryBindingListToBindingList(这个 IDictionary 数据){return new DictionaryBindingList(data);}公共密封类 Pair{私有只读 TKey 密钥;private readonly IDictionary数据;public Pair(TKey key, IDictionary data){this.key = 键;this.data = 数据;}公共 TKey 密钥 { 获取 { 返回密钥;} }公共 TValue 值{得到{T 值;data.TryGetValue(key, out value);返回值;}设置 { 数据 [键] = 值;}}}公共类 DictionaryBindingList: BindingList>{private readonly IDictionary数据;public DictionaryBindingList(IDictionary<TKey, TValue> data){this.data = 数据;重启();}公共无效重置(){bool oldRaise = RaiseListChangedEvents;RaiseListChangedEvents = false;尝试{清除();foreach(data.Keys 中的 TKey 键){添加(新对(键,数据));}}最后{RaiseListChangedEvents = oldRaise;重置绑定();}}}}

请注意,自定义扩展方法的使用完全是可选的,可以在 C# 2.0 等中删除,只需使用 new DictionaryBindingList(prices) 代替.>

I have a Dictionary that contains items and prices. The items are unique but slowly get added and updated through the lifetime of the application (that is, I don't know the item strings in advance). I would like to bind this structure to a DataGridView, so I can show updates on my Form, something like:

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

But cannot, since Dictionary does not implement IList (or IListSource, IBindingList, or IBindingListView).

Is there a way to achieve this? I need to keep a unique list of items, but also update the price for an existing item, so a Dictionary is the ideal data structure I think, but I cannot find a way to display the data on my Form.


Update:

Marc's suggestion below works very nicely, but I'm still not sure how to update the DataGridView during execution.

I have a class-level variable:

private DictionaryBindingList<string, decimal> bList; 

Then instantiate that in Main():

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

Then during program execution if a new entry is added to the dictionary:

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

I thought that would refresh the DataGridView. Why not?

解决方案

There are a couple of issues with Dictionary; the first is (as you've found) it doesn't implement the necessary IList/IListSource. The second is that there is no guaranteed order to the items (and indeed, no indexer), making random access by index (rather than by key) impossible.

However... it is probably doable with some some smoke and mirrors; something like below:

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

    }
}

Note that the use of a custom extension method is entirely optional, and can be removed in C# 2.0, etc. by just using new DictionaryBindingList<string,decimal>(prices) instead.

这篇关于DataGridView 绑定到字典的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆