for (int counter = 0; counter < countSelected; counter++)
{
string groupName = txt_GroupName.Text;
//Get GroupID from the created group
string GroupIDQueryText = "SELECT GroupID FROM tbl_group WHERE GroupName ";
int groupID = Convert.ToInt32(server.performQuery(GroupIDQueryText, groupName, MySqlDbType.VarChar));
//To get User ID
string firstName = ListBoxMembers.SelectedItems[counter].Value;
}
This isn't returning the selected value, but instead returns the 1st person in the list even if I haven't selected it. Where am I going wrong?
System.Web.UI.WebControls does not contain defenition for listboxmembers.selectedItems error
You are using .Items which is the collection of all items in the ListBox. I think you intend to use .SelectedItems (documentation on MSDN).
// When counter = 0, this is the very first item in the listbox
ListBoxMembers.Items[counter].Value;
// When counter = 0, this is the first of the selected items in the listbox
ListBoxMembers.SelectedItems[counter].Value;
EDIT Web ListBox controls are different than WinForms ListBox controls, so knowing that context is very valuable. Here's an article from MSDN on how to determine the selected items in a multi-selection list control (scroll down to the multi-selection section). The idea is to loop through all .Items and check the .Selected property on each.
I think you should use ListBox.SelectedValue("Somval"); to set selected Value
It's quite simple:
If you have multiple listbox members, like
# | Name | Selected
0 | a | false
1 | b | false
2 | c | true
3 | d | true
then your for loop with counter = 0 selects the entry (0,a,false) and not (2,c,true) at
string firstName = ListBoxMembers.Items[counter].Value;
You have to map the value of the variable counter to the counter+1-th selected item or use SelectedItems, as mentioned by David.
Related
I have a checkListBox that has 3 items using DisplayMembers and ValueMembers. The DisplayMember and ValueMember are populated from a database table.
Here is sample data, ID being ValueMember and Name being DisplayMember.
ID | Name
---------
1 john
2 tim
I want to programatically select a specific item in that checkListBox, for example check the checkbox for "tim", but by the ValueMember, so if the ValueMember of the item equals 2, then check the checkbox.
Here's my code so far:
foreach (DataRowView view in clb.Items)
{
if (view.Row[0].ToString() == 2)
{
**code to checkbox goes here**
}
}
The problem is I'm not sure how to check the item it's on. What am I missing?
Thanks!
If you already have the item you can use:
checkedListBox1.Items.IndexOf(itemChecked).checked = true;
If not you can use the number of the item in the first column and use it in the second one.
I am using a Listbox on my windows application. The listbox has a multi-selection option, which users select all the roles the new user will have.
My Listbox is bound to a dataset. The table is Roles, with an ID column and Description column.
When I bound the listbox, I chose the data source being the dataset, the display member to be the description, the value member being the ID and the selected value being the dataset - roles.frolesid
Now when i loop through the listbox's selecteditems, i get only the first item's values etc...
I am trying to assign an int to the current selectedvalue, to get the ID to give to the user.
int num = 0;
foreach (var item2 in lstRoles.SelectedItems)
{
num = Convert.ToInt32(lstRoles.SelectedValue);
}
So if I select 3 roles, for instance Administrator, Capturer and Assessor, I only see the Administrator value.
How do I loop and access the next item? I'm not even using
item2
in my code. Could this be utilised?
For instance:
First iteration:
And it just stays on that selected item, never moving to the next item.
To get list of selected values when the data source is a DataTable, you can use this code:
var selectedValues = listBox1.SelectedItems.Cast<DataRowView>()
.Select(dr => (int)(dr[listBox1.ValueMember]))
.ToList();
But in general Item of a ListBox control may be DataRowView, Complex Objects, Anonymous types, primary types and other types. Underlying value of an item should be calculated base on ValueMember.
If you are looking for a good solution which works with different settings and different data sources, you may find this post helpful. It contains an extension method which returns value of an item. It works like GetItemText method of ListBox.
solved it
int num = 0;
int count = fRoleIDs.Count;
while (num != count)
{
var item = lstRoles.Items[num] as System.Data.DataRowView;
int id = Convert.ToInt32(item.Row.ItemArray[0]);
num += 1;
}
This goes into the listbox's items and according to the index, gets the item as a Row. This then gets me the itemarray, which is ID and Description {0,1}
I find this question but it could be deprecated and is not resolve my problem at all.
I consider how to loop throw asp:radiobuttonlist which is already bound with data and set visible parameter of specific item. For example I have five items in a radiobuttonlist and I want to make visible only item 1 and item 4.
You could store the items you want to keep, then clear the items and add the stored items:
int[] keepIndexes = { 0, 3 }; // item 1 and 4
ListItem[] keepItems = keepIndexes.Select(i => rbl.Items[i]).ToArray();
rbl.Items.Clear();
rbl.Items.AddRange(keepItems);
This is the approach if you really want to make them "invisible" since there is no property Visible in ListItem. But maybe you are confusing it with Enabled then this is more appropriate:
for (int i = 0; i < rbl.Items.Count; i++)
rbl.Items[i].Enabled = keepIndexes.Contains(i);
At first, I want to talk a little about normal binding (with standard property such as Text of a textbox). The sample grid here has only 2 rows (for simplicity). Suppose I have a table of 2 rows (myDataTable) with 2 columns (ID and Name), a DataGridView (myGrid) and a TextBox (myTextBox). Here is the code for binding data:
myGrid.DataSource = myDataTable;
myTextBox.DataBindings.Add("Text", myDataTable, "Name");
After binding data, when the selection changes in the grid, the info is updated automatically to the control TextBox, for example, the 2 rows are:
ID | Name
1 .NET
2 Java
At first, the selection in grid is at index 0, the Text of myTextBox is ".NET", moving the selection to next position (at index 1), the Text of myTextBox is "Java", moving again and again, forward and backward, it works OK as I expect. But now I have a control with a custom property called List, this is type of List and is readonly. I want to bind it to a column of table (for example, Name), I do the same binding rule, however add a little custom Parse to format the correct string before updating to the datasource (myDataTable) because my custom property is type of List while my Name column is type of string, here is the binding code:
Binding bind = new Binding("List", myDataTable, "Name"){
ControlUpdateMode = ControlUpdateMode.Never //Because my List property is readonly
};
//formating string data before updating to the datasource
bind.Parse += (s,e) => {
List<string> data = (List<string>) e.Value;
if(data.Count == 0) e.Value = DBNull.Value;
else e.Value = string.Join(",",data.ToArray());//format as comma separated string
};
myCustomControl.DataBindings.Add(bind);
In this case, suppose myDataTable currently has no data at column Name like this:
ID | Name
1 <DBNull.Value> <--- current index
2 <DBNull.Value>
After running the demo, the current selection index in the grid is 0, I try changing the value of myCustomControl property List (the Items, not the reference), for example, update it like this:
myCustomControl.List.Add(".NET");
myCustomControl.List.Add("Java");
Then, moving the selection in grid to the next position (index 1), the value ".NET,Java" is updated to the datasource in row 0 at column Name, like this:
ID | Name
1 .NET,Java
2 <----- current index
Now if I move the selection back to index 0, the value at column Name in row 1 is also updated to ".NET,Java" like this:
ID | Name
1 .NET,Java <----- current index
2 .NET,Java
Which is not what I want. I mean the value should be updated via control myCustomControl. Here is what I want:
ID | Name
1 .NET,Java <----- current index
2
I can understand that, at the time moving back from index 1 to index 0, the value of List property is still a List with 2 items (".NET" and "Java") and so after the moving, this is updated to the cell at column Name in row 1. I'm finding how to reset that value of List property after it's updated to the cell at column Name in row 0 so that when the selection is at index 1, it's already empty. I'v tried changing the Parse event handler to the following but no good shake:
bind.Parse += (s,e) => {
List<string> data = (List<string>) e.Value;
if(data.Count == 0) e.Value = DBNull.Value;
else e.Value = string.Join(",",data.ToArray());//format as comma separated string
//I think at here, the value has been already updated to the datasource
//and I can perform the reset
myCustomControl.List.Clear();
};
But it seems to Clear before the value is updated to the datasource and so there is no value udpated to the datasource (instead of ".NET,Java", it's a DBNull.Value).
Then I have also tried this:
bind.BindingComplete += (s,e) => {
if(e.BindingCompleteContext == BindingCompleteContext.DataSourceUpdate)
myCustomControl.List.Clear();
};
I thought, it should check if the data is updated to the datasource, the List can be clear. I have also tried some flag to mark as true before clearing and reset it to false after clearing, use this flag to control the flowing in bind.Parse but it did nothing.
Do you have any idea to solve this problem? Your help would be highly appreciated! Thank you.
I've found the solution myself. In fact I can't reset the List anyway, this will update the underlying datasource when switching between rows in the grid. The key idea here is initially set DataSourceUpdateMode to DataSourceUpdateMode.Never, then whenever the List is about to change, turn the DataSourceUpdateMode to DataSourceUpdateMode.OnPropertyChanged. In the Parse event handler, after the parsing is done, reset DataSourceUpdateMode to DataSourceUpdateMode.Never. And that works greatly. The underlying datasource is updated only when user changing the control's value (List) by typing or selecting ,...
Here is all the code:
Binding bind = new Binding("List", myDataTable, "Name"){
ControlUpdateMode = ControlUpdateMode.Never, //Because my List property is readonly
DataSourceUpdateMode = DataSourceUpdateMode.Never//This will be turned on when preparing to change the List's value
};
//formating string data before updating to the datasource
bind.Parse += (s,e) => {
List<string> data = (List<string>) e.Value;
if(data.Count == 0) e.Value = DBNull.Value;
else e.Value = string.Join(",",data.ToArray());//format as comma separated string
//At here reset the DataSourceUpdateMode to Never
//We can also do this in BindingComplete event handler with BindingCompleteContext = BindingCompleteContext.DataSourceUpdate
myCustomControl.DataBindings[0].DataSourceUpdateMode = DataSourceUpdateMode.Never;
};
myCustomControl.DataBindings.Add(bind);
myCustomControl has a method to update/populate the new items for the List property called UpdateList(), we have to set DataSourceUpdateMode to OnPropetyChanged at the very beginning of the method like this:
public void UpdateList(){
if(DataBindings.Count > 0) DataBindings[0].DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
//The remaining code for populating/updating new items goes below
....
}
And that's all, very clean. Hope this will help someone who will encounter the same situation with me.Thank you!
My issue is that I want to display data in a hierarchal structure as so:
Democrat
County Clerk
Candidate 1
Candidate 2
Magistrate
Candidate 1
Candidate 2
Candidate 3
But I'm retrieving the dataset like this:
Party | Office | Candidate
--------------------------------------------
Democrat | County Clerk | Candidate 1
Democrat | County Clerk | Candidate 2
Democrat | Magistrate | Candidate 1
Democrat | Magistrate | Candidate 2
Democrat | Magistrate | Candidate 3
I planned on using nested repeaters, but I need a distinct value of Party, and then distinct values of office name within that party in order to do it.
Are there any .NET functions to easily do what I'm attempting to? Would there be a better way of displaying the information other than repeaters?
Thanks in advance!
If you can modify the stored procedure, I would recommend a result set in the form of an adjacency list:
ID Name ParentID
1 Democrat NULL
2 County Clerk 1
3 Magistrate 1
4 Candidate 1 2
5 Candidate 2 2
6 Candidate 1 3
7 Candidate 2 3
8 Candidate 3 3
It reduces the amount of data retrieved, and allows you to program recursively against the parent-child relationships. You simply start at the root. This approach avoids the hassle of using nested Repeaters by directly building the string literal in a StringBuilder.
StringBuilder sb = new StringBuilder();
DataTable dt = new DataTable();
someDataAdapter.Fill(dt);
// find the roots:
DataRow[] roots = dt.Select("parentId is null");
sb.Append("<ul>");
foreach (DataRow child in roots)
{
WriteNode(child, sb);
}
sb.Append("</ul>");
// recursively write out each node
public static void WriteNode(DataRow row, StringBuilder sb) {
sb.Append("<li>");
sb.Append(row["Name"]);
// find children rows...
DataRow[] children = row.Table.Select("parentId = " + row["id"].ToString());
if (children.Length > 0)
{
sb.Append("<ul>");
foreach (DataRow child in children)
{
WriteNode(child, sb);
}
sb.Append("</ul>");
}
sb.Append("</li>");
}
I am not sure if you would be interested to use a third party control, but I had EXACTLY SAME requirement of yours and needed to display the data hierarchically, showing repeating values as single one with collapsible nodes (like trees). However, Tree controls are not data bound and still needs a fair bit of coding. But this style of Tree building based on non-normalized data can be easily done with DataBinding. The FlexGrid I have used was DataBound to the DataTable and just needed a few lines of code to display EXACTLY what you require, albeit based on a Third Party Control.
I have used the ComponentOne FlexGrid control and used its 'SubTotal' feature to generate the hierarchical data. I am pasting the code below, just in case you are interested to use the ComponentOne FlexGrid. You can download a Demo copy and check.
// Showing master policy in GROUPS
// -----------------------------------------------------------------------------------
// set tree mode to show settings in GROUPS
flxAvailableSettings.Tree.Style = TreeStyleFlags.Simple;
// show outline tree on column 1.
flxAvailableSettings.Tree.Column = 0;
flxAvailableSettings.Cols[0].Visible = true;
flxAvailableSettings.Cols[0].Width = 15;
flxAvailableSettings.AllowMerging = AllowMergingEnum.Nodes;
// subtotal on column 1, outline level 0
flxAvailableSettings.Subtotal(AggregateEnum.None, 0, 0, 0, "{0}");
// use owner draw to suppress repeating group names in Non-Node rows
flxAvailableSettings.DrawMode = DrawModeEnum.OwnerDraw;
flxAvailableSettings.OwnerDrawCell += new C1.Win.C1FlexGrid.OwnerDrawCellEventHandler(flxAvailableSettings_OwnerDrawCell);
// done, autosize columns to finish
flxAvailableSettings.AutoSizeCols();
// -----------------------------------------------------------------------------------
private void flxAvailableSettings_OwnerDrawCell(object sender, C1.Win.C1FlexGrid.OwnerDrawCellEventArgs e)
{
if (!flxAvailableSettings.Rows[e.Row].IsNode && flxAvailableSettings.Cols[e.Col].Name == "PolicyGroup")
e.Text = "";
}
The flxAvailableSettings.Subtotal(AggregateEnum.None, 0, 0, 0, "{0}") line generates the Tree Groups, though I needed to group on a single column, you can use groups on multiple columns. Just refer their docs example on Subtotalling.
Hope this helps.
A TreeView control would give you the format you want. However populating it from the database takes some effort. There is an article here about populating asp.net TreeViews from a database:
http://www.codeproject.com/KB/tree/TreeViewWithDatabase.aspx