Binding controls to LINQ queries - cannot find field - c#

I have several controls that I am trying to bind to LINQ queries but am getting the following error:
$exception {"DataBinding: 'System.Data.DataRow' does not contain a property with the name 'Key'."} System.Exception
{System.Web.HttpException}
I'm binding it the following way:
myDropDownList.DataSource = myDataTable.AsEnumerable().Where(
r => ((string) r["ColumnName"]) == "ColumnIWant").ToList()
myDropDownList.DataTextField = "Key";
myDropDownList.DataValueField = "Value";
I have tried this both with and without the .ToList(), as suggested in other answers but with no effect.
"myDataTable" has both columns "Key" and "Value". It was my understanding you could bind this way, but I seem to be missing a step in specifying the property names.

My suggestion (as it has worked to me this way with GridView and DropDownList controls), is that you specify this DataTextField and DataValueField properties in the design file (aspx) like this:
<asp:DropDownList ID="DropDownList1" runat="server"
DataTextField="Key" DataValueField="Value">
</asp:DropDownList>
This way, you can still apply the ToList() function to the DataTable and it will work (tested).
If if doesn't, maybe you need to set up one break-point after filling up your myDataTable and another one after the LINQ query, to check if the "Key" and "Value" columns are still there.

If it defenitely contains values for key and Value in the data table then i suggest you to use like the following :
myDropDownList.DataSource = myDataTable.AsEnumerable().Where(
r => (r.Field<string>("ColumnName")) == "ColumnIWant").ToList<DataRow>();
myDropDownList.DataTextField = "Key";
myDropDownList.DataValueField = "Value";
I had changed ToList() to .ToList<DataRow>(); so that the datasourse can find the key and value as same as from a datatable, and change the comparison like this: r.Field<string>("ColumnName")

Using .CopyToDataTable() works for what I'm trying to do, but I'd still prefer to know how to bind the data directly to the EnumerableRows collection if that's possible.
Here is what I did:
myDropDownList.DataSource = myDataTable.AsEnumerable().Where(
r => ((string) r["ColumnName"]) == "ColumnIWant").CopyToDataTable();
myDropDownList.DataTextField = "Key";
myDropDownList.DataValueField = "Value";

Related

Binding DropdownList with a nested json result

I have for the most part successfully connected to an API endpoint and manage to deserialize nested json result and bind it to a gridview using Newtonsoft.Json serialization attributes.
I however cannot bind to a dropdownlist. What is the correct property name to use to pass the supplier name to my dropdownlist?
I can see the property I want to pass (supplier name) and have tried all possible strings I can think of but all I get is the class name to display.
The Supplier Name displays fine on the gridview
I can see the property I want to display supplier -> name
Binding Code
var readdata = comsumeapi.Result;
if (readdata.IsSuccessStatusCode)
{
var displayrecords = readdata.Content.ReadAsAsync<IList<CoupaPODetails>>();
displayrecords.Wait();
empobj = displayrecords.Result;
GridView1.DataSource = empobj;
GridView1.DataBind();
DropDownList1.DataSource = empobj;
DropDownList1.DataTextField = "supplier";
DropDownList1.DataBind();
}
It would have been quite helpful to see your JSON object code but I think I can glean what I need from the screenshots
You've bound the drop down list to supplier object, not the name of the supplier. I think you should probably make a new list of all the different suppliers and bind to that, something like:
var x = empobj.Select(e => e.supplier.name).Distinct().ToList();
(Your supplier object only seems to contain a name? This a bit odd why there would even be a supplier object at all if it only houses a string. I figured it might contain more than that , like a name and an ID. If it contains more than that and you want a display text and a value that are different, use one of the techniques from here to group by eg the value and then linq .Select(g => new ListItem(){Text = g.First(), Value = g.Key}) to generate a List<ListItem> that can be the datasource for your drop down)
Don't forget that you'll also need to bind to the grid's row data bound event to set the selected item in the drop down, detail for which is here

Map enum values on ComboBox

