How to dynamically set a control using variables C# - c#

How do you dynamically call a control and set it property at runtime?
// Declare and set queue servers
string[] queueservers = new string[] { "SERVER1", "SERVER2", "SERVER3", "SERVER4" };
int y;
for (y = 0; y <= queueservers.Length - 1; y++)
{
string queueanswer = GetMailQueueSize(queueservers[y]);
if (queueanswer == "alarm")
{
phxQueueImg + queueservers + .ImageUrl = "~/images/Small-Down.gif";
}
else
{
phxQueueImg + queueservers + .ImageUrl = "~/images/Small-Up.gif";
}
queueanswer = "";
}

See here about asking good questions .
I'm going to assume you pasted the wrong code since it doesn't seem to have anything to do with the question afaik. Plus could edit your question and tag if this is winform, wpf or web?
Here I dynamically create the control at runtime:
Textbox c = new Textbox();
Set its text, eg
string s = "Please paste code that relates to your question";
c.Text = s;
Or here I dynamically set my textbox controls property using variables:
propertyInfo = c.GetType().GetProperty(property);
if (propertyInfo != null)
{
propertyInfo.SetValue(c, value, null);
}

try FindControl("controlID") and then cast the result of this call to the required control type and set the needed property.
(SomeParentControl.FindControl("IDOfControlToFind") AS LinkButton).PostBackUrl = "~/someresource.aspx";

Related

WPF C# Dynamic event routing in programmatically created element

I've provided, in a seperated class, some methods to create an element dynamically. Creating that element dynamically is not the problem but routing the event.
My thoughts where that the "path" (like namespace.class.method) is submitted via a parameter in the creating method.
But up to now, I was not able to attach such an event listener. I did many researches using Google and StackOverflow, but without any success.
I post the source code of the method below.
The code in the if-section for "EventHandler" is not empty was my last attempt.
Is it possible that my thoughts will work or is it only possible to attach event handlers in the main class that is initializing the app.
static public WrapPanel comboBox(string Name, List<string> Items, bool MultiSelection = false, string EventHandler="",string Label="", int Width = 0)
{
WrapPanel lPanel = new WrapPanel();
lPanel.Name = "stPanel_" + Name;
if (Label != "")
{
Label lLabel = new Label();
lLabel.Content = Label;
lPanel.Children.Add(lLabel);
if (Width != 0)
{
lPanel.Width = Width;
}
}
dynamic lComboBox;
if (MultiSelection)
{
lComboBox = new ComboBoxAdv();
lComboBox.AllowMultiSelect = true;
}
else lComboBox = new ComboBox();
lComboBox.Name = Name;
foreach (string Item in Items) lComboBox.Items.Add(Item);
lPanel.Children.Add(lComboBox);
ComboBox dkaf = new ComboBox();
if (EventHandler != "")
{
string lClass = "";
string lMethod = EventHandler.Split('.').Last();
for (int lCounter = 0; lCounter < EventHandler.Split('.').Length - 1; lCounter++)
lClass += EventHandler.Split('.')[lCounter] + ".";
lClass = lClass.Substring(0, lClass.Length - 1);
object dynamicObject;
Type objectType = Type.GetType(lClass);
dynamicObject = Activator.CreateInstance(objectType);
System.Reflection.MethodInfo method = objectType.GetMethod(lMethod);
//method.Invoke(dynamicObject, new object[] { });
lComboBox.Click += new RoutedEventHandler(method);
}
return lPanel;
}
Best regards
Chris

How to assign text to a Label with the Label ID being assigned by a string?

