How to get a value from a hashtable entry - c#

I have put all of my form controls in a hashtable thus :-
foreach (Control c in this.Controls)
{
myhash.Add(c.Name, c);
}
amongst which are two radio buttons. I would like to get the value of the buttons, ie checked or unchecked, and assign them to a variable. How can I do that please. Thanks for all and any help.

foreach (Control c in hashtable.Values)
{
if(c is RadioButton)
{
string name = x.Name;
bool isChecked = (c as RadioButton).Checked;
}
}
or if you know the name
(hashtable["name"] as RadioButton).Checked;

You can retrieve a value by a key associated with it, basically control Name is a key in hashtable you've created. So if you know a name of controls you need to access:
var control = hash[radioButtonControlName] as RadioButton;
Otherwise using LINQ OfType() and List.ForEach():
// OfType() does check whether each item in hash.Values is of RadioButton type
// and return only matchings
hash.Values.OfType<RadioButton>()
.ToList()
.ForEach(rb => { bool isChecked = rb.Checked } );
OR using foreach loop:
(there is a nice overview of misconception of the List.ForEach() usage)
var radioButtons = hash.Values.OfType<RadioButton>();
foreach(var button in radioButons)
{
bool isChecked = rb.Checked;
}

Cast the control that is the radio button to a RadioButton Class instance and then look at the checked property. At least that would be how I've done this many times over in WebForms using similar classes.

Assuming the hashtable in your code is an instance of Hashtable:
Hashtable myhash= new Hashtable();
foreach (Control c in this.Controls)
{
myhash.Add(c.Name, c);
}
You can do this:
foreach (DictionaryEntry entry in myhash)
{
RadioButton rb = entry.Value as RadioButton;
if (rb != null)
bool checked = rb.Checked;
}
Also you can see the key of the hashmap entry with:
foreach (DictionaryEntry entry in myhash)
{
var componentName = entry.Key;
}
That will correspond with the name of the component that you put in the hashmap (c.Name).
Hope this help you.

Related

c# Controls in list and accessing ListBox Properties

I have solved a problem I was having with grouping objects in a way, that at beginning of the program, I loop trough all controls and store all TextBox and ListBoxes in a List<Controls>.
When i try to access them i do:
foreach(var g in controlsList)
{
g.Text = "VALUE";
}
and that works, but when I try to do g.SelectedIndex = 0 its wrong, I am guessing that has to do with that property being specific to listBox. How do I solve, or get around that ?
You can simply use OfType to filter Controls:
foreach(ListBox l in Controls.OfType<ListBox>())
l.SelectedIndex = 0;
I think this is what you are looking for:
foreach (var c in Controls)
{
var listBox = c as ListBox;
if (listBox != null)
{
listBox.SelectedIndex = 0;
}
}
Each control is safely cast to a ListBox. If it is not, the result will be null and will be skipped by the if block.
To access that property you have to cast to destination type first:
foreach(var control in controlsList)
{
if(control is ListBox) // check if this control is a listbox
((ListBox)control).SelectedIndex = 0; // now it is save to cast to listbox
}
the same could be done using as operator:
foreach(var control in controlsList)
{
var listBox = control as ListBox;
if(listBox != null) // check if cast was ok
listBox.SelectedIndex = 0; // use listBox
}
You're right that the property is specific to the list box.
You need to cast this to the correct object to be able to access it.
Here's an example:
foreach(var c in controlsList)
{
c.Text = "VALUE";
if (c is ListBox)
{
ListBox listBox = c as ListBox;
listBox.SelectedIndex = 0;
}
}

How to correctly get the type of fields in a row in GridView?

