C# - Convert IEnumerable to Dictionary<object,string> - c#

I am building a WPF UserControl. For this I implemented an ItemSource DependecyProperty like this:
private IEnumerable MisItems;
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(TextBoxAutoComplete), new PropertyMetadata(new PropertyChangedCallback(OnItemsSourcePropertyChanged)));
private static void OnItemsSourcePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var control = sender as TextBoxAutoComplete;
if (control != null)
control.OnItemsSourceChanged((IEnumerable)e.OldValue, (IEnumerable)e.NewValue);
}
private void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
{
MisItems = newValue;
// Remove handler for oldValue.CollectionChanged
var oldValueINotifyCollectionChanged = oldValue as INotifyCollectionChanged;
if (null != oldValueINotifyCollectionChanged)
{
oldValueINotifyCollectionChanged.CollectionChanged -= new NotifyCollectionChangedEventHandler(newValueINotifyCollectionChanged_CollectionChanged);
}
// Add handler for newValue.CollectionChanged (if possible)
var newValueINotifyCollectionChanged = newValue as INotifyCollectionChanged;
if (null != newValueINotifyCollectionChanged)
{
newValueINotifyCollectionChanged.CollectionChanged += new NotifyCollectionChangedEventHandler(newValueINotifyCollectionChanged_CollectionChanged);
}
}
void newValueINotifyCollectionChanged_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
//Do your stuff here.
}
The ItemsSource property is represented by a IEnumerable Object. Now I need to convert it to a Dictionary<object,string> in this function:
protected SearchResult DoSearch(string searchTerm)
{
if (!string.IsNullOrEmpty(searchTerm))
{
SearchResult sr = new SearchResult();
//var ItemsText = MisItems.GetType();
var p = (List<string>)MisItems;
/*sr.Results = ItemsText.Select((x, i) => new { x, i }).Where(x=>x.ToString().ToUpper().Contains(searchTerm.ToUpper()))
.ToDictionary(a => (object)a.i, a => a.x);*/
return sr;
}
else return new SearchResult();
}
How can i make the transition?
EDIT
More info:
My viewmodel has this property:
public List<EnumeradorWCFModel> Clientes { get; set; }
The data for this property is returned by a WCF service:
Clientes = _svc.Clientes_Enum(sTicket, "");
Then I wanted my UserControl to bind to this property. I create my control like this:
<autocomplete:TextBoxAutoComplete x:Name="Clientes" ItemsSource = "{Binding Path=Clientes}" DisplayMemberPath="Descripcion" Height="25"/>

