How to get Many enum sources in the same ListBox - c#

I have these enums that i am trying to get into the same ListBox.
public enum Mammals
{
BlueWhale,
Monkey
}
public enum Reptiles
{
Lizzard,
Python
}
List <object> allAnimals =new List<object>();
animals_lbx.DataSource = allAnimals;
To get one of the lists into the listbox i could simply write:
animals_lbx.DataSource( Enum.GetValues(typeof(Mammals));
but how do i get the both Enum-sources in the same ListBox?

One way is to use
ListBox.Items.AddRange
Adds a group of items to the list of items for a ListBox.
animals_lbx.Items.AddRange(Enum.GetValues(typeof(Mammals));
animals_lbx.Items.AddRange(Enum.GetValues(typeof(Reptiles));
Update
oops, you will need to cast it, as Enum.GetValues returns an System.Array and AddRange expects an object[]
listBox1.Items.AddRange(Enum.GetValues(typeof(Mammals)).Cast<object>().ToArray());

Related

Remove item of unknown type from list

I am trying to remove an item from a List. However, I don't know the type of the objects in the List. Normally I would do it like that:
var itemsSource = lsView.ItemsSource;
var item = (Temperature)lsView.SelectedItem;
var list = (IList<Temperature>)itemsSource;
list.Remove(item);
Is it possible to do the same thing without knowing that the type of the item is "Temperature"? ...so I can use the same function for multiple lists with different objects
If you know the data source is some kind of List<T>, you can use the non-generic IList interface, which is implemented by all generic lists.
IList has a Remove(object) method, so you can just pass it the selected item without worrying about its type.
using System.Collections;
IList itemsSource = lsView.ItemsSource as IList;
itemsSource.Remove(lsView.SelectedItem);
You can do it using the index property
something like
list.RemoveAt(lsView.SelectedIndex);
Alternatively if you want to use the same function for different object types, you can just include the type in your method call
public void RemoveSelectedItem<T>(ListView lsView){
var itemsSource = lsView.ItemsSource;
var item = (T)lsView.SelectedItem;
var list = (IList<T>)itemsSource;
list.Remove(item);
}

Using reflection to get attribute names in struct returns value__

I want to populate a combo box with all of the available item types in my struct ItemTypes:
public enum ItemTypes
{
Ore,
Ice,
Mineral,
Pi
}
In order not to add a new item type in 2 places if I do have to add one eventually (not likely, but still could happen), I want to use reflection to populate that combo box instead of manually adding each item type in a list. This is how I do it:
private void InitItemTypeComboBox()
{
ComboBoxItemTypes = new List<String>();
foreach (var itemType in typeof(EveItem.ItemTypes).GetFields())
{
ComboBoxItemTypes.Add(itemType.Name);
}
SelectedComboBoxItemType = ComboBoxItemTypes.ElementAt(0);
}
Unfortunately, the GetFields() and itemType.Name functions return not only the 4 item types in my struct, it also returns value__ as first field, so I have an extra element in my combo box that I do not want.
I have tried using the BindingFlags.DeclaredOnly, BindingFlags.Public and BindingFlags.Instance flags of the GetFields() together, but it still returns that first value__ element that I don't want.
Is there a way to specify that I do not want this element other than by manually skipping the first element returned by typeof(EveItem.ItemTypes).GetFields()?
EDIT:
If it changes anything, my ItemTypes struct is nested inside another one of my public classes.
you should use :var t = typeof(ItemTypes).GetFields().Where(k => k.IsLiteral == true);
You can use BindingFlags.Static (see for example http://goo.gl/w3VndT)
So
typeof(EveItem.ItemTypes).GetFields(BindingFlags.Static | BindingFlags.Public)
An easiest way to get values from an enum is to use a built-in Enum.GetValues method.
https://msdn.microsoft.com/en-us/library/system.enum.getvalues%28v=vs.100%29.aspx

Convert SelectedObjectCollection to Collection of Specific Type

I have a WinForms multiselect listbox, and each item in the listbox is of type MyClass.
I am also writing a method that needs to take a parameter that is a collection of MyClass. It could be of type MyClass[], List<MyClass>, IList<MyClass>, IEnumerable<MyClass>, etc. Any of those would work fine.
Somehow, I need to pass the selected items in the listbox to my method. But how would I convert SelectedObjectCollection to any of the MyClass collection types described above?
Maybe this helps:
IEnumerable<MyClass> items = yourListBox.SelectedItems.Cast<MyClass>();
One issue is that ListBox Items are not a generic list, so it could contain more than one type. If you call on .AsQueryable you are making the explicit cast on a non type-safe collection when you call on .Select(), Same goes with calling .Cast<T>, as you could get a cast exception. A safer approach would be to use .OfType<T>()
IEnumerable<MyClass> selected = listBox.SelectedItems.OfType<MyClass>();
You can try Linq:
yourSelectedObjectCollection.AsQueryable().Select(o=>(MyClass)o).ToArray()
I had the same issue with my TreeView, which contained 2 different classes.
if(SelectedItem is MyClass)
{
MyClass passvariable = (MyClass)SelectedItem;
}
So if you select an item and the type of the item is MyClass, you create a new variable and set it with the SelectedItem as type MyClass.
You can do the same with a Collection, List, ...
if(MyList is ObservableCollection<MyClass>)
{
ObservableCollection<MyClass> passlist = (ObservableCollection<MyClass>)MyList;
}
If you have more then 1 class in a ListBox, ComboBox, ... just check the SelectedItem with if(... is type)

Can a ComboBox accommodate both numbers and text?

I am trying to figure out something. I have a method which adds some items into a ComboBox named "cbSize". I realize that if I add two types of data into it, the code will crash. Is this because a ComboBox can only accommodate one type of data?
items.Add(1);
items.Add(10);
items.Add(100);
items.Add(2);
items.Add(20);
items.Add(3);
items.Add(30); //works fine if add numbers only
//items.Add("4"); //will crash if mix both numbers and text
//items.Add("2"); //works fine if add text only
//then sort them out
items.Sort();
//now clear original cbSize items
cbSize.Items.Clear();
//and add them back in sorted order
cbSize.Items.AddRange(items.ToArray());
//gotta clear ArrayList for the next time or else things will add up
items.Clear();
Is this because a ComboBox can only accommodate one type of data?
No, try below it will work
cbSize.Items.Add("44");
cbSize.Items.Add(44);
problem is with your items collection, it is type safe. you can't add different types to it.
try with list of objects. it will work. reason is both int and string are objects
List<object> items = new List<object>();
items.Add(1);
items.Add(30);
items.Add("4");
items.Add("2");
//since you have string and int value you need to create custom comparer
items.Sort((x, y) => Convert.ToInt32(x).CompareTo(Convert.ToInt32(y)));
//now clear original cbSize items
cbSize.Items.Clear();
//and add them back in sorted order
cbSize.Items.AddRange(items.ToArray());
OR you can use ArrayList class (not type-safe because it can store any object)
var integers = new ArrayList();
integers.Add(1);
integers.Add(2);
integers.Add("3");
comboBox1.Items.AddRange(integers.ToArray());
What is type-safe in .net?
Yes. What you can do is to provide a Size class that will adapt from ints and strings:
items.Add(new Size(3));
items.Add(new Size(4));
items.Add(new Size("large"));
Then, you could make the Size class implement IComparable so you can call the Sort() method.

ComboBox bound to an enum type's values while also having a "blank" entry?

If I bind a WinForms ComboBox to an enum type's values, i.e.
combo1.DropDownStyle = ComboBoxStyle.DropDownList;
combo1.DataSource = Enum.GetValues(typeof(myEnumType));
Who knows how I could achieve the same result, while, in addition to entries matching each enum value, I can also have a blank entry representing no selection?
I cannot simply add a special value to the enum type because this must be flexible to deal with any enum type.
I'd appreciate your help.
Edit: I should make clear that I want to bind the actual enum values and not their names. If the actual enum values are bound, the ComboBox takes care of calling their ToString() to get the text to display.
Not sure if you guys have tried all of the code that you've been posting or not, but you can't add items do a databound ComboBox. This is winforms, not WPF, so there is no "DataBind" function.
You could do this:
public static string[] GetEnumValues<T>(bool includeBlank)
{
List<string> values = new List<string>((Enum.GetValues(typeof(T)) as T[]).Select(t => t.ToString()));
if (includeBlank)
{
values.Insert(0, string.Empty);
}
return values.ToArray();
}
Then
combo.DataSource = GetEnumValues<myEnumType>(true);
You could try something like this:
(Edited to reflect Brad_Z's excellent suggestion)
static IEnumerable<String> getValues<T>(String initialValue)
{
yield return initialValue;
foreach (T t in Enum.GetValues(typeof(T)))
yield return t.ToString();
}
static IEnumerable<String> getValues<T>()
{
return getValues<T>(String.Empty);
}
This will allow you to bind to the results of this function like this:
combo1.DataSource = getValues<myEnumType>().ToArray();
or like this, if you wish to specify a different value for the initial item:
combo1.DataSource = getValues<myEnumType>("Select").ToArray();
(Please see my edit to the question where I clarified that I don't want to bind to a collection of strings).
After more fiddling, the following monstrosity seems to work. combo1.SelectedItem is of type object and will either be a DBNull or a (boxed?) enum value. Is this code advisable?
combo1.DataSource = (new object[] { DBNull.Value }
.Concat(Enum.GetValues(refToAnEnumType)
.Cast<object>())).ToList()
Edit: I see Adam and Andrew's methods could easily be adapted to do the same thing. Thanks guys!

Categories

Resources