My aim is to loop through all fields in each row in a GridView. The fields are of type CheckBox, TextBox and DropDownList. If one of them are found unchecked/empty/selectedIndex=0, I'll add it to emptyControls list.
foreach (GridViewRow gvRow in gvProxyEntry.Rows)
{
List<object> emptyControls = new List<object>();
foreach (TableCell cell in gvRow.Cells)
{
Type controlType = cell.Controls[0].GetType();
if (controlType == typeof(CheckBox))
{
CheckBox chkBox = (CheckBox)cell.Controls[0];
if (chkBox.Checked == false)
{
emptyControls.Add(chkBox);
}
}
...
}
...
}
My problem is the if-else checking keeps failing to detect checkboxes (based on code snippet above).
I have a guess why this fails. Doing a debug, I found controlType variable is always of type System.Web.UI.LiteralControl.
How do I correctly get the correct type of all the fields without using field's ID? The reason I don't want to use the field's ID is to prevent code change in the future if new fields are being added to the row.
If a control is nested inside other control, you won't be able to find it easily. I believe you know the ID of the control at design time.
If so, you can use the following FindControlRecursive helper method.
Helper Method
public static Control FindControlRecursive(Control root, string id)
{
if (root.ID == id)
return root;
return root.Controls.Cast<Control>()
.Select(c => FindControlRecursive(c, id))
.FirstOrDefault(c => c != null);
}
Usage
foreach (TableCell cell in gvRow.Cells)
{
var checkBox = FindControlRecursive(cell, "CheckBox1") as CheckBox;
if(checkBox != null)
{
// Do something
}
}
Using Linq you can get all the checkboxes using one line
var unCheckedCheckBoxes = gvProxyEntry.Rows.OfType<TableRow>()
.SelectMany(row => row.Cells.OfType<TableCell>()
.SelectMany(cell => cell.Controls.OfType<CheckBox>())).Where(c=>!c.Checked).ToList();
same way you can get other control types by changing type and the where condition
Solution 1
Apparently, I was targeting cell.Control[0], which is the wrong control type in cell.Controls. So I added another foreach loop to loop through cell.Controls to get the correct control type that I wanted.
foreach (GridViewRow gvRow in gvProxyEntry.Rows)
{
List<object> emptyControls = new List<object>();
foreach (TableCell cell in gvRow.Cells)
{
foreach(Control c in cell.Controls)//newly added foreach loop
{
Type controlType = c.GetType();
if (controlType == typeof(CheckBox))
{
CheckBox chkBox = (CheckBox)c;
if (chkBox.Checked == false)
{
emptyControls.Add(chkBox);
}
}
...
}
...
}
...
}
Solution 2
For LinQ users

How can I read ListView Column Headers and their values?

I've been trying to find out a way to read data from the selected ListView row and display each value in their respected TextBox for easy editing.
The first and easiest way would be something like this:
ListViewItem item = listView1.SelectedItems[0];
buyCount_txtBox.Text = item.SubItems[1].Text;
buyPrice_txtBox.Text = item.SubItems[2].Text;
sellPrice_txtBox.Text = item.SubItems[3].Text;
There is nothing wrong with that code but I have around 40 or more TextBoxes that should display data. Coding all 40 or so would become very tedious.
The solution I've come up with, is to get all TextBox Controls in my User Control like so:
foreach (Control c in this.Controls)
{
foreach (Control childc in c.Controls)
{
if (childc is TextBox)
{
}
}
}
Then I need to loop the selected ListView row column headers. If their column header matches TextBox.Tag then display the column value in their respected TextBox.
The final code would look something like this:
foreach (Control c in this.Controls)
{
foreach (Control childc in c.Controls)
{
// Needs another loop for the selected ListView Row
if (childc is TextBox && ColumnHeader == childc.Tag)
{
// Display Values
}
}
}
So then my question would be: How can I loop through the selected ListView Row and each column header.
Looping over your ColumnHeaders is simply done like this:
foreach( ColumnHeader lvch in listView1.Columns)
{
if (lvch.Text == textBox.Tag) ; // either check on the header text..
if (lvch.Name == textBox.Tag) ; // or on its Name..
if (lvch.Tag == textBox.Tag) ; // or even on its Tag
}
However the way you loop over your TextBoxes is not exactly nice even if it works. I suggest that you add each of the participating TextBoxes into a List<TextBox>. Yes, that means to add 40 items, but you can use AddRange maybe like this:
To fill a list myBoxes:
List<TextBox> myBoxes = new List<TextBox>()
public Form1()
{
InitializeComponent();
//..
myBoxes.AddRange(new[] {textBox1, textBox2, textBox3});
}
Or, if you really want to avoid the AddRangeand also stay dynamic, you can also write a tiny recursion..:
private void CollectTBs(Control ctl, List<TextBox> myBoxes)
{
if (ctl is TextBox) myBoxes.Add(ctl as TextBox);
foreach (Control c in ctl.Controls) CollectTBs(c, myBoxes);
}
Now your final loop is slim and fast:
foreach( ColumnHeader lvch in listView1.Columns)
{
foreach (TextBox textBox in myBoxes)
if (lvch.Tag == textBox.Tag) // pick you comparison!
textBox.Text = lvch.Text;
}
Update: since you actually want the SubItem values the solution could look like this:
ListViewItem lvi = listView1.SelectedItems[0];
foreach (ListViewItem.ListViewSubItem lvsu in lvi.SubItems)
foreach (TextBox textBox in myBoxes)
if (lvsu.Tag == textBox.Tag) textBox.Text = lvsu.Text;
Try this one for greeting all the values.
foreach (ListViewItem lvi in listView.Items)
{
SaveFile.WriteLine(lvi.Text + "_" + lvi.SubItems[1].Text);
}

Store a value for an aspx checkbox?

