This question already has answers here:
System.InvalidOperationException: Collection was modified
(6 answers)
How do I loop through items in a list box and then remove those item?
(8 answers)
Collection was modified; enumeration operation may not execute
(16 answers)
Closed 5 years ago.
I need help im trying to shorten a long code by this algorithm.
I use this on my TextBox Fields
Textbox[] Fields = new Textbox[] { txtbox1, txtbox2, txtbox3.. };
string[] arr = { stringVariable1, stringVariable2, stringVariable3.. };
int cnt = 0;
foreach(var r in Fields.AsEnumerable())
{
r.Text = arr[cnt].toString();
cnt++;
}
So when the form loads the user input fields will be populated based on the variable if it's empty or have value.
But how if i have different Type of Fields? like datepicker value, combobox and textbox, radiobutton and checkbox fields.
object[] fields = new object[] { datepicker1, Txtbox1, ComboBox1, CheckBox1 };
The Match it with an Array i declared with different type of Objects too
object[] arr = { DateVar1, TxtBoxVarString1, ComboBoxstring1, CboxBool1, int.. }
is it possible to make declare things like this so i can shorten my code or do i have to do it manually because it's not possible.
I have tried this code:
ArrayList arrvar = new ArrayList(); object[] obj = new object[] { datevarvalue1, cboxvarbool1, rbtnvarbool1, stringvar1.. etc.. etc.. }
arrvar.addrange(obj); try { List Fields = new List { AddinfoDOB.Value, CheckBox1.Checked, RadioButton1.Checked, AddinfoPlaceOfBirth.Text, AddInfoCmbBoxBloodT.Text, AddInfoCmbBoxOrigin.Text, AddInfoCmbBoxCitizenship.Text, AddInfoCmbBoxLanguage.Text, AddInfoAddress01.Text };
int cnt = 0;
foreach (object r in Fields.AsEnumerable())
{
Fields[cnt] = arrvar[cnt];
cnt++;
}
}
catch (Exception ex) { MessageBox.Show(ex.Message.ToString()); }
Error Message: "Collection was modified; enumeration operation may not execute."
Actually you can declare that kind of array. I just tested it and it works. Try this as an example:
Add a button and a checkbox.
using System.Windows.Forms;
string temp = "Hi!";
Object[] arr = new Object[] { button1, checkBox1, temp };
foreach(Object a in arr)
{
if (a is button)
MessageBox.Show(((Button)a).Name);
else if (a is CheckBox)
MessageBox.Show(((CheckBox)a).Name);
else if (a is String)
MessageBox.Show(((String)a));
}
You can do it by introducing collection of "update" functions
Create collection of update functions and correspondent collection of values
var updateFunctions = new List<Action<object>>
{
value => textbox.Text = (string)value,
value => datepicker.Value = (DateTime)value,
value => checkbox.Checked = (bool)value,
};
var values = new List<object>
{
"TextBox value",
DateTime.Now,
true,
};
for(var index = 0; i < updateFunctions.Count; i++)
{
var update = updateFunctions[i];
var value = values[i];
update(value);
}
But for me this approach seems little-bid like "hack-workaround", because you need to check that both collections values and control updates should be in "sync".
Same can be achieved with data-binding on little bid cleaner way
Create a class for values you want display in controls
public class DisplayData
{
public string Name {get; set; }
public DateTime Birthdate {get; set; }
public bool IsActive {get; set; }
}
Then in form constructor "bind" controls to the data
public YourForm() // Form constructor
{
InitializeComponents();
var data = new DisplayData
{
Name = "name",
Birthdate = DateTime.Now,
IsActive = true
};
textbox.DataBindings.Add("Text", data, "Name");
dateTimePicker.DataBindings.Add("Value", data, "Birthdate");
checkBox.DataBindings.Add("Checked", data, "IsActive");
}
When you change control value, correspondent value in the data instance will be changed as well.
If you made DisplayData class implements INotifyPropertyChanged interface and will raise PropertyChanged event every time you change value in data instance - control will be updated automatically.
Howsit!
I encounter an error when i get a null value in my datareader.
public List<Complaint> View_all_complaints()
{
csDAL objdal= new csDAL();
List<Complaint> oblcomplist=new List<Complaint>();
using( IDataReader dr=objdal.executespreturndr("View_all_complaints"))
{
while (dr.Read())
{
Complaint objcomp= new Complaint();
populate_reader(dr,objcomp);
oblcomplist.Add(objcomp);
}
}
return oblcomplist;
}
public void populate_reader(IDataReader dr, Complaint objcomp)
{
objcomp.ref_num = dr.GetString(0);
objcomp.type = dr.GetString(1);
objcomp.desc = dr.GetString(2);
objcomp.date = dr.GetDateTime(3);
objcomp.housenum = dr.GetInt32(4);
objcomp.streetnum = dr.GetInt32(5);
objcomp.status = dr.GetString(6);
objcomp.priority = dr.GetString(7);
objcomp.cid = dr.GetInt32(8);
if (!dr.IsDBNull(9))
{
objcomp.resolved_date = dr.GetDateTime(9);
}
}
in sql resolved date allows null values, this is so because only when a complaint has been resolved , it must reflect that date otherwise it should be null.
if dr.getdatetime(9) is null then it must just set a string saying "Not Resolved"
please help!
You haven't shown what your Complaint type looks like, but basically you'll want to make sure that its resolved_date is of type DateTime? aka Nullable<DateTime>. That allows you to model a missing value elegantly.
As for displaying it - you haven't shown anything about where you display the data, but you'd want something like:
string text = complaint.ResolvedDate.HasValue ? complaint.ResolvedDate.ToString()
: "Not Resolved";
(I've changed this to use a property with the idiomatic name at the same time...)
IDataReader has a "IsDBNull" method, that should be called before calling GetXXX(), in case your value is not nullable.
For example:
objcomp.date = dr.GetDateTime(3);
should be:
objcomp.date = dr.IsDBNull(3) ? DateTime.MinValue : dr.GetDateTime(3);
I have a question about converting types. I want to change the currently selected combobox value string to an int, but I get errors
My code:
int.Parse(age.SelectedItem.ToString());
What can I do for this problem?
Ok now we know the error, you can check for a null value before trying to parse it using:
if (comboBox1.SelectedItem != null)
{
int x = int.Parse(comboBox1.SelectedItem.ToString());
}
else { //Value is null }
You can avoid a null value being passed by setting the text property of the control to what ever default value you want.
If you are still not getting a value after making sure one is selected you really need to post your code.
TryParse is a good method for this sort of thing:
int value;
if (!Int32.TryParse(this.comboBoxNumeric.Text, out value))
{
//Do something fun...
}
Use a Convert.ToInt32 method. You can always use the databinding like this:
class A
{
public int ID{get;set;}
public string Name{get;set;}
}
cbo.DataSource = new A[]{new A{ID=1, Name="hello"}};
cbo.DisplayMember = "Name";
cbo.DisplayValue = "ID";
int id = Convert.ToInt32(cbo.SelectedValue);
A a = (A) cbo.SelectedItem;
int a_id = a.ID;
int a_name = a.Name;
If you use LINQ to DataSets, develop is very easy for C# program.
try
{
string name = comboBoxPort.SelectedItem.ToString();
int portBaudrate = Convert.ToInt32(comboBoxBaudrate.SelectedItem);
}
//just solved
//enjoy
a lot of people have answered the question of how to bind an enum to a combo box in WinForms. Its like this:
comboBox1.DataSource = Enum.GetValues(typeof(MyEnum));
But that is pretty useless without being able to set the actual value to display.
I have tried:
comboBox1.SelectedItem = MyEnum.Something; // Does not work. SelectedItem remains null
I have also tried:
comboBox1.SelectedIndex = Convert.ToInt32(MyEnum.Something); // ArgumentOutOfRangeException, SelectedIndex remains -1
Does anyone have any ideas how to do this?
The Enum
public enum Status { Active = 0, Canceled = 3 };
Setting the drop down values from it
cbStatus.DataSource = Enum.GetValues(typeof(Status));
Getting the enum from the selected item
Status status;
Enum.TryParse<Status>(cbStatus.SelectedValue.ToString(), out status);
To simplify:
First Initialize this command: (e.g. after InitalizeComponent())
yourComboBox.DataSource = Enum.GetValues(typeof(YourEnum));
To retrieve selected item on combobox:
YourEnum enum = (YourEnum) yourComboBox.SelectedItem;
If you want to set value for the combobox:
yourComboBox.SelectedItem = YourEnem.Foo;
The code
comboBox1.SelectedItem = MyEnum.Something;
is ok, the problem must reside in the DataBinding. DataBinding assignments occur after the constructor, mainly the first time the combobox is shown. Try to set the value in the Load event. For example, add this code:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
comboBox1.SelectedItem = MyEnum.Something;
}
And check if it works.
Try:
comboBox1.SelectedItem = MyEnum.Something;
EDITS:
Whoops, you've tried that already. However, it worked for me when my comboBox was set to be a DropDownList.
Here is my full code which works for me (with both DropDown and DropDownList):
public partial class Form1 : Form
{
public enum BlahEnum
{
Red,
Green,
Blue,
Purple
}
public Form1()
{
InitializeComponent();
comboBox1.DataSource = Enum.GetValues(typeof(BlahEnum));
}
private void button1_Click(object sender, EventArgs e)
{
comboBox1.SelectedItem = BlahEnum.Blue;
}
}
Let's say you have the following enum
public enum Numbers {Zero = 0, One, Two};
You need to have a struct to map those values to a string:
public struct EntityName
{
public Numbers _num;
public string _caption;
public EntityName(Numbers type, string caption)
{
_num = type;
_caption = caption;
}
public Numbers GetNumber()
{
return _num;
}
public override string ToString()
{
return _caption;
}
}
Now return an array of objects with all the enums mapped to a string:
public object[] GetNumberNameRange()
{
return new object[]
{
new EntityName(Number.Zero, "Zero is chosen"),
new EntityName(Number.One, "One is chosen"),
new EntityName(Number.Two, "Two is chosen")
};
}
And use the following to populate your combo box:
ComboBox numberCB = new ComboBox();
numberCB.Items.AddRange(GetNumberNameRange());
Create a function to retrieve the enum type just in case you want to pass it to a function
public Numbers GetConversionType()
{
EntityName type = (EntityName)numberComboBox.SelectedItem;
return type.GetNumber();
}
and then you should be ok :)
This is probably never going to be seen among all the other responses, but this is the code I came up with, this has the benefit of using the DescriptionAttribute if it exists, but otherwise using the name of the enum value itself.
I used a dictionary because it has a ready made key/value item pattern. A List<KeyValuePair<string,object>> would also work and without the unnecessary hashing, but a dictionary makes for cleaner code.
I get members that have a MemberType of Field and that are literal. This creates a sequence of only members that are enum values. This is robust since an enum cannot have other fields.
public static class ControlExtensions
{
public static void BindToEnum<TEnum>(this ComboBox comboBox)
{
var enumType = typeof(TEnum);
var fields = enumType.GetMembers()
.OfType<FieldInfo>()
.Where(p => p.MemberType == MemberTypes.Field)
.Where(p => p.IsLiteral)
.ToList();
var valuesByName = new Dictionary<string, object>();
foreach (var field in fields)
{
var descriptionAttribute = field.GetCustomAttribute(typeof(DescriptionAttribute), false) as DescriptionAttribute;
var value = (int)field.GetValue(null);
var description = string.Empty;
if (!string.IsNullOrEmpty(descriptionAttribute?.Description))
{
description = descriptionAttribute.Description;
}
else
{
description = field.Name;
}
valuesByName[description] = value;
}
comboBox.DataSource = valuesByName.ToList();
comboBox.DisplayMember = "Key";
comboBox.ValueMember = "Value";
}
}
Try this:
// fill list
MyEnumDropDownList.DataSource = Enum.GetValues(typeof(MyEnum));
// binding
MyEnumDropDownList.DataBindings.Add(new Binding("SelectedValue", StoreObject, "StoreObjectMyEnumField"));
StoreObject is my object example with StoreObjectMyEnumField property for store MyEnum value.
public static void FillByEnumOrderByNumber<TEnum>(this System.Windows.Forms.ListControl ctrl, TEnum enum1, bool showValueInDisplay = true) where TEnum : struct
{
if (!typeof(TEnum).IsEnum) throw new ArgumentException("An Enumeration type is required.", "enumObj");
var values = from TEnum enumValue in Enum.GetValues(typeof(TEnum))
select
new
KeyValuePair<TEnum, string>( (enumValue), enumValue.ToString());
ctrl.DataSource = values
.OrderBy(x => x.Key)
.ToList();
ctrl.DisplayMember = "Value";
ctrl.ValueMember = "Key";
ctrl.SelectedValue = enum1;
}
public static void FillByEnumOrderByName<TEnum>(this System.Windows.Forms.ListControl ctrl, TEnum enum1, bool showValueInDisplay = true ) where TEnum : struct
{
if (!typeof(TEnum).IsEnum) throw new ArgumentException("An Enumeration type is required.", "enumObj");
var values = from TEnum enumValue in Enum.GetValues(typeof(TEnum))
select
new
KeyValuePair<TEnum,string> ( (enumValue), enumValue.ToString() );
ctrl.DataSource = values
.OrderBy(x=>x.Value)
.ToList();
ctrl.DisplayMember = "Value";
ctrl.ValueMember = "Key";
ctrl.SelectedValue = enum1;
}
This worked for me:
comboBox1.DataSource = Enum.GetValues(typeof(MyEnum));
comboBox1.SelectedIndex = comboBox1.FindStringExact(MyEnum.something.ToString());
this is the solution
to load item of enum in combobox :
comboBox1.Items.AddRange( Enum.GetNames(typeof(Border3DStyle)));
And then use the enum item as text :
toolStripStatusLabel1.BorderStyle = (Border3DStyle)Enum.Parse(typeof(Border3DStyle),comboBox1.Text);
Based on the answer from #Amir Shenouda I end up with this:
Enum's definition:
public enum Status { Active = 0, Canceled = 3 };
Setting the drop down values from it:
cbStatus.DataSource = Enum.GetValues(typeof(Status));
Getting the enum from the selected item:
Status? status = cbStatus.SelectedValue as Status?;
public Form1()
{
InitializeComponent();
comboBox.DataSource = EnumWithName<SearchType>.ParseEnum();
comboBox.DisplayMember = "Name";
}
public class EnumWithName<T>
{
public string Name { get; set; }
public T Value { get; set; }
public static EnumWithName<T>[] ParseEnum()
{
List<EnumWithName<T>> list = new List<EnumWithName<T>>();
foreach (object o in Enum.GetValues(typeof(T)))
{
list.Add(new EnumWithName<T>
{
Name = Enum.GetName(typeof(T), o).Replace('_', ' '),
Value = (T)o
});
}
return list.ToArray();
}
}
public enum SearchType
{
Value_1,
Value_2
}
None of these worked for me, but this did (and it had the added benefit of being able to have a better description for the name of each enum). I'm not sure if it's due to .net updates or not, but regardless I think this is the best way. You'll need to add a reference to:
using System.ComponentModel;
enum MyEnum
{
[Description("Red Color")]
Red = 10,
[Description("Blue Color")]
Blue = 50
}
....
private void LoadCombobox()
{
cmbxNewBox.DataSource = Enum.GetValues(typeof(MyEnum))
.Cast<Enum>()
.Select(value => new
{
(Attribute.GetCustomAttribute(value.GetType().GetField(value.ToString()), typeof(DescriptionAttribute)) as DescriptionAttribute).Description,
value
})
.OrderBy(item => item.value)
.ToList();
cmbxNewBox.DisplayMember = "Description";
cmbxNewBox.ValueMember = "value";
}
Then when you want to access the data use these two lines:
Enum.TryParse<MyEnum>(cmbxNewBox.SelectedValue.ToString(), out MyEnum proc);
int nValue = (int)proc;
I use the following helper method, which you can bind to your list.
''' <summary>
''' Returns enumeration as a sortable list.
''' </summary>
''' <param name="t">GetType(some enumeration)</param>
Public Shared Function GetEnumAsList(ByVal t As Type) As SortedList(Of String, Integer)
If Not t.IsEnum Then
Throw New ArgumentException("Type is not an enumeration.")
End If
Dim items As New SortedList(Of String, Integer)
Dim enumValues As Integer() = [Enum].GetValues(t)
Dim enumNames As String() = [Enum].GetNames(t)
For i As Integer = 0 To enumValues.GetUpperBound(0)
items.Add(enumNames(i), enumValues(i))
Next
Return items
End Function
Convert the enum to a list of string and add this to the comboBox
comboBox1.DataSource = Enum.GetValues(typeof(SomeEnum)).Cast<SomeEnum>();
Set the displayed value using selectedItem
comboBox1.SelectedItem = SomeEnum.SomeValue;
public enum Colors
{
Red = 10,
Blue = 20,
Green = 30,
Yellow = 40,
}
comboBox1.DataSource = Enum.GetValues(typeof(Colors));
Full Source...Binding an enum to Combobox
You can use a extension method
public static void EnumForComboBox(this ComboBox comboBox, Type enumType)
{
var memInfo = enumType.GetMembers().Where(a => a.MemberType == MemberTypes.Field).ToList();
comboBox.Items.Clear();
foreach (var member in memInfo)
{
var myAttributes = member.GetCustomAttribute(typeof(DescriptionAttribute), false);
var description = (DescriptionAttribute)myAttributes;
if (description != null)
{
if (!string.IsNullOrEmpty(description.Description))
{
comboBox.Items.Add(description.Description);
comboBox.SelectedIndex = 0;
comboBox.DropDownStyle = ComboBoxStyle.DropDownList;
}
}
}
}
How to use ...
Declare enum
using System.ComponentModel;
public enum CalculationType
{
[Desciption("LoaderGroup")]
LoaderGroup,
[Description("LadingValue")]
LadingValue,
[Description("PerBill")]
PerBill
}
This method show description in Combo box items
combobox1.EnumForComboBox(typeof(CalculationType));
comboBox1.SelectedItem = MyEnum.Something;
should work just fine ... How can you tell that SelectedItem is null?
You could use the "FindString.." functions:
Public Class Form1
Public Enum Test
pete
jack
fran
bill
End Enum
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
ComboBox1.DataSource = [Enum].GetValues(GetType(Test))
ComboBox1.SelectedIndex = ComboBox1.FindStringExact("jack")
ComboBox1.SelectedIndex = ComboBox1.FindStringExact(Test.jack.ToString())
ComboBox1.SelectedIndex = ComboBox1.FindStringExact([Enum].GetName(GetType(Test), Test.jack))
ComboBox1.SelectedItem = Test.bill
End Sub
End Class
You can use a list of KeyValuePair values as the datasource for the combobox. You will need a helper method where you can specify the enum type and it returns IEnumerable> where int is the value of enum and string is the name of the enum value. In your combobox, set, DisplayMember property to 'Key' and ValueMember property to 'Value'. Value and Key are public properties of KeyValuePair structure. Then when you set SelectedItem property to an enum value like you are doing, it should work.
At the moment I am using the Items property rather than the DataSource, it means I have to call Add for each enum value, but its a small enum, and its temporary code anyway.
Then I can just do the Convert.ToInt32 on the value and set it with SelectedIndex.
Temporary solution, but YAGNI for now.
Cheers for the ideas, I will probably use them when I do the proper version after getting a round of customer feedback.
Old question perhaps here but I had the issue and the solution was easy and simple, I found this http://www.c-sharpcorner.com/UploadFile/mahesh/1220/
It makes use of the databining and works nicely so check it out.
comboBox1.DataSource = Enum.GetValues(typeof(MyEnum));
comboBox1.SelectedIndex = (int)MyEnum.Something;
comboBox1.SelectedIndex = Convert.ToInt32(MyEnum.Something);
Both of these work for me are you sure there isn't something else wrong?
Generic method for setting a enum as datasource for drop downs
Display would be name.
Selected value would be Enum itself
public IList<KeyValuePair<string, T>> GetDataSourceFromEnum<T>() where T : struct,IConvertible
{
IList<KeyValuePair<string, T>> list = new BindingList<KeyValuePair<string, T>>();
foreach (string value in Enum.GetNames(typeof(T)))
{
list.Add(new KeyValuePair<string, T>(value, (T)Enum.Parse(typeof(T), value)));
}
return list;
}
That was always a problem.
if you have a Sorted Enum, like from 0 to ...
public enum Test
one
Two
Three
End
you can bind names to combobox and instead of using .SelectedValue property use .SelectedIndex
Combobox.DataSource = System.Enum.GetNames(GetType(test))
and the
Dim x as byte = 0
Combobox.Selectedindex=x
In Framework 4 you can use the following code:
To bind MultiColumnMode enum to combobox for example:
cbMultiColumnMode.Properties.Items.AddRange(typeof(MultiColumnMode).GetEnumNames());
and to get selected index:
MultiColumnMode multiColMode = (MultiColumnMode)cbMultiColumnMode.SelectedIndex;
note: I use DevExpress combobox in this example, you can do the same in Win Form Combobox
A little late to this party ,
The SelectedValue.ToString() method should pull in the DisplayedName .
However this article DataBinding Enum and also With Descriptions shows a handy way to not only have that but instead you can add a custom description attribute to the enum and use it for your displayed value if you preferred. Very simple and easy and about 15 lines or so of code (unless you count the curly braces) for everything.
It is pretty nifty code and you can make it an extension method to boot ...
only use casting this way:
if((YouEnum)ComboBoxControl.SelectedItem == YouEnum.EspaƱol)
{
//TODO: type you code here
}