2009-05-12 21 views
25

मेरे पास Dictionary है जिसमें आइटम और कीमतें हैं। आइटम अद्वितीय हैं लेकिन धीरे-धीरे एप्लिकेशन के जीवनकाल के माध्यम से जोड़ा और अद्यतन किया जाता है (यानी, मैं आइटम स्ट्रिंग को पहले से नहीं जानता)। मैं एक DataGridView को यह संरचना बाध्य करने के लिए चाहते हैं, इसलिए मैं अपने फार्म पर अपडेट, जैसे कुछ दिखा सकते हैं: Dictionary के बाद सेडेटाग्रिड व्यू एक शब्दकोश से बंधे

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

लेकिन नहीं कर सकते हैं, IList (या IListSource, IBindingList, या IBindingListView) को लागू नहीं करता है।

क्या यह हासिल करने का कोई तरीका है? मुझे वस्तुओं की एक अनूठी सूची रखना है, लेकिन मौजूदा आइटम के लिए कीमत भी अपडेट करना है, इसलिए Dictionary आदर्श डेटा संरचना है जो मुझे लगता है, लेकिन मुझे अपने फॉर्म पर डेटा प्रदर्शित करने का कोई तरीका नहीं मिल रहा है।


अद्यतन: नीचे

मार्क के सुझाव बहुत अच्छी तरह से काम करता है, लेकिन मैं अभी भी निष्पादन के दौरान DataGridView अपडेट करने का तरीका यकीन नहीं है।

private DictionaryBindingList<string, decimal> bList; 

तब का दृष्टांत कि Main() में:

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

तब प्रोग्राम निष्पादन करता है, तो एक नई प्रविष्टि शब्दकोश में जोड़ा जाता है के दौरान:

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

मैं एक वर्ग-स्तर चर है

मैंने सोचा कि डेटाग्रिड व्यू रीफ्रेश करेगा। क्यों नहीं?

+3

- "मूल्य" के लिए आप सामान्य रूप से दशमलव, दोगुना –

+0

अपनी टिप्पणी फिर से अपडेट किया गया नहीं इस्तेमाल करना चाहिए; जब तक हम <,> शब्दकोश उप-वर्गीकृत नहीं करते हैं, तो यह जानने का कोई आसान तरीका नहीं है कि आपने कोई आइटम जोड़ा है; इसके बजाए, मैंने एक रीसेट() विधि (उदाहरण के उपयोग के साथ) जोड़ा है जो सूची को फिर से पॉप्युलेट करता है। उदाहरण के लिए फॉर्म के निचले भाग में बटन देखें। –

उत्तर

21

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

    } 
} 

ध्यान दें कि एक कस्टम विस्तार पद्धति के उपयोग को पूरी तरह से वैकल्पिक है, और सी # 2.0, आदि में हटाया जा सकता है बस new DictionaryBindingList<string,decimal>(prices) उपयोग करने के बजाय द्वारा।

1

तो जैसे एक वर्ग बनाओ:

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

फिर उन्हें उस सूची में डालने, और सूची में DataBind:

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

फिर उनमें से एक सूची बनाते हैं।

एक तरफ, यदि आपके पास LINQ है, तो मुझे लगता है कि ToArray विधि है जो यह सब सरल करेगी ...

+0

सूचियाँ आसानी से विशिष्टता को लागू नहीं है, और ऐसा एक सूची संरचना है, जिसके कारण मैं एक शब्दकोश का उपयोग करना पसंद करते हैं में एक मूल्य के अद्यतन करने के लिए आसान नहीं है। हालांकि धन्यवाद। – WillH

47

या, LINQ में, यह अच्छा और जल्दी हो जाता है:

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

यही तो, bindable होना चाहिए कॉलम 'आइटम' और 'मूल्य' के लिए।

एक ग्रिड दृश्य में कोई डेटा स्रोत के रूप में उपयोग करने के लिए

, तो आप सिर्फ ToArray() के साथ पालन करने के लिए। Key और Value:

dataGridView1.DataSource = _priceDataArray.ToArray(); 
+7

+1 स्वीकार्य उत्तर से बहुत आसान और साफ है। – GuiSim

+2

+1 मेरे लिए काम किया! पाई के रूप में आसान (पीआई नहीं)! –

+0

पाई के रूप में आसान है? मैं वास्तव में प्राप्त करने के लिए सही पाई काफी मुश्किल लगता है: पी –

2

Dictionary<TKey, TValue> के लिए आप बाध्यकारी के लिए इन कीवर्ड का प्रयोग कर सकते हैं।

यहाँ ComboBox बाध्यकारी के लिए उदाहरण है, लेकिन यह DataGridView (Key या Value करने के लिए स्तंभ के लिए DataPropertyName सेट) के लिए शब्दकोश बाध्य करने के लिए संभव है।

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

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

मैं बात यह आपकी समस्या है जो मैं कुछ महीने पहले का सामना करना पड़ा हो जाएगी।

उपयोग dictionay आप आइटम की कीमतों को अपडेट करना चाहते हैं और केवल जब यू अपडेशन समाप्त करने और datagrid में दिखाना चाहते हैं तो बस ऐसा करने के रूप में। आशा है कि आप

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

में मदद मिलेगी शायद यह सबसे आसान तरीका है:

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 sortable होगा।

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

मार्क के सुझाव के लिए एक विस्तार के रूप में, मैं निम्नलिखित समाधान भी शब्दकोश से रन-टाइम हेरफेर की अनुमति देगा का प्रस्ताव करना चाहते हैं मौजूदा मानों को ओवरराइट करने के लिए मूल्य जोड़ें अनुमति दें। मैं एक 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)); 
    } 
के रूप में एक अलग रूप में
0

Bleiers DictionaryBindingList का ही विस्तार मैं करने के लिए एक छोटा सा परिवर्तन किए गए के रूप में:

संबंधित मुद्दे