Unable to cast object of type '<>f__AnonymousType0`2[System.String,System.Int32]' to type 'System.IConvertible' - winforms

I am trying to populate a data list box to text box on list box's click event but I found this error
Additional information: Unable to cast object of type '<>f__AnonymousType0`2[System.String,System.Int32]' to type 'System.IConvertible'
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
StudenRecordDataContext std = new StudentRecordDataContext();
int selectedValue = Convert.ToInt32(listBox1.SelectedValue);
StudentRecord sr = std.StudentRecords.Single(s =>s.ID==selectedValue);
txtId.Text = sr.ID.ToString();
txtName.Text = sr.Name;
txtPassword.Text = sr.Password;
txtCnic.Text = sr.CNIC;
txtEmail.Text = sr.Email;
}
I think the error is on line StudentRecord sr = std.StudentRecords.Single(s =>s.ID==selectedValue);
Where does that error come from and what do I need to change to fix that error?

I'm sorry to say so but you provided us with the wrong diagnosis of the line your program fails.
The culprit is this line:
int selectedValue = Convert.ToInt32(listBox1.SelectedValue);
I expect you have earlier populated that listbox1 with a collection from StudentRecords coming from an instance of your StudentRecordDataContext.
If you select a value from the listbox the SelectedValue holds the object you added to the items collection (or indirectly by setting the DataSource property).
To fix your code you could first make sure the object becomes a StudentRecord again. That is not that easy because you created an anonymous type, I expect something like:
listbox1.DataSource = new StudentRecordDataContext()
.StudentRecords
.Select(sr => new { Name = sr.Name, ID = sr.ID });
When you try to retrieve the SelectedValue you get that anonymous type, not something that is strongly typed.
Instead of adding an anonymous type, create a new class that has the properties for the Name and the Id:
class StudentRecordItem
{
public string Name {get; set;}
public int ID {get; set;}
}
When you populate the Datasource create StudentRecordItem classes for each record and add those to the datasource.
listbox1.DataSource = new StudentRecordDataContext()
.StudentRecords
.Select(sr => new StudentRecordItem { Name = sr.Name, ID = sr.ID });
The your code can become something like this:
StudentRecordItem selectedStudent = listBox1.SelectedValue as StudentRecordItem;
if (selectedStudent == null)
{
MessageBox.Show("No student record");
return;
}
int selectedValue = selectedStudent.ID;
You don't need the Convert.ToInt32 because I assume ID is already an int.
Remember that the debugger in Visual Studio shows the actual types and values of all your properties and variables. When a type conversion fails you can inspect there what the actual type is you're working with.

Related

LINQ to SQL query to populate ListBox returns wrong results

Hello here's a LINQ to SQL query :
private void Stk_DT_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DataTable dt = new DataTable();
DataGrid grid = sender as DataGrid;
#region Buttons Picking Libres
using(BdCretsDataContext dc=new BdCretsDataContext())
{
var placement = (from p in dc.PICKING
where p.ART_CODE == ArtCode_TxtBox.Text
select new { p.R_PLACEMENT }).Distinct().ToList();
LB.ItemsSource = placement;
}
#endregion
}
With this query I want to fill a ListBox. But I get this result :
All I want is just: 53.
Thanks for helping me
The point is that select new { p.R_PLACEMENT } creates a collection of objects that have a property called R_PLACEMENT. The ToString() of this object, which is invoked by the ListBox, returns a string representation of this object: { R_PLACEMENT = 53 }. You have to unwrap or collect the values from this property:
LB.ItemsSource = placement.Select(row => row.R_PLACEMENT);
This returns a collection of values only.
This is because you create a new (anonymous) type within select new { p.R_PLACEMENT }.
Your placement variable will thus hold a List<> of this new type. The ListBox however does not know how to display items of this type.
To make the ListBox display something useful you must tell it what it should make out of this anonymous type. ListBox does not figure out it on its own.
The simplest solution would probably be to create placement like this:
var placement = (from p in dc.PICKING
where p.ART_CODE == ArtCode_TxtBox.Text
select p.R_PLACEMENT.ToString()).Distinct().ToList();
(From your example I deduce that R_PLACEMENT is of some numeric type.) The .ToString() suffix makes placement a List<string> which the ListBox will be glad to display correctly.

How do I set values for the entries in a Windows Forms ComboBox?

