C# Dictionary绑定datagridview

多线程的窗体程序,FormLoad的时候初始化了一个dictionary,然后各个线程里面很多地方会用到这个字典(每次添加或者删除操作的时候都lock了),现在我希望添加... 多线程的窗体程序,FormLoad的时候初始化了一个dictionary,然后各个线程里面很多地方会用到这个字典(每次添加或者删除操作的时候都lock了),现在我希望添加一个datagridview控件,可以在我每次变更dictionary数据的时候都刷新并显示现有的dictionary里面的数据(有个前提是我的dictionary里面的value是个内部类<string,InnerClass>)。
我希望在dictionary变更时至少能显示出来所有的key,最好是显示key的值和value这个内部类里面的某个属性。
如果我尝试在每个更改dictionary的线程里面加上this.dataGridView.DataSource = tmpMap.ToList<KeyValuePair<string, InnerClass>>();会报跨线程错误。
求大神帮忙!!
BindingSource q = new BindingSource();
q.DataSource = this.tmpMap.Values;
this.dataGridView1.DataSource = q;
这个在初始化map后定义只能动态显示map里面数据的count,不过应该是某位用BindingSource比较好的大神能轻松化解我的问题!我觉得思路应该就该是在这儿
展开
 我来答
makosharp
推荐于2018-05-17 · TA获得超过676个赞
知道小有建树答主
回答量:188
采纳率:100%
帮助的人:270万
展开全部

你诶,离胜利只差一步了哟。

跨线程错误我就不说了。

你想要的是深入绑定,即能够绑定到元素项的内部属性,甚至内部属性的内部属性。


先说一下绑定原理,不论是dgv还是BindingSource的DataSource绑定,都需要数据获取者指明DataPropertyName,这要求绑定数据源:首先继承了IEnumrable<T>等一系列接口,其次T包含有至少可get的属性才可使用绑定。对于你的情况,如果使用BindingSource直绑Dictionary,你的泛型T就是KeyValuePair<TKey,TValue>,其拥有公开的属性Key、Value、Count等等,此时数据获取者要填写的DataPropertyName可以是“Key”,“Value”,“Count”等等。


当然我们的需求是花样百出的,还是以你的情况为例,难免会出现Value和Key是自己定义的类型,此时如果不改DataPropertyName,你得到的只会是该类型的名称字符串。想要绑定到自定义类型的内部甚至更内部,有至少二种办法:


一、继承系统的BindingSource,overide及新增一些方法,可以让你在使用MyBindingSource mbs=new MyBindingSource(...)时直接指明你需要绑定的内部元素。这个过程开销很小但是编写有一定难度,需要在BindingSource内部重新维护一个合适你需要的绑定元素列表,并且需要处理绑定属性名的问题。此技术在大型项目中比较多用,好处是一次改完哪里都能用,而且可以支持双向绑定,允许反向编辑真实的数据源。有兴趣的话可以PM我我写个简单的给你。


二、修改提供给BindingSource或者dgv.DataSouce的数据源,也就是直接抽取内部属性出来构建一个新的绑定数据源。比较适合针对某个特定表的绑定,也是最容易实现的。当然,因为你是新构建了用于显示的数据源,只能支持单向绑定咯。

假定你的InnerClass是这样写的:

public class MyData
    {
        public string C1 { get; set; }
        public string C2 { get; set; }
        public string C3 { get; set; }
    }

如果需要用两列分别绑定Dictionary<string,MyData> dic的Key和MyData.C1,一行搞定:

dataGridView1.DataSource=(from i in dic select new{i.Key,i.MyData.C1}).ToList();
本质上就是遍历字典,把每一个键值对的Key和Value.C1都抽出来做成新字典然后转列表。
如果不熟悉Linq,也可以自己写一个抽取数据的小方法每次绑定前转换下。


嗯,刚才我同事也给了个很中二的办法:重写dataGridView。通过重写绑定相关的方法,可以让DataGridView能够识别形如"Value.C1"甚至“Value.C1.Length"这样的DataProperyName并且在绑定事件中能够通过反射查找Value内部是否存在C1属性,如果该属性存在则将其呈现。

这个可以一试,目测难度较大。


和同事小聊了下我又想起一个另类的办法- -|

我们知道不管你绑的是什么值,想在界面上看到都有一个转换过程。这里DataGridView描绘每个含绑定的单元格时都会把对应的数据源中的绑定元素的ToString()值拿来呈现。如果你只有一列需要绑定到InnerClass的C1属性,我们可以这样取巧:

首先dgv里的两列的DataPropertyName仍然写的是”Key“和"Value”,这样第二列绑到的是一个InnerClass对象,只不过其显示出来的ToString()是形如“MyNamespace.InnerClass”这样的类名字符串,如果我们重写InnerClass的ToString()方法呢?测试完发现一切OK。也只需要在InnerClass里加一句:

public override string ToString()
        {
            return C1;
        }


以上四种方案你挑着用吧。我相信如果你愿意投一点时间多从其他角度看问题的话,你会找到更多解决方案的。为了生活有时我们不得不只抓效率抓进度,但闲暇时做点小研究其实也是挺惬意的一个事情,并非是得不偿失~


还有什么问题可PM我。

追问
您简直是我的superstar,我差点就放弃了!
追答
加油!
刘禹永记
2014-02-08 · 超过25用户采纳过TA的回答
知道答主
回答量:155
采纳率:66%
帮助的人:47.7万
展开全部
报跨线程错误就使用invok或者是最简单的在this.dataGridView.DataSource = tmpMap.ToList<KeyValuePair<string, InnerClass>>()上面写上Control.CheckForIllegalCrossThreadCalls = false;
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式