how to bind datasource to List<Dictionary<string, string>>? - c#

I have a class that stores a list of dictionary entries. I want bind that to a datasource for gridview from codebehind.
Code for dictionary type of , representing ErrorMessage and failed field.
public partial class FailedFields
{
private Dictionary<string, string> Code_Error = new Dictionary<string, string>();
public void AddFailedField(string field, string message)
{
Code_Error.Add(field, message);
}
public Dictionary<string, string> GetFailedFields()
{
return Code_Error;
}
}
Code for List of Dictionary entries.
public partial class ErrorFieldsList
{
private static List<Order.FailedFields> ErrorList = new List<Slab.FailedFields>();
public void AddErrorField(Order.FailedFields errs)
{
ErrorList.Add(errs);
}
public List<Order.FailedFields> GetErrorMessages()
{
return ErrorList;
}
}
Running in Visual Studio debug mode, i can see the list has the error list, but i cannot get it to display in the gridview. Bellow is one of the many ways (the one that makes most sense) i tried to set the list as a datasource.
ErrorBoxGridView.DataSource = FailedRecords.GetErrorMessages(). ;
ErrorBoxGridView.DataBind();
Any idea where i am going wrong ?
Also, i don't want to specify a datasource in the aspx page because i only want to display this when the error occurs.
If interested why i am doing this to store error messages, have a look at this:link 1
Solved Here Related Question
I will document a complete project when i finish on the wiki.

This can not be done I think. What I'd do is:
Instead of using Dictionary<string, string> define a class that contains two public properties for field and message
Create an object data source for that class (using Visual Studios "Data Sources" window)
Have GetErrorMessages() return List<ErrorClass> instead of Dictionary
Assign that list to the binding source.
EDIT
This is to clarify things according to the latest comments. What you need is one class that contains the information for one error. For example:
public class ErrorInfo
{
public string Field { get { ... } }
public string Message { get { ... } }
}
After that you place a BindingSource on your form and (in code) set its DataSource property to a list of error message classes. For example:
private List<ErrorInfo> errorList = new List<ErrorInfo>();
errorList.Add(new ErrorInfo() { ... });
errorList.Add(new ErrorInfo() { ... });
errorList.Add(new ErrorInfo() { ... });
bindingSource.DataSource = errorList;
The data grid view is bound to the BindingSource. You should see data now. You can manually create columns and set them to the respective property names of your ErrorInfo class as well, but then you'd have to set dataGridView.AutoCreateColumns to false somewhere in your code.

Databind List of Dictionnary into a GridView
List<Dictionary<string,string>> resultSet = SOME List of Dictionaries...
DataGridView.DataSource = resultSet.Select(x => new {
fieldOne = x["key1"], fieldTwo = x["key2"]
}).ToList();
DataGridView.DataBind();
Now u can Bind fieldOne and fieldTwo in the DataGridView element...
Kindly check the Link for the precise ans...
Thanks

.NET provides a handy KeyValuePair<(Of <(TKey, TValue>)>) structure, that can be used in cases like this. That way you don't have to define your own class. HTH.

Or you could bind to the Value & Key properties of each Dictionary item:
ErrorBoxGridView.DataSource = FailedRecords.GetErrorMessages();
ErrorBoxGridView.DataTextField = "Value";
ErrorBoxGridView.DataValueField = "Key";
ErrorBoxGridView.DataBind();

Related

Validating a large dictionary of set strings with user input

