How to populate dropdown box with indices list - c#

Was hoping this could be a quick answer. New to C# and NEST (as is probably obvious from my previous posts).
I am using NEST to query my ES instance and have built a small winform application to help accomplish the task. I would like to have one of the comboboxes on my winform populate dynamically with the names of the indices from my cluster.
So far I have used:
var node = new Uri("http://xxx.xxx.x.xxx:xxx");
var settings = new ConnectionSettings(node);
var client = new ElasticClient(settings);
var myindexes = client.CatIndices();
I cannot for the life of me figure out how to populate the values of my combobox with the values store in "myindexes"
I have tried
combobox1.value = myindexes.ToList();
but can't see to figure out how to go one level deeper.
I know it is a simple question, but I would really appreciate the help if somebody could spare a few moments.
Thanks very much for the help as always!
Mick

Supposing myindexes is an object that implement IList or an Array. You can use either of these options:
ComboBox.DataSource
this.comboBox1.DataSource = myindexes;
ComboBox.Items.AddRange
this.comboBox1.Items.AddRange(myindexes.Cast<object>().ToArray());
Note:
The text that will be shown for items in ComboBox is the result of ToString method.
If you are showing a complex object, using DataSource way, you can set DisplayMember to one of properties of your complex object to show in ComboBox.
The object that you want to set to DataSource property, should be an object that implements the IList interface or an Array. If it's not, you should first convert it to the expected mentioned types.

you may use BindingSource
BindingSource bs = new BindingSource();
bs.DataSource = myindexes.ToList();
comboBox1.DataSource = bs;

Related

Bind an AutoCompleteTextView to an Array of Objects (ID,NAME)

I've been trying for a while to create an AutoCompleteTextView where you can search for a name, when you select a name from the list the controller should store somewhere (in my test it would be fine to just Toast.MakeTest().Show() the result).
Here's my code:
List<Persona> personeList = getPersone ();
View view = inflater.Inflate(Resource.Layout.MyFragment, container, false);
var autoCompleteSearchName = view.FindViewById<AutoCompleteTextView> (Resource.Id.autoTextName);
ArrayAdapter<Persona> autoCompleteAdapter = new ArrayAdapter<Persona> (
view.Context,
Android.Resource.Layout.SimpleDropDownItem1Line,
personeList
);
autoCompleteSearchName.Adapter = autoCompleteAdapter;
This is the part where I bind the xml element to the controller, then I create the Adapter (Persona is an Object with properties int id and String name, exposing a ToString() method).
It works fine, I can start writing a letter and it shows the suggested names.
Now I would like to get the property id bound to the name that the user selects.
Is it possible?
The only alternative I know is using spinners, but I would like to show thousands of names so I would avoid the spinner if I can.
If you see any other solution I would really appreciate since I'm quite new to Xamarin.
Thanks a lot.
EDIT. I added the autoCompleteSearchName.ItemClick += autoTextViewItemClick;
This triggers when I select an option, the problem is that e.Position is relative to the display order, and is not bound in any way to my real Object,'s properties.
Am I missing something?
You will have to create a custom adapter and use e.Id instead of e.Position. Don't forget to implement Filter in you adapter.
Note: you won't be able to subclass ArrayAdapter because you can't access the items list or override GetItemId.

EF in WinForms: how to filter data in BindingSource/DGW (.Local.ToBindingList())

I generated an EF model (Database first) and DataSource following this tutorial http://msdn.microsoft.com/en-us/data/jj682076.aspx
On my form I created BindingSource (bsUsers) and bound DataGridView to it.
Here is how I load data on form startup:
_myDbContext = new MyDbContext();
_myDbContext.Users.Load();
bsUsers.DataSource = _myDbContext.Users.Local.ToBindingList();
It works, I can add and modify records using DataGridView and other bound controls.
But the thing I didn't figure out is how to filter data. For example I want to have textbox where I can type user name (or part of it) and it will hide all other records.
Looks like BindingList that is returned by ToBidingList() method doesn't support filtering?
I tried this
bsUsers.Filter = "Id = 1";
or
bsUsers.Filter = "Username like 'admin'";
But no effect. UPD: and bsUsers.SupportsFiltering is false.
I have googled but found only this topic MSDN topic where they suggest to filter data before loading (Users.Where(...).Load()), and that's not what I need. I want to load all records and then allow to filter it.
The Filter property of the BindingSource only works with lists that implement the IBindingListView interface. Since BindingList only implements IBindingList (which has no filtering capabilities) the Filter property does nothing.
Either load your data into something like a List<User> and provide the bsUsers.DataSource with filtered elements of the list, e.g. users.Where( u=> u.Id == 1 ).ToList() or replace your BindingList by a list that implements IBindingListView. Possible pointers from here: Generic IBindingListView Implementations

Is the verbose version better or verboten?

I've been populating a combobox this way (getRoundingMethodVals() returns a List<String>):
comboBoxRounding.DataSource = RateSetupData.getRoundingMethodVals();
...but I saw on a StackOverflow answer the following:
comboBox1.DataSource = new BindingSource(dict, null);
...which makes me wonder if I should change my code to:
comboBoxRounding.DataSource = new BindingSource(RateSetupData.getRoundingMethodVals(), null);
Is this a six-of-one-and-half-a-dozen-of-the-other situation? Or does one way hold a strong advantage over the other?
Depends on what you want to do. If you just need to populate the comboBox for a user to select a value, then your first way works very well. It's a one way data flow: from lsit to control. In your case, a simple List(Of String) doesn't need a binding source.
However, if you have a much more complex object and want a change in the combobox value to also change the value of that object, you would use the BindingSource. This creates a two-way data flow. (For this scenario, you could use a BindingList which implements many of the BindingSource interfaces.)