[s]Alright. You posted a lot of code (that I personally think is unnecessary for what you're trying to do).
Let's slim it down.
You have an IEnumerable<string> to start out, correct? Good.
There's a ToDictionary() extension method in the LINQ libraries. Documentation is here.
So what you need to do is the following:
IEnumerable<string> myEnumerableOfStrings = new List<string>();
Dictionary<object, string> dictionary = myEnumerableOfStrings.ToDictionary(value => (object) value);
And here's a Fiddle as an example.
Alright, so we have just an IEnumerable with no strong type. (First I've ever seen or heard of this being done, but the same principles should apply.)
We need to create a local dictionary and iterate over that collection.
var myDictionary = new Dictionary<object, string>();
IEnumerable myCollection = new List<string>();
foreach(var item in myCollection)
{
// This might be fun if you get two of the same object in the collection.
// Since this key is based off of the results of the GetHashCode() object in the base object class.
myDictionary.Add((object) item, item.ToString());
}
Here's an example of that.

The above answer's example for ToDictionary extension, is a List of a primitive type (string), I would like to demonstrate converting a List of a complex type (class) into dictionary.
This overload is constructing a dictionary out of keySelector function and elementSelector function (docs):
public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector);
For example:
public class FooClass
{
public int FooKey { get; set; }
public string FooValue { get; set; }
}
IENumerable<FooClass> foos = new List<FooClass>();
IDictionary<int, string> dict = foos.ToDictionary<int, string>(x=>x.FooKey, x=>x.FooValue);

Related

Sort an observable collection of type T where T will change on run time (generics)

Hello I want to sort an ObservableCollection but I cant get access to its properties.
public static class CommonMethods<T>
{
public static ObservableCollection<T> Sort(ObservableCollection<T> array, string columnName, bool sort)
{
ObservableCollection<T> res = new ObservableCollection<T>();
res = res.OrderBy(r => r[""]) // This gives an error says cannot apply indexing with [] to an expression of type T.
return res;
}
}
The Calling code.
mlRegionDetails = CommonMethods<MLRegion>.Sort(mlRegionDetails, columnName, sort);
Please do tell me where I m going wrong.
Instead of passing the name of the property you want to order by, pass the selector function:
public static ObservableCollection<T> Sort(ObservableCollection<T> array, Func<T, object> columnSelector, bool sort)
{
ObservableCollection<T> res = new ObservableCollection<T>(array.OrderBy(columnSelector));
return res;
}
And call it using this:
mlRegionDetails = CommonMethods<MLRegion>.Sort(mlRegionDetails, x => x.SomeColumn, sort);
If you want to do this using strings, you will need to build the expression manually.
Note: the following code has not been tested as it was written here, it may need some change.
public static class CommonMethods<T>
{
private static readonly MethodInfo orderByMethod =
typeof(Enumerable).GetMethods().Single(method =>
method.Name == nameof(Enumerable.OrderBy) && method.GetParameters().Length == 2);
public static ObservableCollection<T> Sort(ObservableCollection<T> array, string columnName, bool sort)
{
var tType = typeof(T);
var parameter = Expression.Parameter(tType);
Expression member = Expression.Property(parameter, columnName);
var lambda = Expression.Lambda(member, paramter);
var genericMethod = orderByMethod.MakeGenericMethod(tType, member.Type);
var orderedData = genericMethod.Invoke(null, new object[] { array, lambda }) as IEnumerable<T>;
return new ObservableCollection<T>(orderedData);
}
}
At last i found an alternate solution to the problem. I create a temp var then convert that ObservableCollection to AsEnumerable and ordering it by the Key passed to it.
Creating key part credit goes to #Camilo Terevinto
public static class CommonMethods
{
public static ObservableCollection<T> sort<T>(ObservableCollection<T> array, Func<T, object> key)
{
var res = array.AsEnumerable().OrderByDescending(key); ;
ObservableCollection<T> temp = new ObservableCollection<T>(res);
return temp;
}
}

BindingList<T> equivalent for Dictionary in WinForms [duplicate]

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?
Or, in LINQ, it's nice and quick:
var _priceDataArray = from row in _priceData select new { Item = row.Key, Price = row.Value };
That should then be bindable, to the columns 'Item' and 'Price'.
To use it as a data source in a grid view, you just have to follow it with ToArray().
dataGridView1.DataSource = _priceDataArray.ToArray();
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.
Probably this is easiest way:
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);
}
If use this you datagridview shall be sortable.
i thing this will resolve your problem which i faced few months ago.
use dictionay as you want to update item prices and just when u finish updation and want to show in datagrid just do this. hope will help you
Grd.DataSource=null;
Grd.DataSource = Dictionary.Values.ToList();
For Dictionary<TKey, TValue> you can use these keywords for binding: Key and Value.
Here is example for ComboBox Binding, but it's possible to bind dictionary to DataGridView (set DataPropertyName for column to Key or Value).
ComboBox1.DataSource =
new BindingSource(Pricelevel.GetPricelevels(), null); // GetPricelevels() returns Dictionary<string, string>
ComboBox1.ValueMember = "Key";
ComboBox1.DisplayMember = "Value";
Make a class like so:
class MyRow
{
public string key;
public double value;
public string Key {get {return key;}}
public string Value {get {return value;}}
}
Then make a list of them:
List<MyRow> rows = new List<MyRow>();
Then insert them into that list, and databind to the list.
As an aside, if you've got LINQ, I think there's a ToArray method that'll simplify all this...
As an extension to Marc's suggestion, I would like to propose the following solution that will also allow run-time manipulation of the dictionary:
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);
}
}
As an extension of Bleiers DictionaryBindingList I made a small alteration to allow Add values to overwrite existing values.
I'm using the method with a WAMP websocket so it would allow me to keep values updated just by updating the collection, next I need to tie events onto the values.
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));
}