I have a profile form that has a lot of user selections and I am sort of stumped on a good approach to validate what the user enters, when passing validation mapping those values to object properties.
For example I have a dictionary
public static Dictionary<string, string> objProfileSelections = new Dictionary<string, string>();
public static string MySelections(string key)
{
objProfileSelections.Add("1", "No Answer");
objProfileSelections.Add("3", "Less Than $25,000");
objProfileSelections.Add("5", "$35,000 to $50,000");
objProfileSelections.Add("7", "$50,000 to $75,000");
objProfileSelections.Add("9", "$75,000 to $100,000");
objProfileSelections.Add("11", "$100,000 to $150,000");
objProfileSelections.Add("13", "$150,000+");
objProfileSelections.Add("2", "No Answer");
objProfileSelections.Add("4", "Less Than $25,000");
objProfileSelections.Add("6", "$35,000 to $50,000");
objProfileSelections.Add("8", "$50,000 to $75,000");
objProfileSelections.Add("10", "$75,000 to $100,000");
objProfileSelections.Add("12", "$100,000 to $150,000");
objProfileSelections.Add("14", "$150,000+");
string item;
objProfileSelections.TryGetValue(key, out item);
return item;
}
Id like to pass in a list of key strings from the user and pass those items to populate an object. The issue is I don't know how to code it so it know which property to go to, I looked at reflection, but I couldn't find any examples that have a set dictionary of values that map to property names.
To make a bit more clear, when a user makes a selection it passes as a parameter in the dictionary, and the dictionary outputs the items. From key 1 comes value No Answer. If the user selected all the check boxes it would be value - (1,3,5,7,9,11,13). I need to extract those values when there is a matching key to a matching property. For example if the user clicks 1,5 but leaves the rest unchecked, how do I know which selections the user made? How do I get the program to know which property to populate based on the results?
*edit
some properties I would like it mapped to
public string MyAnnualIncome{ get; set; }
public List<string> InterestAnnualIncome{ get; set; }
So the first property would be taking one value, and the second property would be taking multiple values.
When a key matches a value comes out the dictionary, I would need the odd values going to MyAnnualIncome and the even values going to InterestAnnualIncome.
so no one is confused odd and even keys are set up for a purpose, odd numbers belonging to a certain group of properties and the even ones belonging to another based on the html selections (even being my selections, odd being what I am interested in)
*Update
Is there a way I can possibly use the keys like 1,3,5 and pass that into a list using the except extension method. Then take the results and use a method to convert the values from enumerated data types to strings?
Hopefully I understood your question.
I would add a small helper class (this is a solution which doesn't use reflection, but uses delegates instead):
public class PropertyModifier
{
private string text;
private Func<string> modifier;
public PropertyModifier(Func<string> modifier)
{
this.modifier = modifier;
}
public PropertyModifier With(string text)
{
PropertyModifier newModifier = new PropertyModifier(modifier);
newModifier.text = text;
return newModifier;
}
public void Modify()
{
modifier(Text);
}
}
Then I would rewrite your code and have the dictionary map to this class instead to string:
public static Dictionary<string, PropertyModifier> objProfileSelections = new Dictionary<string, PropertyModifier>();
public static MyUserProfile Profile; //Assuming this is the object you want to modify
public static string MySelections(string key)
{
PropertyModifier myIncome = new PropertyModifier(text => Profile.MyAnnualIncome = text);
PropertyModifier interestIncome = new PropertyModifier(text => Profile.InterestAnnualIncome.Add(text));
objProfileSelections.Add("1", myIncome.With("No Answer"));
objProfileSelections.Add("3", myIncome.With("Less Than $25,000"));
...
objProfileSelections.Add("2", interestIncome.With("No Answer"));
objProfileSelections.Add("4", interestIncome.With("Less Than $25,000"));
...
}
Then, when processing the user's selection, get the mapped PropertyModifier from the dictionary and call its Modify method.
I tried in this code to illustrate how you can modify the properties of the different classes that may compose a profile. Modifications are done by reflection only, i.e. just providing the class name, the property name that will vary in each class and the string value to be assigned to the property.
Not sure that it fits your expectations :(
Profile profile = new Profile() ;
profile.SetPropertyValue("hair","color","brown") ;
internal class Profile()
{
private Hair hair_ = new Hair();
private Job job_ = new Job ();
internal Hair hair { get { return hair_ ; } }
internal Job job { get { return job_ ; } }
private void SetPropertyValue(string profileItemName, string ItemPropertyName, string value)
{ // it is assumed that the different items (hair or job) of the Profile are accessible
// with a a property
// first find the Item object, i.e. hair or job
object itemObj = this.GetType().GetProperty(profileItemName).GetValue(this,null);
// assign to Item property the input value, e.g. hair.color=Brown
itemObj.GetType().GetProperty(ItemPropertyName).SetValue(itemObj, value, null);
}
}
internal class Hair()
{
private string color_ ;
private string style_ ;
internal string color { get { return color_ ; } set {color_ = value ; } }
internal string style { get { return style_ ; } set {style_ = value ; } }
}

DataBind Generic "Dynamic" Class to GridView

How can I databind a GridView to a class like the following?
public class GenericEntity
{
private readonly Dictionary<string, object> properties = new Dictionary<string, object>();
public object this[string propertyName]
{
get
{
if (properties.ContainsKey(propertyName))
return properties[propertyName];
else
return null;
}
set
{
if (value == null)
properties.Remove(propertyName);
else
properties[propertyName] = value;
}
}
}
This class may have any number of properties and there is no way to know any of them on compile time, only on runtime, this is because the properties map directly to columns of a result set from the BD.
How can I databind a list of this GenericEntity class to a GridView? I tried the following but I get the exception of 'class does not contain a property with name...'
var newColumn = new BoundField();
newColumn.HeaderText = resultsetDescription.FieldDisplayName;
newColumn.DataField = resultsetDescription.FieldName;
myGridView.Columns.Add(newColumn);
myGridView.DataSource = GetListOfGenericEntities(args);
myGridView.DataBind();
EDIT:
I have implemented the approach mentioned in this SO answer but it still throws the property exception...
If all you need is to bind this generic list to a GridView I would convert this to a DataTable, and then bind the DataTable to the GridView. Have you checked Anonymous Types? You can create a Generic List of Anonymous Types and then bind it to your GridView as well.
Good luck!

How to add to array in C# dynamically

In response to this answer... Access MVC3 Model properties from Javascript in the View I'd like to know how I can construct the data for the view model in that example dynamically, without having to hardcode. i.e. I'd like to be able to do model.Values.Add(...)
There's already a dynamic object that you can add your values to...it's called the ViewBag.
There's no point in trying to roll your own since you're already losing the benefits of the strong typed model.
You can have a model that looks like this
public class MyViewModel()
{
private readonly List<string> _values = new List<string>();
public string[] Values { get { return _values.ToArray(); } }
public void AddValue(string value)
{
_values.Add(value);
}
}

How come checkedlistbox does not have datasource ? how to bind to a list of values?

I am developing a Winform and I need a checkedlistbox. I have the values stored in an object which has a List property:
public static class Fields
{
public static IList<string> FieldList { get; set; }
static Fields()
{ ...//populate FieldList }
}
Now I would like my CheckedListBox to use Fields.FieldList as datasource. After searching online I found I needed to set
//in myForm_Load
mycheckedListBox.DataSource = Fields.FieldList;
But myCheckedListBox does not have a DataSource property.
Am I missing something here?
Per the documentation, it should have this property... http://msdn.microsoft.com/en-us/library/system.windows.forms.checkedlistbox.datasource(VS.90).aspx
However, I also had the same issue on a project a while back, and used this CodeProject article to code the solution in the one project where I needed this feature.
Researching a bit more, I did find this:
http://connect.microsoft.com/VisualStudio/feedback/details/115199/checkedlistbox-datasource-displaymember-valuemember-are-hidden
Edit: The above link is no longer working, but the exceprt below is from the article that once resided there.
Posted by Microsoft on 5/30/2005 at 10:28 AM
Thanks for the feedback
however this is by design. We do not support data binding on the
CheckedListBox control. These properties are inherited from it base
class and cannot be removed so we hid them form the property grid and
IntelliSense.
That explains why the property exists, but doesn't show in Intellisense.
This blog post is worth a read as well: http://waxtadpole.wordpress.com/2009/10/12/assigning-custom-class-to-checkedlistbox-datasource/
Here is how I am binding a List<T> of User objects into CheckedListBox.
((ListBox)myCheckedListBox).DataSource = listOfUsers;
((ListBox)myCheckedListBox).DisplayMember = "FullName";
((ListBox)myCheckedListBox).ValueMember = "UserID";
Of course this is not recommended, since documentation is telling us that this property is hidden.
The code above works, but I noticed some side effects in Visual Studio 2012 such as:
Delay for rendering checked marker:
After you click on the desired item, there is annoying delay to render the "checked" marker.
In my case, CheckOnClick property is True, CausesValidation is False.
Personally I use a DataGridView that is bound to a DataTable that has a Boolean field along with a field for the display value.
If you hide the column headers and row headers then you get something pretty close to what a CheckedListBox gives you.
This can be worked around by iterating through your would-be datasource and adding its items one-at-a-time. For example:
This, which will cause an exception:
myCheckedListBox.DataSource = myStringList;
Can be modified to this:
foreach (string myString in myStringList)
{
myCheckedListBox.Items.Add(myString);
}
I solved the problem by changing the ToString () method to the name that should appear:
public static class Fields
{
public string MyDisplayMenber{ get; set; }
public override string ToString(){
return MyDisplayMenber;
}
}
and turning into array list with objects:
{
mycheckedlistbox.Items.AddRange(MyList.ToArray<Fields>());
}
I know this is pretty old; for the benefit of anyone who still has the same requirement, here's what worked for me. Note that I did not use DisplayMember or ValueMember properties, as it seems like it is discouraged (see #David Stratton's post above).
//References
// https://social.msdn.microsoft.com/Forums/vstudio/en-US/0e0da0c9-299e-46d0-b8b0-4ccdda15894c/how-to-assign-values-to-checkedlistbox-items-and-sum-these-values?forum=csharpgeneral
using Microsoft.Practices.EnterpriseLibrary.Data;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Windows.Forms;
namespace MyApp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
DatabaseProviderFactory factory = new DatabaseProviderFactory();
Database db = factory.Create("MyConnString");
DataTable dt = db.ExecuteDataSet(CommandType.StoredProcedure, "ProcGetCustomers").Tables[0];
var custlist = new List<CheckBoxItem<string, string>>();
for (int i = 0; i < dt.Rows.Count; i++)
{
custlist.Add(Create(dt.Rows[i]["DESC"].ToString(), dt.Rows[i]["CODE"].ToString()));
}
checkedListBox1.Items.AddRange(custlist.Cast<object>().ToArray());
}
public class CheckBoxItem<K, V>
{
public CheckBoxItem(K displayValue, V hiddenValue)
{
DisplayValue = displayValue;
HiddenValue = hiddenValue;
}
public K DisplayValue { get; private set; }
public V HiddenValue { get; private set; }
public override string ToString()
{
return DisplayValue == null ? "" : DisplayValue.ToString();
}
}
public static CheckBoxItem<K, V> Create<K, V>(K displayValue, V hiddenValue)
{
return new CheckBoxItem<K, V>(displayValue, hiddenValue);
}
}
}