I have a checkbox list filled by a list of ListItem, each ListItem having both text and a value like "8" or "5".
But I realized that a CheckBox does not have a value, its value is checked or not.
var listType = SettingsManager.Get("CRMCaseTypes");
var listStatus = SettingsManager.Get("CRMStatusReasons");
var listTypeItems = ParseSettingList(listType);
var listStatusItems = ParseSettingList(listStatus);
cblCRMType.DataSource = listTypeItems;
cblCRMType.DataBind();
cblCRMStatus.DataSource = listStatusItems;
cblCRMStatus.DataBind();
foreach (Control c in cblCRMStatus.Controls)
{
CheckBox cb = c as CheckBox;
if(cb != null && cb.(value........)
}
Is there some way I could store a value in each checkbox and use it again in code behind after the user clicks submit?
Thanks
Yes, you can. You can add a custom attribute to the CheckBox. You can use the HTML5 data attributes so your HTML will be HTML5 valid:
Set
foreach (Control c in cblCRMStatus.Controls)
{
CheckBox cb = c as CheckBox;
if(cb != null)
{
cb.Attributes.Add("data-MyField", myFieldVal);
}
}
Retrieve
foreach (Control c in cblCRMStatus.Controls)
{
CheckBox cb = c as CheckBox;
if(cb != null && cb.Attributes["data-MyField"].ToString())
{
// do something
}
}
How long do you want to re use it? If you want to store it temporarily, you can use session. If you want to store it longer, save it to a database or a file.
You could pull the value from the list that the checkboxes were bound to, referencing the relevant list item based on the index of the checkbox.
You could add it as an attribute -
SET:
myCheckBox.Attributes.Add("myKey","myValue");
GET:
var myKey = myCheckBox.Attributes["myKey"] != null ? myCheckBox.Attributes["myKey"].ToString() : "";
Is there some way I could store a value in each checkbox and use it again in code behind after the user clicks submit?
You can set it to a Session
Session["CbxList"] = YourCheckBoxList;
Then when you want to reference it just add the following:
if (Session["CbxList"] != null)
{
YourCheckBoxList = Session["CbxList"] as CheckBoxList;
}
and use.
I've included a link to sessions in case you or anyone else is not familiar with them:
http://msdn.microsoft.com/en-us/library/ms178581(v=vs.100).aspx
You need to look at the Items collection, not the Controls collection:
foreach (ListItem item in cblCRMStatus.Items)
{
string value = item.Value;
}
Although probably no longer needed by OP I'll add my answer since this thread still ranks highly in Google. If this is an ASPxCheckBox you can make use of the JSProperties dictionary to store your value(s) like so:
cb.JSProperties["cpMyValue"] = "MyValue";
I would then usually use a callback from a ASPxGridView or CallbackPanel to get this back to server side (which is slightly out of scope of the original question).

How do you access a Control in a collection by its Type?

How does one target a control by its Type?
I have a Control collection "TargetControls"
List<Control> TargetControls = new List<Control>();
foreach (Control page in Tabs.TabPages)
{
foreach (Control SubControl in page.Controls)
TargetControls.Add(SubControl);
}
foreach (Control ctrl in TargetControls)...
I need to access each existing control (combobox,checkbox,etc.) by its specific Type with access to its specific properties. The way I'm doing it now only gives me access to generic control properties.
Can't I specify something like...
Combobox current = new ComboBox["Name"]; /// Referencing an Instance of ComboBox 'Name'
and then be given access to it's (already existing) properties for manipulation?
You can use the is keyword to check for a specific type of the control. If the control is of a specific type, do a typecast.
foreach (Control SubControl in page.Controls)
{
if (SubControl is TextBox)
{
TextBox ctl = SubControl as TextBox;
}
}
You can use the OfType<T> extension method:
foreach (var textBox = page.Controls.OfType<TextBox>()) {
// ...
}
You'll need to cast the control to the right type of control before accessing any specific parameters.
ComboBox c = ctrl as ComboBox;
If (c != null)
{
//do some combo box specific stuff here
}
Also you could add the controls to a generic dictionary<string, control> and use the control.name as the key there.
Ex.
Dictionary<string, Control> TargetControls = new Dictionary<string, Control>();
Assuming you can use LINQ, and you're looking for (say) a Button control:
var button = (from Control c in TargetControls
where c.Name == "myName" && c is Button
select c
).FirstOrDefault();
...which will give you the first Button control named "myName" in your collection, or null if there are no such items present.
What about the Find method?
Button btn = (Button)this.Controls.Find("button1", true)[0];
btn.Text = "New Text";
In order to access a control's specific properties, you have to cast it to its appropriate type. For example, if the item in your TargetControls collection was a textbox, you would have to say ((TextBox)TargetControls[0]).Text = 'blah';
If you don't know the types ahead of time, you can use reflection to access the properties, but I'd need to have a better example of what you're trying to do first...

Categories