How to create objects dynamically with C#?

I'm trying to create objects dynamically but I don't know how to. What I need is, I have a class for that object, and objects properties are stored in the database. Then I'll need to compare the properties of each object to get the desired result.
So I need to dynamically create objects on the fly with the properties loaded from database.
I don't think you need to create objects dynamically, just create one statically that matches your db schema with the property details, then you can compare the values of the properties across rows, or within an instance of your object.
I have been working on something similar to this. There are several things:
Include the System.Reflection namespace
Create an object dynamically using Activator
Get the object properties using the myObjectType.GetProperties() method
Here is an example of a generic object creation function using the above methods:
using System.Reflection;
public static Item CreateItem<Item>(object[] constructorArgs, object[] propertyVals)
{
//Get the object type
Type t = typeof(Item);
//Create object instance
Item myItem = (Item)Activator.CreateInstance(t, constructorArgs);
//Get and fill the properties
PropertyInfo[] pInfoArr = t.GetProperties();
for (int i = 0; i < pInfoArr.Length; ++i)
pInfo.SetValue(myItem, propertyVals[i], null); //The last argument is for indexed properties
return myItem;
}
Of course the above example assumes that the values in the property value array are arranged correctly, which is not necessarily the case, but you get the idea.
With the PropertyInfo class you can get properties, get property names, get attributes associated with the properties, etc. Powerful technology. You should be able to do what you need with the above info, but if not let me know and I will add more info.
If you have a number of objects you want to instantiate from database values it can be done something like this.
//database code goes here, results go in results
List<ClassName> l = new List<ClassName>()
foreach(Row r in results){
l.Add(new ClassName(){ClassProperty1 = r.Property1,ClassProperty2 = r.Property2});
}
Are you talking about Dictionary?
var dict=new Dictionary<string, string>();
dict.Add("property1", "val1");
dict.Add("property2", "val2");
var prop2val=dict["property2"];
Maybe Activator is what your looking for?
http://msdn.microsoft.com/en-us/library/system.activator.aspx
Check this class, compile in the realtime. But it's performance is not quite good.
http://msdn.microsoft.com/zh-cn/library/microsoft.csharp.csharpcodeprovider(VS.80).aspx
You could use reflection to dynamically build your objects:
Reflection msdn reference
I think that you want to retrieve rows from the DB and directly assign them to object given that the properties of the object are equivalent to the columns of DB table. If that what you mean then I believe you can't :)
Rob Conery did a small project called Massive that pretty much does what you're trying to accomplish. It's essentially a small ORM, in 400 lines of Dynamic C# 4.0 code.
Rob has been doing this kind of thing for quite some time with SubSonic, so you might find his approach with Massive quite interesting.
http://blog.wekeroad.com/helpy-stuff/and-i-shall-call-it-massive
Some of the code is explained here, with examples:
http://blog.wekeroad.com/microsoft/the-super-dynamic-massive-freakshow

Add Items to ComboBox from an IEnumerable object

I have a System.Timers.Timer that updates my win form application components in every 5 seconds.
I have a comboBox and global IEnumerable<Person> list that updated also in everty 5 seconds.
I need to add persons name to combobox. If the name is already in the list, i should not add.
How can I proceed?
Here is the code inside the timer event. This adds multiple times and i am not sure to do that with foreach, maybe IEnumareble interface has an easier way.
foreach (Persons person in personsList)
{
comboBox.Items.Add(person.Name);
}
This is one of the simpler solutions to this problem, assuming you're using .NET 3.5 or greater:
foreach(Person person in personsList)
{
if(!comboBox.Items.Cast<string>().Contains(person.Name))
{
comboBox.Items.Add(person.Name);
}
}
If you're using 3.0 or earlier, you'll have to do the search yourself:
foreach(Person person in personsList)
{
bool contains = false;
foreach(string item in comboBox.Items)
{
contains = string.Equals(item, person.Name);
if(contains) break;
}
if(!contains) comboBox.Items.Add(person.Name);
}
If possible using DataBinding is usually good. WPF has even nicer binding allowing for MVVM. WPF would actually make modifications as you modify the original collection (realtime) and don't have to readd all at every pass.
Readding all items at every pass is a bad approach, but its the easy way out. It would be better to either modify the listbox directly if the code allows it (not too many updates, not too time critical) or to make a copy of the list and perform only differences. (Pass 1: Remove any items in combobox that doesn't exist in new list. Pass 2: Add any items in new list that doesn't exist in combobox)
A couple approaches could be to walk all the items in the combobox, or you could keep track of a List of names that you've already added. Do you have any performance requirements?
Easier would be to just bind directly to the list of Persons and set your DisplayMember appropriately...
If I bind the data cmb.DataSource = personsList; cmb.DisplayMember = "Subject"; This wont work
It didn't work for me also. After some trying found this solution, maybe it will help someone:
IEnumerable<ICustomer> customers = GetCustomers(); //fill Ienumerable object list
_comboBox.DataSource = customers.ToList(); //convert it to list and it binds fine
_comboBox.DisplayMember = "Name"; // field Name from ICustomer
_comboBox.ValueMember = "CustomerID"; // field CustomerID from ICustomer
A more simpler approach is:
comboBox.Items.Clear();
comboBox.Items.AddRange(personsList.Select(p => p.Name));
All that does is clears the comboBox and adds the entire list again. Or if you don't like clearing the comboBox:
comboBox.Items.AddRange(personsList.Where(p => !comboBox.Items.Cast<string>().Contains(p.Name)).Select(p => p.Name));
You don't need the foreach anymore. Simply replace all your code with this!

Categories