I want to have a drop down list with 12 choices.
I found that ComboBox is what I need (if there is a better control kindly tell me).
I dragged and drop a combo box into a panel using VS2012 and then clicked on the left arrow that appears on the combo box. The following wizard shows:
As you can see, I am just able to type the name of the choice but not the value of it.
My question is how to get the value of these choices?
What I have tried
I built an array with the same length as the choices, so when the user selects any choice, I get the position of that choice and get the value from that array.
Is there a better way?
You need to use a datatable and then select the value from that.
eg)
DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("Description", typeof(string));
dt.Load(reader);
//Setting Values
combobox.ValueMember = "ID";
combobox.DisplayMember = "Description";
combobox.SelectedValue = "ID";
combobox.DataSource = dt;
You can then populate your datatable using:
dt.Rows.Add("1","ComboxDisplay");
Here, the DisplayMember(The dropdown list items) are the Descriptions and the Value is the ID.
You need to include a 'SelectedIndexChanged' Event on your combobox (If using VS then double click the control in Design Mode) to get the new values. Something like:
private void ComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
int ID = Combobox.ValueMember;
string Description = ComboBox.DisplayMember.ToString();
}
You can then use the variables in the rest of your code.
You cannot use the wizard to store values and text. To store DisplayText/Value pair the combobox needs to be connected to some data.
public class ComboboxItem
{
public string DisplayText { get; set; }
public int Value { get; set; }
}
There are two properties on the combobox - DisplayMember and ValueMember. We use these to tell the combobox that - show whats in DisplayMember and the actual value is in ValueMember.
private void DataBind()
{
comboBox1.DisplayMember = "DisplayText";
comboBox1.ValueMember = "Value";
ComboboxItem item = new ComboboxItem();
item.DisplayText = "Item1";
item.Value = 1;
comboBox1.Items.Add(item);
}
To get the value -
int selectedValue = (int)comboBox1.SelectedValue;

How do I position a datagridview to the searched text input

