I'm looping through the Controls collection of an asp:Panel, and I am not sure how to set Properties specific to some controls...
For example the Panel might contain a DropDownList, and I would like to be able to set and get the SelectedValue of this. Or it might contain a TextBox, and I would like to set and get the Text property.
I'm using this code to traverse:
foreach (Control control in panel.Controls)
{
// ...
}
And since I get just a Base Control from this, it appears not to be able to get/set any of these properties as they are not defined for the Base Control.
So, what to do?
Thanks
One possibility is to use the as operator:
foreach (Control control in Controls) {
TextBox txt = control as TextBox;
if (txt!=null) {
txt.Text = "bla";
...
}
ComboBox cbo = control as ComboBox;
if (cbo!=null) {
cbo.SelectedItem = ...
...
}
...
}
Note: If you have multiple controls of one type, you may use the Tag property to store additional information. While Tag is of type object, you also need the as operator here...
You could always check the type, and then cast it to that type.
foreach (Control control in Controls)
{
if (control.GetType().Equals(typeof(DropDownList)))
{
((DropDownList)control).Enabled = value;
}
}
You should be able to use the is operator like so:
if(control is DropDownList)
{
// Cast control as DDL and do your work
}
Related
I have tons of Buttons named like this x0y1
How do I access the variable name dynamically so I could loop all names by xiy1 or so.
in PHP it would be like ${"myString" . $randomvar}
I can't use a list or array because the the button already exist defined through the xaml
You can use:
var textbox =
this.Controls.OfType<TextBox>().Where(txb => txb.Name == "myString").FirstOrDefault();
This assumes you are in the context of your form (this.Controls).
And of course, don't forget to add using System.Linq;...
You can get all the textbox using this method
void AllTextBox(System.Windows.Forms.Control.ControlCollection ctrls)
{
foreach (Control ctrl in ctrls)
{
if (ctrl is TextBox)
{
if (ctrl.Name == "textBox1")
{
// do your stuf with textbox
}
}
}
}
You can create function that return control by name :
Control GetControlByName(string Name)
{
foreach(Control control in this.Controls)
if(c.Name == Name) return control ;
return null;
}
or Function with a specific control like that :
Button GetButtonByName(string Name)
{
foreach (Control c in this.Controls.OfType<Button>())
if (c.Name == Name) return c;
return null;
}
For wpf project...
Let's say you have a grid named MyGrid and there's lot of buttons on it.
You want to refer to the button named x0y1:
var btn = MyGrid.Children.OfType<Button>().Where(x=>x.Name=="x0y1");
Note: above code should work for flat structure (one level deep only).
You can achieve the same by using code provided in this thread: How can I find WPF controls by name or type?
Just call FindName("elementName"). FindName searches through all child elements of a FrameworkElement. To access any button by its name as string in a window, call the FindName() method of the window !
If your code is in a class inheriting from Window, just use:
Button button = (Button)FindName("xiy1");
If you write the code in a class not inheriting from Window but FrameworkElement, which is unlikely, use:
Window window = Window.GetWindow(this);
Button button = (Button)window.FindName("xiy1");
Check the MSDN documentation about Namescopes for more information about limitations.
I'm cycling over my WinForms controls and give their Text and ToolTipText to my Translation service for translation.
Example:
foreach (ToolStripItem item in toolStrip.Items)
{
if (item is ToolStripMenuItem)
{
item.ToolTipText = Translate(item.ToolTipText);
item.Text = Translate(item.Text);
}
}
However, I cannot access tooltips set by using the WinForms ToolTip control.
I see I can cycle over the components. Can I Get and Set their tooltips?
protected void TranslateToolTip(ToolTip toolTip)
{
foreach (var component in toolTip.Container.Components)
{
// Doesn't work. No ToolTipText property
component.ToolTipText = Translate(component.ToolTipText);
}
}
Can I access the tooltip text directly from the control?
To set a tooltip text on all components in your form like button1 etc. I think you should use something like this:
foreach (var control in this.Controls) {
ToolTip1.SetToolTip(this.control, "Your text");
}
That's because ToolTip doesn't have a Text property and it's set like on example above.
See also ToolTip Class and ToolTip.SetToolTip Method and ToolTip.GetToolTip Method
Or you can try something like that but not sure if this gonna work:
protected void TranslateToolTip(ToolTip toolTip)
{
foreach (var component in toolTip.Container.Components)
{
// Doesn't work. No ToolTipText property
// component.ToolTipText = Translate(component.ToolTipText);
toolTip.SetToolTip(component , (string)Translate(toolTip.GetToolTip(component));
}
}
I don't know what Translate(component.ToolTipText) is supposed to return. If it's just translated string, then we don't need the (string) part in my exmple.
Hope it helps.
EDIT: Fixed second example to show how to Set and Get tooltip text from specific control.
i get an InvalidArgumentException while casting Control to System.Windows.Forms.Textbox:
Unable to cast object of type 'System.Windows.Forms.Control' to type 'System.Windows.Forms.TextBox'.
System.Windows.Forms.Control control = new System.Windows.Forms.Control();
control.Width = currentField.Width;
//here comes the error
((System.Windows.Forms.TextBox)control).Text = currentField.Name;
I am doing this, because I have different Controls (Textbox, MaskedTextbox, Datetimepicker...), which will dynamically be added to a panel and have the same basic properties (Size, Location... -> Control)
Why isn't the cast possible?
The cast fails because control is not a TextBox. You can treat a TextBox as a control (higher up the type hierarchy) but not any Control as a TextBox. For setting common properties you can just treat everything as Control and set them whereas you have to create the actual controls you want to use beforehand:
TextBox tb = new TextBox();
tb.Text = currentField.Name;
Control c = (Control)tb; // this works because every TextBox is also a Control
// but not every Control is a TextBox, especially not
// if you *explicitly* make it *not* a TextBox
c.Width = currentField.Width;
You control is an object of Control class which is parent class. May be more controls are inheriting from parent.
Hence a child can be cast as parent but not vice versa.
Instead use this
if (control is System.Windows.Forms.TextBox)
(control as System.Windows.Forms.TextBox).Text = currentField.Name;
or
Make a TextBox object. That one will always be a TextBox and you do not need checking/casting for it.
Joey is right:
your control isn't a textbox! You can test types using:
System.Windows.Forms.Control control = new System.Windows.Forms.Control();
control.Width = currentField.Width;
if (control is TextBox)
{
//here comes the error
((System.Windows.Forms.TextBox)control).Text = currentField.Name;
}
All your controls inherit from System.Windows.Forms.Control. However, a TextBox is not the same as DateTimePicker, for example, so you cannot cast them to each other, only to the parent types. This makes sense as each control is specialized for doing certain tasks.
Given that you have controls of different types, you may wish to test the type first:
if(control is System.Windows.Forms.TextBox)
{
((System.Windows.Forms.TextBox)control).Text = currentField.Name;
}
You can also speculatively cast to the type using the 'as' keyword:
TextBox isThisReallyATextBox = control as TextBox;
if(isThisReallATextBox != null)
{
//it is really a textbox!
}
I am looking for a way to loop through controls on a particular tab of a tabcontrol. For example, I have a tabcontrol with the following tabs:
Cars,
Pets,
Admin
On each of these tabs are several controls to display/edit/save data, etc. On the "Save" button, I would like to loop through the controls for that particular tab to check whether all required fields have been filled in.
So, if I am on the Cars tab and click "Save," I want to loop ONLY through the controls on the Cars tab and NOT the Pets or Admin tabs.
How can achieve this result?
As for looping through a TabControl's controls, you need to use the Controls property.
Here's an MSDN article on the TabControl.
Example:
TabPage page = aTabControl.SelectedTab;
var controls = page.Controls;
foreach (var control in controls)
{
//do stuff
}
I feel it's important to note that, in general, you should take a more structured approach to your application. E.g., instead of having all the controls on three tab pages, include exactly one UserControl on each tabpage. A CarUserControl, PetUserControl, and AdminUserControl e.g. Then each user control knows how to create the proper respective data structure so you don't have to manually munge it all together at the same level of abstraction using inter-tab loops and whatnot.
Such a separation of concerns will make it much easier to reason about your program and is good practice for writing maintainable code for your future career.
Example where I wanted to get the DataGridView in a particular tab for an application I wrote.
TabPage pg = tabControl1.SelectedTab;
// Get all the controls here
Control.ControlCollection col = pg.Controls;
// should have only one dgv
foreach (Control myControl in col)
{
if (myControl.ToString() == "System.Windows.Forms.DataGridView")
{
DataGridView tempdgv = (DataGridView)myControl;
tempdgv.SelectAll();
}
}
The Controls property is the way to go...
foreach(Control c in currentTab.Controls)
{
if(c is TextBox)
// check for text change
if(c is CheckBox)
//check for check change
etc...
}
TabControl has a SelectedTab property, so you'd do something like this:
foreach(Control c in tabControl.SelectedTab.Controls)
{
//do checks
}
foreach (Control c in this.tabControl1.SelectedTab.Controls)
{
// Do something
}
I had the need to disable or enable controls of a tab as well. I had to go a bit more generic though. Hope it helps people and I didn't make a mistake
private void toggleControls(Control control, bool state)
{
foreach (Control c in control.Controls)
{
c.Enabled = state;
if (c is Control)
{
toggleControls(c, state);
}
}
}
I have an event handler for a Textbox and a RichTextBox.
The code is identical, but
In handler #1 I do:
RichTextBox tb = (RichTextBox)sender
In handler #2 accordingly:
TextBox tb = (TextBox)sender
Doing so I can fully manipulate the sending control.
How can I cast the sending object to Textbox or RichTextbox according to its type using
sender.GetType().Name
and then create the control at runtime and work with it? That way I only need one event handler function: less code, less errors, easier to maintain and DRY :-)
You never have to cast. I used to think the same way when I started, this 'pattern' is incorrect, and not really logical.
Your best bet is to use something like:
if (sender is TextBox)
{
TextBox tb = (TextBox)sender;
}
else if (sender is RichTextBox)
{
RichTextBox rtb = (RichTextBox)sender;
}
else
{
// etc
}
I know this is a very old post but in Framework 4 you can cast the sender as a Control:
Control cntrl = (Control)sender;
cntrl.Text = "This is a " + sender.GetType().ToString();
Note you are only able to reference controls that all of the different controls have in common (ie Text).
Rather than the type name you could use 'is'.
If you just want to know the type and don't need an object reference:
if (sender is RichTextBox)
{
// ...
}
else if (sender is TextBox)
{
// ...
}
However you generally do want the object: C#7 has a nice syntax that allows you to test and get the value inline:
if (sender is RichTextBox richTextBox)
{
richTextBox.Text = "I am rich";
}
else if (sender is TextBox textBox)
{
textBox.Text = "I am not rich";
}
RichTextBox textbox = sender as RichTextBox;
if (textbox != null)
{
// do stuff as a rtb
textbox.Text = "I'm a rtb";
return;
}
TextBox textbox = sender as TextBox;
if (textbox != null)
{
// do stuff as a textbox
textbox.Text = "I'm a textbox";
}
Depending on what properties you need, you could cast the sender as a TextBoxBase as both the TextBox and RichTextBox both inherit from that sub-class.
Casting can only be done at compile-time and thus you need to know the types that you wish to cast to at compile-time. A runtime Type (as returned by GetType()) can therefore not be used when casting.
If it is polymorphism you are looking for you could access the Name property through reflection. I wouldn't go that way though just to be able to reuse event handlers.
If you want strong typing, a common base class or interface on the two senders is the only way to go.
Generic version of the above code:
public static void CastAndUse<T>(object item, Action<T> action) where T : class
{
T thing = item as T;
if (thing != null)
{
action(thing);
}
}
Used as:
CastAndUse(sender, new Action((foo) => foo = bar));
Not perfect, but handy.
You can also use an inline-temporary variable to handle the cast for you.
if (sender is RichTextBox tb)
{
// ... //
}
else if (sender is TextBox tb)
{
// ... //
}
If the code is identical, do you need to care? I wonder if casting to Control wouldn't give you everything you need...
One complex handler is not necessarily better than several simple handlers. Either way, if you have to go this route, "as"/"is" is preferable (it isn't dependent on strings etc):
TextBox tb = sender as TextBox;
if(tb!=null) {/* TextBox specific code */}
...
if you dont want to repeat the code then you can cast both the controls, refactor the common actions to a separate method which takes TextBoxBase as an argument. And in your event handlers convert the controls to System.Windows.Forms.TextBoxBase as both controls are derived from the TexbBoxBase and call the method.
Please note If you need specific properties of any of these controls then this refactoring wont work.