Convert a generic IEnumerable<T> to IEnumerable<KeyValuePair> (C#)

In the following code, I need to explicitly mention CountryId and CountryName but I would like to avoid that and trying to create a generic method.
public struct KeyValueStruct
{
public int Key { get; set; }
public string Value { get; set; }
}
private static IEnumerable<KeyValueStruct> ConvertPocoToKeyValueList(IEnumerable<CountryPoco> list)
{
var result = new List<KeyValueStruct>();
if (list != null)
{
foreach (var item in list)
{
result.Add(new KeyValueStruct()
{
Key = item.CountryId,
Value = item.CountryName
});
}
}
return result;
}
I know from the list that first property is always integer (which is CountryId in this example) and second property would be String.
I was thinking to implement using Generics but am not sure is this the best approach, see my proposed code (it's not working though).
private static IEnumerable<KeyValueStruct> ConvertPocoToKeyValueList<T>(T list)
{
var result = new List<KeyValueStruct>();
if (list != null)
{
foreach (var item in list)
{
result.Add(new KeyValueStruct()
{
Key = item.CountryId,
Value = item.CountryName
});
}
}
return result;
}
If you have a better idea to achieve the same result, then please propose.
You can make that generic by passing the properties to be used as Key and value. I think using the generic struct named KeyValuePair<Tkey, TValue> is better than reinventing the wheel yourself:
private static IEnumerable<KeyValuePair<Tkey, TValue>>
ConvertPocoToKeyValueList<TSource, Tkey, TValue>
(IEnumerable<TSource> list,
Func<TSource, Tkey> keySelector,
Func<TSource, TValue> valueSelector)
{
return list.Select(item => new KeyValuePair<Tkey, TValue>
(keySelector(item), valueSelector(item)));
}
Usage:
var result = ConvertPocoToKeyValueList(list, x=> x.CountryId, x=> x.CountryName);
You can even do that without using this generic method by using directly:
var result = list.Select(item => new KeyValuePair<Tkey, TValue>
(item.CountryId, item.CountryName));

c#: Call boxed delegate

In my project I need to transform data between several classes so I created a class DataMapper that is used for strong-typed mapping of properties from two different classes. When properties in the pair need to be modified I store two delegates (converters) for this purpose.
Then the DataMapper has two methods Update(T source, S target) and Update(S source, T target) that use these mappings to provide the tranformation.
public class DataMapper<TSourceType, TTargetType> : IDataUpdater<TSourceType, TTargetType> {
private readonly IDictionary<PropertyInfo, PropertyInfo> _sourceToTargetMap = new Dictionary<PropertyInfo, PropertyInfo>();
private readonly IDictionary<PropertyInfo, object> _converters = new Dictionary<PropertyInfo, object>();
public DataMapper<TSourceType, TTargetType> Map<TSourceValue, TTargetValue>(
Expression<Func<TSourceType, TSourceValue>> sourcePropExpr,
Expression<Func<TTargetType, TTargetValue>> targetPropExpr)
{
_sourceToTargetMap.Add(sourcePropExpr.AsPropertyInfo(), targetPropExpr.AsPropertyInfo());
return this;
}
public DataMapper<TSourceType, TTargetType> Map<TSourceValue, TTargetValue>(
Expression<Func<TSourceType, TSourceValue>> sourcePropExpr,
Expression<Func<TTargetType, TTargetValue>> targetPropExpr,
Func<TSourceValue, TTargetValue> sourceToTargetConverter,
Func<TTargetValue, TSourceValue> targetToSourceConverter)
{
_sourceToTargetMap.Add(sourcePropExpr.AsPropertyInfo(), targetPropExpr.AsPropertyInfo());
_converters.Add(sourcePropExpr.AsPropertyInfo(), sourceToTargetConverter);
_converters.Add(targetPropExpr.AsPropertyInfo(), targetToSourceConverter);
return this;
}
public void Update(TSourceType source, TTargetType target) {
foreach (var keyValuePair in _sourceToTargetMap) {
var sourceProp = keyValuePair.Key;
var targetProp = keyValuePair.Value;
Update(source, target, sourceProp, targetProp);
}
}
public void Update(TTargetType source, TSourceType target) {
foreach (var keyValuePair in _sourceToTargetMap) {
var sourceProp = keyValuePair.Value;
var targetProp = keyValuePair.Key;
Update(source, target, sourceProp, targetProp);
}
}
private void Update(
object source,
object target,
PropertyInfo sourceProperty,
PropertyInfo targetProperty)
{
var sourceValue = sourceProperty.GetValue(source);
if (_converters.ContainsKey(sourceProperty)) {
sourceValue = typeof(InvokeHelper<,>)
.MakeGenericType(sourceProperty.PropertyType, targetProperty.PropertyType)
.InvokeMember("Call", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, new[] { _converters[sourceProperty], sourceValue });
}
targetProperty.SetValue(target, sourceValue);
}
}
Here is the usage:
public SomeClass {
private static readonly IDataUpdater<SomeClass, SomeOtherClass> _dataMapper = new DataMapper<SomeClass, SomeOtherClass>()
.Map(x => x.PropertyA, y => y.PropertyAA)
.Map(x => x.PropertyB, y => y.PropertyBB, x => Helper.Encrypt(x), y => Helper.Decrypt(y));
public string PropertyA { get; set; }
public string PropertyB { get; set; }
public void LoadFrom(SomeOtherClass source) {
_dataMapper.Update(source, this);
}
public void SaveTo(SomeOtherClass target) {
_dataMapper.Update(this, target);
}
}
You can see in class DataHelper in the last overload of method Update that when I want to call the stored converter function, I use helper class InvokeHelper, because I didn't found other way how to call boxed delegate Func. Code for class InvokeHelper is simple - just single static method:
public static class InvokeHelper<TSource, TTarget> {
public static TTarget Call(Func<TSource, TTarget> converter, TSource source) {
return converter(source);
}
}
Is there a way how to do it without reflection? I need to optimalize these transformations for speed.
Thanks.
You can use Delegate.DynamicInvoke to invoke the delegate. Or, use dynamic:
((dynamic)(Delegate)_converters[sourceProperty])(sourceValue);
The (Delegate) cast is not necessary. It's for documentation and runtime assertion purposes. Leave it out if you don't like it.
Actually, you better use delegate instead of object in the dictionary.
If it were me, I would use a little meta-coding with expressions to create a list of compiled and strongly typed delegates. When you call the Update method, you can go through each Action in the list and update the destination from the source.
No reflection and all of the compiling and such is done once, ahead of the Update call.
public class DataMapper<TSourceType, TTargetType> : IDataUpdater<TSourceType, TTargetType>
{
List<Action<TSourceType, TTargetType>> _mappers = new List<Action<TSourceType, TTargetType>>();
DataMapper<TTargetType, TSourceType> _reverseMapper;
public DataMapper() : this(false) { }
public DataMapper(bool isReverse)
{
if (!isReverse)
{
_reverseMapper = new DataMapper<TTargetType, TSourceType>(isReverse: true);
}
}
public DataMapper<TSourceType, TTargetType> Map<TSourceValue, TTargetValue>(
Expression<Func<TSourceType, TSourceValue>> sourcePropExpr,
Expression<Func<TTargetType, TTargetValue>> targetPropExpr)
{
var mapExpression = Expression.Assign(targetPropExpr.Body, sourcePropExpr.Body);
_mappers.Add(
Expression.Lambda<Action<TSourceType, TTargetType>>(
mapExpression,
sourcePropExpr.Parameters[0],
targetPropExpr.Parameters[0])
.Compile());
if (_reverseMapper != null) _reverseMapper.Map(targetPropExpr, sourcePropExpr);
return this;
}
public DataMapper<TSourceType, TTargetType> Map<TSourceValue, TTargetValue>(
Expression<Func<TSourceType, TSourceValue>> sourcePropExpr,
Expression<Func<TTargetType, TTargetValue>> targetPropExpr,
Func<TSourceValue, TTargetValue> sourceToTargetConverter,
Func<TTargetValue, TSourceValue> targetToSourceConverter)
{
var convertedSourceExpression = Expression.Invoke(Expression.Constant(sourceToTargetConverter), sourcePropExpr.Body);
var mapExpression = Expression.Assign(targetPropExpr.Body, convertedSourceExpression);
_mappers.Add(
Expression.Lambda<Action<TSourceType, TTargetType>>(
mapExpression,
sourcePropExpr.Parameters[0],
targetPropExpr.Parameters[0])
.Compile());
if (_reverseMapper != null) _reverseMapper.Map(targetPropExpr, sourcePropExpr, targetToSourceConverter, sourceToTargetConverter);
return this;
}
public void Update(TSourceType source, TTargetType target)
{
foreach (var mapper in _mappers)
{
mapper(source, target);
}
}
public void Update(TTargetType source, TSourceType target)
{
if (_reverseMapper != null)
{
_reverseMapper.Update(source, target);
}
else
{
throw new Exception("Reverse mapper is null. Did you reverse twice?");
};
}
}
The expression is built by taking the expressions that are passed in and using them as parts for the new expression.
Say you called .Map(x => x.PropertyA, y => y.PropertyAA). You now have 2 expressions each with a parameter x and y and each with a body x.PropertyA and y.PropertyAA.
Now you want to re-assemble these expression parts into an assignment expression like y.PropertyAA = x.PropertyA. This is done in the line var mapExpression = Expression.Assign(targetPropExpr.Body, sourcePropExpr.Body); which gives you an expected expression.
Now when you call Expression.Lambda, you are incorporating the parameters (x,y) into a new expression that looks like (x,y) = > y.PropertyAA = x.PropertyA.
Before you can execute this, you need to compile it, hence the .Compile(). But since you only need to compile this once for any given map, you can compile and store the result. The uncompiled expression is of type Expression<Action<TSourceType,TTargetType>> and after it is compiled the resulting type is Action<TSourceType,TTargetType>

DataGridView bound to a Dictionary

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?
Or, in LINQ, it's nice and quick:
var _priceDataArray = from row in _priceData select new { Item = row.Key, Price = row.Value };
That should then be bindable, to the columns 'Item' and 'Price'.
To use it as a data source in a grid view, you just have to follow it with ToArray().
dataGridView1.DataSource = _priceDataArray.ToArray();
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.
Probably this is easiest way:
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);
}
If use this you datagridview shall be sortable.
i thing this will resolve your problem which i faced few months ago.
use dictionay as you want to update item prices and just when u finish updation and want to show in datagrid just do this. hope will help you
Grd.DataSource=null;
Grd.DataSource = Dictionary.Values.ToList();
For Dictionary<TKey, TValue> you can use these keywords for binding: Key and Value.
Here is example for ComboBox Binding, but it's possible to bind dictionary to DataGridView (set DataPropertyName for column to Key or Value).
ComboBox1.DataSource =
new BindingSource(Pricelevel.GetPricelevels(), null); // GetPricelevels() returns Dictionary<string, string>
ComboBox1.ValueMember = "Key";
ComboBox1.DisplayMember = "Value";
Make a class like so:
class MyRow
{
public string key;
public double value;
public string Key {get {return key;}}
public string Value {get {return value;}}
}
Then make a list of them:
List<MyRow> rows = new List<MyRow>();
Then insert them into that list, and databind to the list.
As an aside, if you've got LINQ, I think there's a ToArray method that'll simplify all this...
As an extension to Marc's suggestion, I would like to propose the following solution that will also allow run-time manipulation of the dictionary:
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);
}
}
As an extension of Bleiers DictionaryBindingList I made a small alteration to allow Add values to overwrite existing values.
I'm using the method with a WAMP websocket so it would allow me to keep values updated just by updating the collection, next I need to tie events onto the values.
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));
}

Categories