I want to use a C# Windows Forms combo box to select the value of an enum:
this.comboBoxColor.DataSource = System.Enum.GetValues(typeof(System.Drawing.KnownColor));
But when I put this in the InitializeComponent, it replaces this line with a static assignment of an array with all items in the enum. It does this twice, once for the Datasource, and once for the Items property.
But these things don't work together. When having a bound DataSource, adding items to the Items list causes an error and when doin it the other way around assigning the SelectedValue property doesn't work any more.
I've tried using a separate method to do this outside the InitializeComponent method. And simply setting the DataSource as above in the separate method produces the following error:
System.InvalidOperationException: 'Can't set the SelectedValue in a ListControl with an empty ValueMember.'
Edit: Microsoft says using a simple array as a data source should be possible: https://msdn.microsoft.com/nl-nl/library/x8160f6f(v=vs.110).aspx
It's possible to specify the data source in the designer, but there it only allows selecting classes. What must a class implement to make that work?
You can write a simple method that transforms your enum to a datatable and then use the result of the method as a DataSource with a pair of well known names for the ValueMember and DisplayMember properties of the combo
public DataTable CreateTableFromEnum(Type t)
{
DataTable dt = new DataTable();
if (t.IsEnum)
{
dt.Columns.Add("key", t);
dt.Columns.Add("text", typeof(string));
foreach(var v in Enum.GetValues(t))
dt.Rows.Add(v, v.ToString());
}
return dt;
}
and call it with
var colors = CreateTableFromEnum(typeof(KnownColor));
cbo.ValueMember = "key";
cbo.DisplayMember = "text";
cbo.DataSource = colors;
Now when you look at the selected value you will get the numeric value of the color selected

Why DisplayMember doesn't work with manually added DataRow in ListBox?

Here is the thing I add manually few DataRow's to this.listBox1.Items and set in WinForms Designer the DisplayMember to column name but all I get displayed later is a list of type's name (System.Data...) .
How to solve this issue?
CODE:
list1.ForEach(x => this.listBox1.Items.Add(x)); //x is DataRow from a filled DataTable
The DisplayMember and ValueMember are applicable only when you use data binding (ListBox.DataSource). They work either with real properties, which can be retrieved by reflection, or via the .NET component model and the ICustomTypeDescriptor interface.
If you bind a DataTable directly, the GetEnumerator method and the IList implementation returns always DataRowView instances instead of DataRows. DataRowView implements the ICustomTypeDescriptor where the DisplayName can refer a column name.
So if you want to add some custom filtered list, I suggest you to create one from whatever source. For example:
listBox1.DisplayMember = "Name";
listBox1.ValueMember = "Value";
var list = Enumerable.Range(1, 10).Select(i => new {Name = i.ToString(), Value = i}).ToList();
listBox1.DataSource = list;
If Name property exists, you will see its value; otherwise, you will see the ToString of the items.
However, if you add the items programmatically (ListBox.Items), these properties are ignored and always the ToString of the items will be used.
Specify the column name you want to add to your list box:
list1.ForEach(x => this.listBox1.Items.Add(x["column_name"]));

Can't edit my datagridview after binding to XML file via linq

Links to 2 similar examples on here which I can't really link to my exact case.
Similalr example 1
Similar Example 2
Here is the code that populates my datagridview...
XElement xdoc = XElement.Load(#"C:\xmltest\test.xml");
var lines = from item in xdoc.Descendants("line")
let fields = item.Elements("field")
select new
{
Name = (string)fields
.FirstOrDefault(n => (string)n.Attribute("name") == "Name"),
Description = (string)fields
.FirstOrDefault(n => (string)n.Attribute("name") == "Description"),
ExtraDetails = (string)fields
.FirstOrDefault(n => (string)n.Attribute("name") == "ExtraDetails"),
};
dataGridView1.DataSource = lines.ToArray();
This works fine but I can't edit the datagridview after the 'import'. I have defiantly set the datagridview settings to allow editing etc. The problem seems to be related to the databind in some way.
The problem is that you are projecting the result to anonymous type. The very first line in the documentation link states
Anonymous types provide a convenient way to encapsulate a set of read-only properties into a single object without having to explicitly define a type first.
Hope you noticed the read-only word.
If you want to get editable data, then create your own class with read/write properties and project the query result into it.

Manually set value Member of Combobox

Actually I need to set the value member of combobox using Foreach loop
My code goes like this.
foreach(DataRow row in dsTable.Tables["mytable"].Rows)
{
combobox1.Items.Add(row["my column"]);
}
how do i set value member on it?
Here is the definition and some examples of combobox use.
msdn combobox link
Basically a combobox accepts "objects" so u could add any kind of items in it.
Hopes it helps.
You're not binding a DataSource so basically there's no point in setting the ValueMember property.
You should do this instead of the loop:
combobox1.DataSource = dsTable.Tables["mytable"];
combobox1.ValueMember = "MyValueColum";
combobox1.DisplayMember = "MyDisplayColumn";

Categories