Target:
To write in the label text, but the label ID is assigned by a string.
Problem:
It doesn't work, no errors given. I looked in most places for an answer but nothing helped!
My Code:
string asdfj = treeView2.SelectedNode.Text;
string adqien = System.IO.Path.Combine(dir7, asdfj);
string[] tnsop = System.IO.File.ReadAllLines(#adqien);
h1a.Text = "100";
for (int o = 2; o > 6; o++)
{
//This is the label name e.g "h2a',h3a" etc
string tempc = string.Format("h" + o.ToString() + "a");
foreach (Control ctr in this.Controls)
{
if (ctr is Label)
{
if (ctr.Name == tempc)
{
ctr.Text = tnsop[o];
}
}
}
}
I also consulted this post:
Use string variable content as label ID to update label.Text, I get error - 'string' does not contain a definition for 'Text'
You can do it simply like:
this.Controls.Find(labelname).Text = Value;
or
this.Controls.OfType<Label>().FirstOrDefault(x => x.Name == labelName).Text = Value;
The for loop
First of all, this is wrong for (int o = 2; o > 6; o++).
It starts at o = 2, then checks if o > 6, which is false, because o = 2, and then skips the loop.
I guess you wanted to write: for (int o = 2; o < 6; o++). I am not sure about that, fix it as appropiate.
Addendum: This would have been easily discovored by debugging and stepping. You can start by adding a break point on your code (in Visual Studio you can place your cursor on the desired line and press F9 - by default) and then run in the debugger. When the a line with the break point is reached, the debbuger stops the execution and let you inspect the values of the variables, the call stack, etc. You can then step with F10 or F11 (if you want to inside a method call) and see how the code evolves. You would notice it does not enter the for loop.
Finding the labels
If finding the label still does not work, I would guess the problem is that the labels are not directly on the form or that they do not have the given name.
You can use this.Controls.Find(name, searchAllChildren) to get the labels you need.
That is:
string labelName = string.Format("h" + o.ToString() + "a");
Control[] control = this.Controls.Find(labelName, true);
Note: Yes, I can figure out it is the name of the label by how you use it. Using a comment to tell me saves some time... however, please use better variable names. You won't need a comment to tell me this is the name of the label if the variable name says so.
You still need to check it for the label:
string labelName = string.Format("h" + o.ToString() + "a");
Control[] controls = this.Controls.Find(labelName, true);
foreach (Control control in controls)
{
if (control is Label) // if (control.GetType() == typeof(Label))
{
// ...
}
}
Building a Dictionary
However, I would advice against doing this every time. Instead, I suggest to build a dictionary:
Dictionary<string, Label> labels;
// ...
labels = new Dictionary<string, Label>();
for(int o = 2; o < 6; o++)
{
string labelName = string.Format("h" + o.ToString() + "a");
Label label = GetLabel(labelName);
labels.Add(labelName, label);
}
// ...
private Label GetLabel(string labelName)
{
Control[] controls = this.Controls.Find(labelName, true);
foreach (Control control in controls)
{
if (control is Label) // if (control.GetType() == typeof(Label))
{
return control as Label;
}
}
return null;
}
Note: I suggest to make the dictionary a field and initialize it only once during the form load.
This separates the responsability of finding the labels from reading the file (which is external to the program). Allowing you to test if it can find the right controls without the need of a file.
It will also make the case where the Label is not found visible (we just added a null to the dictionary).
And then use it:
string[] tnsop = System.IO.File.ReadAllLines(#adqien);
for (int o = 2; o < 6; o++)
{
string labelName = string.Format("h" + o.ToString() + "a");
label = labels[labelName];
label.Text = tnsop[o];
}
The code above should throw NullReferenceException if the label was not found while building the dictionary.
Simplify
I guess we can do better. The designer will create fields for your labels, you can just add them to the dictionary:
Dictionary<string, Label> labels;
// ...
labels = new Dictionary<string, Label>();
labels["h2a"] = h2a;
labels["h3a"] = h3a;
labels["h4a"] = h4a;
labels["h5a"] = h5a;
// ...
string[] tnsop = System.IO.File.ReadAllLines(#adqien);
for (int o = 2; o < 6; o++)
{
string labelName = string.Format("h" + o.ToString() + "a");
label = labels[labelName];
label.Text = tnsop[o];
}
Note: There are plenty of opportunities for more modern syntax, including collection initialization and the var keyword.
Addendum: I am unrolling the loop in the above code, this is ok for maintainability if the number of iterations small, in fact, it is a common optimization. You could, in theory do it for the other loop too.
PS. An array will do
I noticed, after finishing writing, that the code only needs to look up by an int o.
We can rework to use int for dictionary keys:
Dictionary<int, Label> labels;
// ...
labels = new Dictionary<int, Label>();
labels[2] = h2a;
labels[3] = h3a;
labels[4] = h4a;
labels[5] = h5a;
// ...
string[] tnsop = System.IO.File.ReadAllLines(#adqien);
for (int o = 2; o < 6; o++)
{
label = labels[o];
label.Text = tnsop[o];
}
Now we have less concatenations, and a simpler code.
We could, in fact, be using an array:
Label[] labels;
// ...
labels = new Label[4];
labels[0] = h2a;
labels[1] = h3a;
labels[2] = h4a;
labels[3] = h5a;
// ...
string[] tnsop = System.IO.File.ReadAllLines(#adqien);
for (int o = 2; o < 6; o++)
{
label = labels[o - 2];
label.Text = tnsop[o];
}
Notice I did offset the indexes to be able to use the array from index 0.

How to Clone a Windows Forms Controls even with non-Serializable properties?

How to Clone or Serialize a Windows Forms Control?
When I am trying to Clone windows forms controls using this code "CloneControl(Control ct1)", it allows me to duplicate controls with some Serializable properties, not with all properties.
public Form1()
{
InitializeComponent();
Columns = new DataGridViewTextBoxColumn[2];
for (int i = 0; i < 2; i++)
{
Columns[i] = new System.Windows.Forms.DataGridViewTextBoxColumn();
//
// Columns[i]
//
Columns[i].HeaderText = "j" + (i + 1);
Columns[i].Name = "Column" + (i + 1);
Columns[i].Width = 50;
}
dataGridView1 = new System.Windows.Forms.DataGridView();
dataGridView1.Name = "dataGridView1";
dataGridView1.Location = new System.Drawing.Point(100, 100);
dataGridView1.RowHeadersWidth = 50;
dataGridView1.RowTemplate.Height = 25;
dataGridView1.Size = new System.Drawing.Size(55 + 50 * 2, 25 + dataGridView1.RowTemplate.Height * 2);
dataGridView1.Anchor = System.Windows.Forms.AnchorStyles.None;
dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
dataGridView1.Columns.AddRange(Columns);
dataGridView1.TabIndex = 3;
dataGridView1.AllowUserToAddRows = false;
dataGridView1.Rows.Add();
dataGridView1.Rows.Add();
dataGridView1.Rows[0].HeaderCell.Value = "i" + 1;
dataGridView1.Rows[1].HeaderCell.Value = "i" + 2;
dataGridView1.Rows[0].Cells[0].Value = "value1";
Controls.Add(dataGridView1);
Control cloned1 = CloneControl(dataGridView1);
cloned1.SetBounds(cloned1.Location.X, cloned1.Location.Y + 300, cloned1.Width, ct1.Height);
Controls.Add(cloned1);
cloned1.Show();
}
public Control CloneControl(Control ct1)
{
Hashtable PropertyList = new Hashtable();
PropertyDescriptorCollection Properties = TypeDescriptor.GetProperties(ct1);
Assembly controlAsm = Assembly.LoadWithPartialName(ct1.GetType().Namespace);
Type controlType = controlAsm.GetType(ct1.GetType().Namespace + "." + ct1.GetType().Name);
Control cloned1 = (Control)Activator.CreateInstance(controlType);
foreach (PropertyDescriptor pr1 in Properties)
{
if (pr1.PropertyType.IsSerializable)
{
PropertyList.Add(pr1.Name, pr1.GetValue(ct1));
}
if (PropertyList.Contains(pr1.Name))
{
try
{
Object obj = PropertyList[pr1.Name];
pr1.SetValue(cloned1, obj);
}
catch (Exception ex)
{
}
}
}
return ct2;
}
If you run the code... the you will get
As you can see in the main method I create a clone of dataGridView1, which has a few properties.
And actually each cell value is null in a cloned dataGridView.
Also size of a columns are not cloned!
You may have a question: if Visual Studio or SharpDeveloper as IDE which is written in C# can handle this problem, then it might be possible to write that kind of code! Right?
In Visual Studio When you are trying drag and drop controls, or copy and paste controls, it not only duplicates that controls with all properties (including Serializable or non-Serializable) but also it changes the name of control itself from "dataGridView1" to "dataGridView2" as well as in SharpDeveloper!
What should I do?
What kind of method should I create?
Maybe another control has a many non-Serializable properties!
How to duplicate all of them?
Please anyone.....
Like #Hans mentioned in the comment, Clone is not that easy. If you want to get some identical controls with only a bit different, you'd better use a function to define general behavior and pass the different properties in as parameters. For example, we define a function with some general properties which apply to DataGridView:
private void InitDataGridView(DataGridView dataGridView, string name)
{
dataGridView.Name = name;
// configure other properties here
dataGridView.Location = new System.Drawing.Point(100, 100);
dataGridView.RowHeadersWidth = 50;
dataGridView.RowTemplate.Height = 25;
dataGridView.Size = new System.Drawing.Size(55 + 50 * 2, 25 + dataGridView1.RowTemplate.Height * 2);
dataGridView.Anchor = System.Windows.Forms.AnchorStyles.None;
dataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
// remember to initialize your columns, or pass it in as a parameter
dataGridView.Columns.AddRange(Columns);
dataGridView.AllowUserToAddRows = false;
dataGridView.Rows.Add();
dataGridView.Rows.Add();
dataGridView.Rows[0].HeaderCell.Value = "i" + 1;
dataGridView.Rows[1].HeaderCell.Value = "i" + 2;
dataGridView.Rows[0].Cells[0].Value = "value1";
}
public Form1()
{
InitializeComponent();
var dataGridView1 = new DataGridView();
var dataGridView2 = new DataGridView();
InitDataGridView(dataGridView1, "dataGridView1");
InitDataGridView(dataGridView2, "dataGridView2");
}
IDE (e.g. Visual Studio) is using PropertyDescriptors, DesignerSerializationVisibility and ShouldSerializeValue, but DataGrid Rows are something special, because you cannot add them at design time! IDE cannot copy something that is not there, so, the solution must be different (if you want to clone controls beyond what IDE/Designer can do - see other answers and comments for this). Try my code (everything except grid rows got cloned without the extra check - the columns got cloned).
foreach(PropertyDescriptor pd in TypeDescriptor.GetProperties(src)) {
if(!pd.ShouldSerializeValue(src)) {
if(src is DataGridView && pd.Name == "Rows")
CopyDataGridRows((DataGridView)src, (DataGridView)dst);
continue; }
Note: The above can be done better (by check for the class at the end), but is as it is to be obvious.
using System;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
namespace CloneControls {
public partial class Form1: Form {
public Form1() { InitializeComponent(); }
private void Form1_Load(object sender, EventArgs e) {
dataGridView1.Rows.Add();
dataGridView1.Rows.Add();
foreach(Control c in splitContainer1.Panel1.Controls)
splitContainer1.Panel2.Controls.Add((Control)Clone(c));
}
static object Clone(object o) {
return Copy(o, Activator.CreateInstance(o.GetType()));
}
static object Copy(object src, object dst) {
IList list = src as IList;
if(list != null) {
IList to = dst as IList;
foreach(var x in list)
to.Add(Clone(x));
return dst; }
foreach(PropertyDescriptor pd in TypeDescriptor.GetProperties(src)) {
if(!pd.ShouldSerializeValue(src)) {
if(src is DataGridView && pd.Name == "Rows")
CopyDataGridRows((DataGridView)src, (DataGridView)dst);
continue; }
switch(pd.SerializationVisibility) {
default: continue;
case DesignerSerializationVisibility.Visible:
if(pd.IsReadOnly) continue;
pd.SetValue(dst, pd.GetValue(src));
continue;
case DesignerSerializationVisibility.Content:
Copy(pd.GetValue(src), pd.GetValue(dst));
continue;
}
}
return dst;
}
static void CopyDataGridRows(DataGridView src, DataGridView dst) {
foreach(DataGridViewRow row in src.Rows)
if(!row.IsNewRow) dst.Rows.Add((DataGridViewRow)Clone(row));
}
}
}
I think I made more better method here.
This Method at first checks interface of property: if it is ICollection then it does the first job.
After this one loop ends in the method "DeepClone()", then it is necessary to do another loop without checking PropertyType Interface... I mean I could not mix these two operation into one loop?!
Also You can detect that there will be some kind of Run-time Exceptions and for this reason I put this code into try-catch block...
Control cloned1 = (Control)DeepClone(dataGridView1);
cloned1.SetBounds(cloned1.Location.X, cloned1.Location.Y + 300, cloned1.Width, ct1.Height);
Controls.Add(cloned1);
cloned1.Show();
public dynamic DeepClone(dynamic ob1)
{
dynamic ob2 = null;
if (ob1.GetType().IsSerializable && !ob1.GetType().IsArray)
{
if (ob1 != null)
{
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(ms, ob1);
ms.Position = 0;
ob2 = formatter.Deserialize(ms);
}
}
}
else
{
if (ob1.GetType().IsArray)
{
var r1 = ob1.Rank;
object[] d1 = new object[r1];
long[] V1 = new long[r1];
for (int i = 0; i < r1; i++)
{
V1[i] = 0;
d1[i] = ob1.GetUpperBound(i) + 1;
}
ob2 = Activator.CreateInstance(ob1.GetType(), d1);
for (long i = 0; i <= ob2.Length; i++)
{
ob2.SetValue(DeepClone(ob1.GetValue(V1)), V1);
for (int j = 0; j <= V1.GetUpperBound(0); j++)
{
if (V1[j] < ob2.GetUpperBound(j))
{
V1[j]++;
break;
}
else
{
V1[j] = 0;
}
}
}
}
else
{
PropertyInfo[] P1 = ob1.GetType().GetProperties();
ob2 = Activator.CreateInstance(ob1.GetType());
foreach (PropertyInfo p1 in P1)
{
try
{
if (p1.PropertyType.GetInterface("System.Collections.ICollection", true) != null)
{
dynamic V2 = p1.GetValue(ob1) as IEnumerable;
MethodInfo gm1 = p1.PropertyType.GetMethods().Where(m => m.Name == "Add").Where(p => p.GetParameters().Count() == 1).First(f => V2[0].GetType().IsSubclassOf(f.GetParameters()[0].ParameterType) || f.GetParameters()[0].ParameterType == V2[0].GetType());
if (V2[0].GetType().IsSubclassOf(gm1.GetParameters()[0].ParameterType) || gm1.GetParameters()[0].ParameterType == V2[0].GetType())
{
for (int i = 0; i < V2.Count; i++)
{
dynamic V3 = DeepClone(V2[i]);
gm1.Invoke(p1.GetValue(ob2), new[] {V3});
}
}
}
}
catch (Exception ex)
{
}
}
foreach (PropertyInfo p1 in P1)
{
try
{
if (p1.PropertyType.IsSerializable && p1.CanWrite)
{
var v2 = p1.GetValue(ob1);
p1.SetValue(ob2, v2);
}
if (!p1.PropertyType.IsSerializable && p1.CanWrite)
{
dynamic V2 = p1.GetValue(ob1);
if (p1.PropertyType.GetMethod("Clone") != null)
{
dynamic v1 = V2.Clone();
p1.SetValue(ob2, v1);
}
}
}
catch (Exception ex)
{
}
}
}
}
return ob2;
}
You may say that this Method does not copy some kind of property, But it does copy of main properties and the Cloned control will look like an original control!
Trying to clone a control is overkill except if you really need a totally generic control clone method. Most of the time, you only need to clone a specific control and you have an easy access to the code that created it (see the Form designer generated code, and the setup code you wrote yourself).
But nevertheless, I once used a trick to duplicate many controls at once in order to fill the new tabs of a TabControl, choosing one out of ten tab designs.
I also wanted to use the Form design tool of the C# IDE to edit and modify the 10 template.
So, besides my Tab control form, and using the VS IDE, I created 10 "control factory dummy forms" in my project. I put a dummy Panel control in each of it.
Each time I had to dynamically create a new Tab, I simply instantiated a new dummy window of the desired style. Then I simply moved the Parent pane to my ControlTab (using the Controls.Add() method of the new tab).
This way, you must link the event handlers after the Tab creation (after the controls move). And the event handler's code should be written in you main window class, otherwise you will have "this" reference problems.
Obviously, you will have to store control references somewhere, to be able to access them. The easiest way to do this is to just keep track of each "dummy template Form" you instantiate and to set the "modifier" of your controls to be "public". You can use the Tag property of the destination tab page to store that reference. But, to avoid many casts, it is better to declare an array of each form class, and to store the references there.

Check if TextBox is created, then assign it's value

I'm trying to make a small app, for make my job easier creating definitions (new web forms aspx) via WinForms C#.
Now I have this form, where I tell the app how many textboxes I want to create.
After their creation, I want to assign to a string the textboxes values that I wrote.
private void CreateControls()
{
for (int index = 0; index < NumberOfRows; index++)
{
TextBox textBox = new TextBox();
textBox.Name = "TextBox" + (index + 1).ToString();
textBox.Size = new Size(120, 20);
textBox.Location = new Point(X, Y + 26);
ComboBox comboBox = new ComboBox();
comboBox.Name = "ComboBox" + (index + 1).ToString();
comboBox.Size = new Size(75, 20);
comboBox.Location = new Point(141, Y + 26);
comboBox.DataSource = Enum.GetNames(typeof(DataTypes));
Y += 26;
this.Controls.Add(textBox);
this.Controls.Add(comboBox);
}
}
Now, I don't know how to check if the textboxes are created, and then take their values.
Could anyone refer me something? Thanks :)!
You'll need to, on Page_Load, find those controls and grab their values. Since you gave them meaningful names when you created them, this should do the trick:
for (int index = 0; index < NumberOfRows; index++)
{
TextBox textBox = this.FindControl(
string.Format("TextBox{0}", index)) as TextBox;
if (textBox == null) { continue; } // this means it wasn't found
var text = textBox.Text;
// work with the text
}
However, if the ComboBox class you're using isn't a third-party one and it's not an ASP.NET application, the code would work for a Windows Forms application as well with a minor modification:
for (int index = 0; index < NumberOfRows; index++)
{
// you have to use the Find method of the ControlCollection
TextBox textBox = this.Controls.Find(
string.Format("TextBox{0}", index)) as TextBox;
if (textBox == null) { continue; } // this means it wasn't found
var text = textBox.Text;
// work with the text
}
I tend to agree with the community that it's probably a Windows Forms application because you can't set the Location of a standard ASP.NET control. However, if these are user controls, or third-party ones, that support those properties and render the appropriate CSS then we'd never know.
if(Page.FindControl("IDofControl") != null)
//exists
else
//does no exists

Dynamically changing multiple check boxes ID with C#

Whats the best way for me to change the ID's of the check boxes, like as in using a loop, the problem I'm having is with the current control ID CheckBox1.ID, i cant seem to change the 1 to be used as a variable
CheckBox1.ID = "chckbx_1";
CheckBox2.ID = "chckbx_2";
CheckBox3.ID = "chckbx_3";
CheckBox4.ID = "chckbx_4";
CheckBox5.ID = "chckbx_5";
CheckBox6.ID = "chckbx_6";
Is there any way where i can implement this logic?, and please note, I'm using web forms
Try something like this:
for (int i = 1; i < some_number; i++)
{
Control myControl = FindControl("CheckBox" + i.ToString());
if(myControl != null && myControl.GetType() == typeof(CheckBox))
{
((CheckBox)myControl).ID = "chckbx_" + i.ToString();
((CheckBox)myControl).CssClass = "newClass";
}
}

Categories

Resources