Im using c# .net windows form application. I have a database with some tables.I have two comboboxes (A & B). I have populated a combo box A with column names of a table using sys.columns. Now when i select an item in combo box A ,combo box B should be populated with the same items except the selected item which was selected in combobox A .
You should delete either this question or this one which are about identical things. anyway, here is my identical answer:
in the selected item changed event of A, add code which clears B, then loops round each item in A's Item collection and adds it to B as long as the index of the current item is different from the index of the SelectedItem in A.
Something like (pseudo code, not tested)
b.Items.Clear;
for(int i=0; i<A.Items.Count; i++)
{
if (i!=A.SelectedItemIndex)
{
b.Items.Add(A.Items[i]);
}
}
or
B.Items.Clear;
foreach(object o in A.Items)
{
b.Items.Add(o);
}
b.Items.Remove(A.SelectedItem);
should do it as well.
I'd use a combination of static extension methods and LINQ.
The static extension part would look like this:
// static class...
public static class ComboBoxHelper
{
public static string GetSelectedIndexText(this ComboBox target)
{
return target.Items[target.SelectedIndex].ToString();
}
public static object[] GetNonSelectedItems(this ComboBox target)
{
string selected = GetSelectedIndexText(target);
try
{
object[] result =
target.Items.Cast<object>().Where(c => c.ToString()
!= selected).ToArray();
return result;
}
catch
{
return new object[] { };
}
}
public static void ReplaceItems(this ComboBox target, object[] newRange)
{
target.Items.Clear();
target.Items.AddRange(newRange);
}
}
And the LINQ:
// LINQ:
private void ComboBoxA_SelectedIndexChanged(object sender, EventArgs e)
{
comboBoxB.ReplaceItems(comboBoxA.GetNonSelectedItems());
}
HTH!
Note: there's probably more efficient way than returning an array of list items, but I haven't found this to be a big issue in terms of the big picture (e.g. overall performance, etc).....
I think you will have to code the filling/removal of B in the Change Event of A
m_comboB.Items.AddRange((from item in m_comboA.Items.Cast<object>()
where item != m_comboA.SelectedItem
select item).ToArray());
Or you can use this way which don't remove duplicate items (Sam pointed this out in his comment):
m_comboB.Items.AddRange(Enumerable.Range(0, m_comboA.Items.Count)
.Where(index => index != m_comboA.SelectedIndex)
.Select(index => m_comboA.Items[index]).ToArray());
Related
Situation: I have 3 TextBoxes, a button and a ComboBox. When I enter something in every TextBox and trigger the button, I want that the strings I've written in the TextBoxes can be choosen in the ComboBox as a ComboBoxItem. I've got the idea of putting the strings from the TextBoxes into a list and refer the ComboBoxItem to the correct list-entrys. Or is there a more efficient way to set and get these strings?
Would be nice if some could help me writing the code for it.
private void bAdd_Click(object sender, RoutedEventArgs e)
{
Random random = new Random();
int randomNumber = random.Next(0, 100);
int txBetrag;
txBetrag = int.Parse(betrag1.Text);
int txMonate;
txMonate = int.Parse(monate1.Text);
int txZins;
txZins = int.Parse(zins1.Text);
List<int> abList = new List<int>();
comboBox.Items.Add("1");
}
If you simply want to add txBetrag, txMonate and txZins to your combobox then you don't need a list. At the moment you're creating a list, adding nothing to it and then simply adding 1 entry to your comboBox (not even from your list).
To add your items just do:
comboBox.Items.Add(int.Parse(betrag1.Text));
comboBox.Items.Add(int.Parse(monate1.Text));
comboBox.Items.Add(int.Parse(zins1.Text));
If you really need the list as well (perhaps because it is used elsewhere as well) then you can do the following:
abList.Add(int.Parse(betrag1.Text));
abList.Add(int.Parse(monate1.Text));
abList.Add(int.Parse(zins1.Text));
Then use the list to populate the comboBox:
foreach(var item in abList)
{
comboBox.Items.Add(item);
}
UPDATE
Based off your comment it seems like you want ONE entry in the comboBox that is effectively the 3 textbox values concatenated together. So you could do something like this:
comboBox.Items.Add(betrag1.Text + monate1.Text + zins1.Text);
UPDATE 2
Following you're last comment regarding the fact that you want 1 comboBox item that refers to the 3 values, but doesn't display them, yes you can do this.
Assuming you won't have duplicate entries in the comboBox you could use a Dictionary to map your values to an entry rather than use a list. I'm assuming here that you will have more than 1 entry in your comboBox eventually, otherwise it's a bit pointless having a combobox.
var valueComboMapping = new Dictionary<string, int[]>();
valueComboMapping.Add("Entry 1", new int[] {int.Parse(betrag1.Text), int.Parse(monate1.Text), int.Parse(zins1.Text)};
This will enable you to add mappings at a later date. You can then use the Dictionary to create the listings in the comboBox like this:
foreach(var entry in valueComboMapping.Keys)
{
comboBox.Items.Add(entry);
}
To trigger an event off selecting an item in the comboBox using the SelectedIndexChanged event.
Retrieving the Values
To retrieve your mapped values in the SelectedIndexChanged event you can do something like:
private void comboBox_SelectedIndexChanged(object sender, System.EventArgs e)
{
ComboBox comboBox = (ComboBox) sender;
string entryName = (string) comboBox.SelectedItem;
//retrieve the values from the dictionary using the value of 'entryName'.
List values = new List<int>();
if (valueComboMapping.TryGetValue(entryName, out values)
{
//do something if the key is found.
}
else
{
//do something else if the key isn't found in the dictionary.
}
}
To get this to work you would need to create the dictionary as follows:
var valueComboMapping = Dictionary<string, List<int>>();
Instead of:
var valueComboMapping = Dictionary<string, int[]>();
You can add directly to combobox,no need to add to list.You are using int.Parse, it will generate Format exception.
private void button1_Click(object sender, EventArgs e)
{
comboBox1.Items.Add(betrag1.Text);
comboBox1.Items.Add(monate1.Text);
comboBox1.Items.Add(zins1.Text);
}
Is there a property or a method on the CheckBoxList class that will return an array of ints that represents all of the selected indexes? This is in ASP.NET.
According to the MSDN documentation, there doesn't appear to be. You'll have to iterate the items yourself.
Here is a method that does just that. It iterates each item, checks if it is selected, then adds the index to a list. I use a list because a list is mutable whereas an array is not. Then to return an array, I just call ToArray() on the list.
public int[] selectedIndexesOfCheckBoxList(CheckBoxList chkList)
{
List<int> selectedIndexes = new List<int>();
foreach (ListItem item in chkList.Items)
{
if (item.Selected)
{
selectedIndexes.Add(chkList.Items.IndexOf(item));
}
}
return selectedIndexes.ToArray();
}
You could create an extension method to simulate the behavior you want. The benefit of that being that you could re-use it on any list control. Below is a rough example (I'm just returning the list of strings of the values, you could return anything though, the index, the value, the entire list item, etc.).
public static List<string> SelectedValues(this ListControl lst)
{
List<string> returnLst = new List<string>();
foreach (ListItem li in lst.Items)
{
if (li.Selected == true)
{
returnLst.Add(li.Value);
}
return returnLst;
}
I have a list of windows but it is not in the order I want them. I'm able to get the windows into string from the title - they are being put into a list of windows. I want to sort this list in a specific order with Estimate 1st, Control Center 2nd, and Login 3rd. This is the order I desire. I have know idea on how to go about it but I want to sort it before it goes into the foreach loop.
private void CloseMainWindows(IEnumerable<Window> Windows)
{
var winList = Windows.ToList();
winList.Sort()//This is where I want to sort the list.
foreach (Window window in winList)
{
if (window.Title.Contains("Estimate"))
{
Estimate.closeEstimateWindow();
}
if (window.Title.Contains("Control Center"))
{
ContorlCenter.CloseContorlCenter();
}
if (window.Title.Contains("Login"))
{
login.ClickCanel();
}
}
}
One way would be to have a lookup function:
int GetTitleIndex(string s)
{
if (s.Contains("Estimate")) return 0;
if (s.Contains("Control Center")) return 1;
if (s.Contains("Login")) return 2;
}
Then, to sort, you lookup the indexes:
winList.Sort((x, y) => GetTitleIndex(x).CompareTo(GetTitleIndex(y)));
Alternatively, you could create the list directly using LINQ's OrderBy:
var winList = Windows.OrderBy(GetTitleIndex).ToList();
And in fact in your case you don't even need the intermediate list:
foreach (var window in Windows.OrderBy(GetTitleIndex))
{
...
}
You can do something like this :
List<Type> data = new List<Type>();
data.Sort(new Comparison<Type>(Compare));
private static int Compare(Type x, Type y)
{
//you can compare them like so :
//I'll show you an example just for the sake of illustrating how :
if(x.Name.ToString().Length > y.Name.ToString().Length) return 1;
else return -1;
//the logic for the comparison is up to you.
//compare the 2 elements.
}
I adapted the following code from here
foreach (String table in tablesToTouch)
{
foreach (Object selecteditem in listBoxSitesWithFetchedData.SelectedItems)
{
site = selecteditem as String;
hhsdbutils.DeleteSiteRecordsFromTable(site, table);
}
}
...but, alas, the SelectedItems member appears unavailable to me: "'System.Windows.Forms.ListBox' does not contain a definition for 'SelectedItems' and no extension method 'SelectedItems' accepting a first argument of type 'System.Windows.Forms.ListBox' could be found (are you missing a using directive or an assembly reference?)"
Another suggestion was:
foreach(ListItem listItem in listBox1.Items)
{
if (listItem.Selected == True)
{
. . .
...but I also don't have ListItem available.
What is a workaround to accomplish the same thing?
UPDATE
There are at least two (somewhat kludgy) things I could do:
0) Manually keep track of items selected in listBoxSitesWithFetchedData (as they are clicked) and loop through *that* list
1) Dynamically create checkboxes instead of adding items to the ListBox (getting rid of the ListBox altogether), and use the text value of checked checkboxes to pass to the "Delete" method
But I'm still thinking there's got to be a more straightforward way than those.
UPDATE 2
I can do this (it compiles):
foreach (var item in listBoxSitesWithFetchedData.Items)
{
hhsdbutils.DeleteSiteRecordsFromTable(item.ToString(), table);
}
...but I'm still left with the problem of only acting on the items that have been selected.
UPDATE 3
Since the CF-Whisperer said that listbox multiselection isn't possible in the murky and misty labyrinthine world of CF (cuneiform forms), I simplified the code to:
foreach (String table in tablesToTouch)
{
// Comment from the steamed coder:
// The esteemed user will have to perform this operation multiple times if they want
to delete from multiple sites
hhsdbutils.DeleteSiteRecordsFromTable(listBoxSitesWithFetchedData.SelectedItem.ToString(),
table);
}
The Compact Framework Listbox simply contains a list of object Items. It calls ToString() on each for display, but the items are there.
So let's say we have an object:
class Thing
{
public string A { get; set; }
public int B { get; set; }
public Thing(string a, int b)
{
A = a;
B = b;
}
public override string ToString()
{
return string.Format("{0}: {1}", B, A);
}
}
And we throw some into a ListBox:
listBox1.Items.Add(new Thing("One", 1));
listBox1.Items.Add(new Thing("Two", 2));
listBox1.Items.Add(new Thing("Three", 3));
They will show up as the ToString() equivalent in the list (e.g. "One: 1").
You can still iterate across them as the source objects via a cast or as operation like this:
foreach (var item in listBox1.Items)
{
Console.WriteLine("A: " + (item as Thing).A);
Console.WriteLine("B: " + (item as Thing).A);
}
I have the MultiSelect property of the listView set to false and I'm trying to get a single listViewItem. But the available property is SelectedItems. I've been using the following code...
foreach (ListViewItem item in listView1.SelectedItems)
{
//do something with item.text or whatever
}
Because I know there will only be one item selected. What is the correct way of doing this?
Usually SelectedItems returns either a collection, an array or an IQueryable.
Either way you can access items via the index as with an array:
String text = listView1.SelectedItems[0].Text;
By the way, you can save an item you want to look at into a variable, and check its structure in the locals after setting a breakpoint.
I do this like that:
if (listView1.SelectedItems.Count > 0)
{
var item = listView1.SelectedItems[0];
//rest of your logic
}
Sometimes using only the line below throws me an Exception,
String text = listView1.SelectedItems[0].Text;
so I use this code below:
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listView1.SelectedIndices.Count <= 0)
{
return;
}
int intselectedindex = listView1.SelectedIndices[0];
if (intselectedindex >= 0)
{
String text = listView1.Items[intselectedindex].Text;
//do something
//MessageBox.Show(listView1.Items[intselectedindex].Text);
}
}
If its just a natty little app with one or two ListViews I normally just create a little helper property:
private ListViewItem SelectedItem { get { return (listView1.SelectedItems.Count > 0 ? listView1.SelectedItems[0] : null); } }
If I have loads, then move it out to a helper class:
internal static class ListViewEx
{
internal static ListViewItem GetSelectedItem(this ListView listView1)
{
return (listView1.SelectedItems.Count > 0 ? listView1.SelectedItems[0] : null);
}
}
so:
ListViewItem item = lstFixtures.GetSelectedItem();
The ListView interface is a bit rubbish so I normally find the helper class grows quite quickly.
For a shopping cart situation here's what I recommend. I'm gonna break it down into it's simplest form.
Assuming we start with this(a list view with 2 colums, 2 buttons, and a label):
First things first, removing the items, to do that we'll enter our remove button:
private void button2_Click(object sender, EventArgs e)
{
listView1.Items.Remove(listView1.SelectedItems[0]);
label1.Text = updateCartTotal().ToString();
}
Now the second line is updating our labels total using the next function i'll post to addup all the total of column 2 in the listview:
private decimal updateCartTotal()
{
decimal runningTotal = 0;
foreach(ListViewItem l in listView1.Items)
{
runningTotal += Convert.ToDecimal(l.SubItems[1].Text);
}
return runningTotal;
}
You don't have to use decimal like I did, you can use float or int if you don't have decimals. So let's break it down. We use a for loop to total all the items in the column 2(SubItems[1].Text). Add that to a decimal we declared prior to the foreach loop to keep a total. If you want to do tax you can do something like:
return runningTotal * 1.15;
or whatever your tax rate is.
Long and short of it, using this function you can retotal your listview by just calling the function. You can change the labels text like I demo'd prior if that's what you're after.
None of the answers above, at least to me, show how to actually handle determining whether you have 1 item or multiple, and how to actually get the values out of your items in a generic way that doesn't depend on there actually only being one item, or multiple, so I'm throwing my hat in the ring.
This is quite easily and generically done by checking your count to see that you have at least one item, then doing a foreach loop on the .SelectedItems, casting each item as a DataRowView:
if (listView1.SelectedItems.Count > 0)
{
foreach (DataRowView drv in listView1.SelectedItems)
{
string firstColumn = drv.Row[0] != null ? drv.Row[0].ToString() : String.Empty;
string secondColumn = drv.Row[1] != null ? drv.Row[1].ToString() : String.Empty;
// ... do something with these values before they are replaced
// by the next run of the loop that will get the next row
}
}
This will work, whether you have 1 item or many. It's funny that MSDN says to use ListView.SelectedListViewItemCollection to capture listView1.SelectedItems and iterate through that, but I found that this gave an error in my WPF app: The type name 'SelectedListViewItemCollection' does not exist in type 'ListView'.
foreach (ListViewItem itemRow in taskShowListView.Items)
{
if (itemRow.Items[0].Checked == true)
{
int taskId = Convert.ToInt32(itemRow.SubItems[0].Text);
string taskDate = itemRow.SubItems[1].ToString();
string taskDescription = itemRow.SubItems[2].ToString();
}
}
If you want to select single listview item no mouse click over it try this.
private void timeTable_listView_MouseUp(object sender, MouseEventArgs e)
{
Point mousePos = timeTable_listView.PointToClient(Control.MousePosition);
ListViewHitTestInfo hitTest = timeTable_listView.HitTest(mousePos);
try
{
int columnIndex = hitTest.Item.SubItems.IndexOf(hitTest.SubItem);
edit_textBox.Text = timeTable_listView.SelectedItems[0].SubItems[columnIndex].Text;
}
catch(Exception)
{
}
}
This works for single as well as multi selection list:
foreach (ListViewItem item in listView1.SelectedItems)
{
int index = item.Index;
//index is now zero based index of selected item
}
On mouse click, I would do it like this:
public static string GetSelectedItem(ListView list)
{
foreach (ListViewItem item in list.Items)
{
if (item.Selected)
return item.Text;
}
return null;
}