Binding the Checkbox.Checked property to property on DataSet

Environment: Visual Studio 2010, .NET 4.0, WinForms
I have a DataSet that implements INotifyPropertyChanged, and have created a bool property on the DataSet. I am trying to bind a CheckBox.Checked property to that bool property. When I try to do it in the designer, I see the DataSet and the tables in the DataSet , but not the property. I attempted to do it manually, but receive the error that the property is not found. The only thing different I see that I'm doing is the property on the form is a superclass of the DataSet that is being instantiated, but I don't even see how that would affect anything. A code snippet is below.
Derived Class Definition
public class DerivedDataSetClass: SuperDataSetClass, INotifyPropertyChanged
{
private bool _mainFile = false;
public bool MainFile
{
get { return this._mainFile; }
set {
this._mainFile = value;
this.NotifyPropertyChanged("MainFile");
}
}
}
Property Definition
private SuperDataSetClass _dataSet;
public DerivedDataSetClass DataSet
{
get { return (DerivedDataSetClass)_dataSet;
}
Ctor
this._DataSet = new DerivedDataSetClass (this);
this.mainFileBindingSource = new BindingSource();
this.mainFileBindingSource.DataSource = typeof(DerivedDataSetClass);
this.mainFileBindingSource.DataMember = "MainFile";
var binding = new Binding("Checked", this.mainFileBindingSource, "MainFile");
this.chkMainFile.DataBindings.Add(binding);
Thoughts?
The problems comes directly from the way you want to use your DerivedDataSetClass. Since it's DataSet, any binding done will use its default DataViewManager, which "pushes" binding further to Tables binding.
When you bind to your DerivedDataSet MainFile property, what is being done under the hood is an attempt to bind to a table named MainFile within your dataset tables. Of course this fails, unless you really have such table in the dataset. For the same reason, you can't bind to any other property of base DataSet - eg. Locale or HasErrors - it also checks whether such tables exist, not properties.
What are the solutions to this problem? You can try implementing different DataViewManager - however I wasn't able to find reliable resources on that topic.
What I suggest is to create simple wrapper class for your MainFile property and associated DerivedDataSetClass, like this:
public class DerivedDataSetWrapper : INotifyPropertyChanged
{
private bool _mainFile;
public DerivedDataSetWrapper(DerivedDataSetClass dataSet)
{
this.DataSet = dataSet;
}
// I assume no notification will be needed upon DataSet change;
// hence auto-property here
public DerivedDataSetClass DataSet { get; private set; }
public bool MainFile
{
get { return this._mainFile; }
set
{
this._mainFile = value;
this.PropertyChanged(this, new PropertyChangedEventArgs("MainFile"));
}
}
}
Now you can bind to both dataset inner content (tables) as well as MainFile on your wrapper class.
var wrapper = new DerivedDataSetWrapper(this._DataSet);
BindingSource source = new BindingSource { DataSource = wrapper };
// to bind to checkbox we essentially bind to Wrapper.MainFile
checkBox.DataBindings.Add("Checked", source, "MainFile", false,
DataSourceUpdateMode.OnPropertyChanged);
To bind data from tables within dataset, you need to bind to DerivedDataSetWrapper DataSet property, and then navigate through tables names and columns. For example:
textBox.DataBindings.Add("Text", source, "DataSet.Items.Name");
... will bind to table Items and column Name in your original _DataSet.

Categories