Using Windows forms and linq to Sql, I bound a datagridview to Products Table, I added to the form 1 Textbox to input the searched text.
I wonder how to position the datagridview according to the text entered to find a given ProductName.
Here I do not want to filter rows, I only want to reposition datagrid after each character entered, the used code:
private void textBox1_TextChanged(object sender, EventArgs e)
{
var searchValue = textBox1.Text.Trim().ToUpper();
var qry = (from p in dc.Products
where p.ProductName.ToUpper().StartsWith(searchValue)
select p).ToList();
int itemFound = productBindingSource.Find("ProductName", searchValue);
productBindingSource.Position = itemFound;
}
The execution of code give the next error: System.NotSupportedException was unhandled at the ligne:
int itemFound = productBindingSource.Find("ProductName", searchValue);
Any idea please ?
The MSDN documentation for BindingSource has the answer:
The Find method can only be used when the underlying list is an
IBindingList with searching implemented. This method simply refers the
request to the underlying list's IBindingList.Find method. For
example, if the underlying data source is a DataSet, DataTable, or
DataView, this method converts propertyName to a PropertyDescriptor
and calls the IBindingList.Find method. The behavior of Find, such as
the value returned if no matching item is found, depends on the
implementation of the method in the underlying list.
When you call this method on a BindingSource whose underlying data source does not implement IBindingList then you see the exception (thrown by the default implementation of IBindingList.FindCore:
System.NotSupportedException: The specified method is not supported.
You don't show what you bind the binding source to but clearly it doesn't implement this method.
Annoyingly, BindingList<T> the recommended list type to use for your data source does not provide a FindCore implementation.
If you are using BindingList you will need to create your own custom type. Here is the code for an absolutely bare bones implementation of a BindingList that supports find:
public class FindableBindingList<T> : BindingList<T>
{
public FindableBindingList()
: base()
{
}
public FindableBindingList(List<T> list)
: base(list)
{
}
protected override int FindCore(PropertyDescriptor property, object key)
{
for (int i = 0; i < Count; i++)
{
T item = this[i];
if (property.GetValue(item).Equals(key))
{
return i;
}
}
return -1; // Not found
}
}
You can do lots with your own implementations of BindingList such as supporting sorting. I've left my answer as just the minimum to support the find method. Search for SortableBindingList if you want to know more.
To use this class do something like this:
var qry = (from p in dc.Products
where p.ProductName.ToUpper().StartsWith(searchValue)
select p).ToList();
FindableBindingList<YourType> list = new FindableBindingList<YourType>(qry);
dataGridView1.DataSource = list;

Under SelectionChanged read out the underlying data from a List

Im busy with my app and i walked in some problems when i click on a photo in my listbox PhotoFeed.
I got 1 List<> with in it the strings UrlTumb and UrlFull.
I got 1 ListBox with in it a WrapPanel filled with images wich i set the Image.Source from my UrlTumb.
What my problem is when i click on a photo in my listbox i want to navigate to a new page and display there the original image (UrlFull) now i can only get my UrlTumb from my Image.Source but i want my UrlFull which is stored in the List. Now is my question how do i obtain the UrlFull. So how can i back trace which item i clicked and get the UrlFull from that item so i can send it with my NavigationService.Navigate
I can do it on an dirty way and create an invisible textblock besides the image in my ListBox and put the UrlFull in there but i would like to do it in a proper way
So what do i place in the ????? spot in this line
NavigationService.Navigate(new Uri("/PhotoInfo.xaml?urlfull={0}", ????? , UriKind.Relative));
Greetings Cn
There are multiple options:
Use selected item's index listBox.SelectedIndex to get the index
of the selected property which will correspond to the index in your
source (it might not if you filter the collection using collection
source, but I think that is not the case)
Use selected item listBox.SelectedItem this will return the
SelectedItem which will contain your object. (Note, that if your
selection mode set to multiple, this will return only the firstly
selected item)
Use SelectemItems. It will allow you to get an array of selected
items (Note: this should be normally used only when your list's
selection mode is set to multiple)
Use SelectedValue, which will contain the value of the SelectedItem
(this will save you and extra step.
Use arguments of the Selection changed event AddedItems.
Bellow is the code snippet of 3 options above. x, y, z will all be your selected names (e.g. "Mike")
XAML:
<ListBox x:Name="lb"
ItemsSource="{Binding Names}"
SelectionChanged="NameChanged" />
Code behind:
public class Person
{
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
private List<Person> people = new List<Person>
{
new Person{Name = "Lewis"},
new Person{Name = "Peter"},
new Person{Name = "Brian"}
};
public List<Person> People
{
get
{
return this.people;
}
set
{
this.people = value;
}
}
private void NameChanged(object sender, SelectionChangedEventArgs e)
{
var x = this.people[lb.SelectedIndex];
var y = lb.SelectedItem;
var z = lb.SelectedItems[0];
var h = lb.SelectedValue;
var u = e.AddedItems[0];
var person = e.AddedItems[0] as Person;
if (person != null)
{
var result = person.Name;
}
}
For the differences between SelectedValue and SelectedItem refer here SelectedItem vs SelectedValue

Set DisplayMemberPath and SelectedValue in WPF with Code

I have a DataTable that is coming from a Web Service, which I need to bind to a ComboBox. I have not grokked doing binding in XAML yet so this question is about binding in code instead. So far I have tried
cboManager.DataContext = Slurp.DistrictManagerSelect().DefaultView;
cboManager.DisplayMemberPath = "Name";
cboManager.SelectedValuePath = "NameListId";
cboManager.SetBinding(ComboBox.ItemsSourceProperty, new Binding());
And I have tried
DataTable tbl = new DataTable();
tbl = Slurp.DistrictManagerSelect();
cboManager.ItemsSource = ((IListSource)tbl).GetList();
cboManager.DisplayMemberPath = "[Name]";
cboManager.SelectedValuePath = "[NameListId]";
DataContext = this;
In both cases I get the list of managers to show but when I select from the ComboBox I get [Name] and [NameListId] and not the values I am expecting. What am I doing wrong (other than not using XAML's DataBinding)?
Edit added after answers to my original post came in.
So (based on Rachel's response) try number three looks like this:
using (DataTable tbl = Slurp.DistrictManagerSelect())
{
List<ManagerList> list = new List<ManagerList>();
foreach (var row in tbl.Rows)
{
list.Add(new ManagerList
{
NameListId = (int)row[0],
Name = row[1].ToString()
});
}
}
Assuming I am doing what she meant the correct way I am no getting this error Cannot apply indexing with [] to an expression of type 'object'
Have you tried to just bind to the DataTable directly? Do you have columns Name and NameListId? Leave off the DataContext (you already assigned the ItemsSource).
DataTable tbl = Slurp.DistrictManagerSelect();
cboManager.ItemsSource = tbl;
cboManager.DisplayMemberPath = "Name";
cboManager.SelectedValuePath = "NameListId";
When you cast to the IListSource I suspect it is combining all the columns. If you want to bind to a list then you need to create items that have properties Name and NameListID.
I think that's because your ItemsSource is a DataTable, so each ComboBoxItem contains a DataContext of a DataRow, and the DataRow class doesn't have properties called Name or NameListId
Basically, you're trying to tell the ComboBox to display DataRow.Name, and set the value to DataRow.NameListId, both of which are not valid properties.
I usually prefer to parse data into objects, and bind the ItemsSource a List<MyObject> or ObservableCollection<MyObject>
foreach(DataRow row in tbl.Rows)
list.Add(new MyObject { Name = row[0].ToString(), NameListId = (int)row[1] });
cboManager.ItemsSource = list;

Resources