It is possible to copy all the properties of a certain control? (C# window forms)
You'll need to use reflection.
You grab a reference to each property in your source control (based on its type), then "get" its value - assigning that value to your target control.
Here's a crude example:
private void copyControl(Control sourceControl, Control targetControl)
{
// make sure these are the same
if (sourceControl.GetType() != targetControl.GetType())
{
throw new Exception("Incorrect control types");
}
foreach (PropertyInfo sourceProperty in sourceControl.GetType().GetProperties())
{
object newValue = sourceProperty.GetValue(sourceControl, null);
MethodInfo mi = sourceProperty.GetSetMethod(true);
if (mi != null)
{
sourceProperty.SetValue(targetControl, newValue, null);
}
}
}
Copying a Control between forms moves it instead
You are only copying the reference to your control. But a control can only be used in one form. So the control is dissapearing in the "old" form. You need real copies of your controls.
This Question describes a way to copy a control via reflection. Try it with a solution like this:
private void copyControl(Control sourceControl, Control targetControl)
{
// make sure these are the same
if (sourceControl.GetType() != targetControl.GetType())
{
throw new Exception("Incorrect control types");
}
foreach (PropertyInfo sourceProperty in sourceControl.GetType().GetProperties())
{
object newValue = sourceProperty.GetValue(sourceControl, null);
MethodInfo mi = sourceProperty.GetSetMethod(true);
if (mi != null)
{
sourceProperty.SetValue(targetControl, newValue, null);
}
}
}
C#: Copy all properties from one Label to another Label. Is it possible?
What you are describing is known as a "Deep Copy". There are several ways to accomplish this that range in the amount of technical wizardry involved, but for your case, I would suggest keeping it simple and just using a helper method to duplicate all the properties you care about:
public static Label CopyLabel(Label label)
{
Label l = new Label();
l.Left = label.Left;
l.Top = label.Top;
l.Right = label.Right;
l.Bottom = label.Bottom;
l.Width = label.Width;
l.Height = label.Height;
l.Margin = label.Margin;
l.Text = label.Text;
// Add whatever other properties you deem important
return l;
}
And call it like so:
Label newLabel = CopyLabel(label1);
(If you really do want to perform a true deep copy, then you can check out existing answers here and here.)
Can I use multiple copies of a Windows Forms Control?
For example, you want to have labels that their text are same in your designer.
We make a class, say LabelTextResourced
public class LabelTextResourced: Label
{
private string _textResourceName;
public string TextResourceName
{
get { return _textResourceName; }
set
{
_textResourceName = value;
if (!string.IsNullOrEmpty(_textResourceName))
base.Text = Properties.Resources.ResourceManager.GetString(_textResourceName);
}
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text
{
get { return base.Text; }
set
{
// Set is done by resource name.
}
}
}
Build your project, now you can add LabelTextResourced
control to your designer.
Right click your project and go to properties and select resource tab.
add a resource for example: {Name: "LabelText", Value: "Hiiiiii!!!"}
Now, go back to form designer, select your instance of LabelTextResourced
and set it's TextResourceName
property to LabelText
.
Build again and now you should see that your label text is set from the resource. Now you can have many label that their text are all set from one location and changing the LabelText
resource (and a build) results to changing of all of you LabelTextResourced
controls that have LabelText
as their TextResourceName
.
This is just a starting point, you can customize this class and any other properties you want with some effort.
WinForm - Copy TabControl with OWN behaviour
Your code has at least two issues not related to the actual question. Let's fix two of them first:
You set all properties even those you should not set; most notably you should not touch the
"WindowTarget"
property! It is for internal use only and messing with it will stop at least some controls from working. I found I couldn't check aCheckBox
, for example.Your code only will create visible controls if the orginal
TabPage
is also the current one. All controls on all other pages are invisible and if you try to clone any otherTabPage
all control will be added just fine but remain invisible.
Let's add a filter :
if(entry.Name != "WindowTarget") entry.SetValue(cNew, val);
and make the new controls visible:
cNew.Visible = true;
tpNew.Controls.Add(cNew);
Note that this is a simplistic solution as it will also make those controls visible that were invisible originally. You could instead show the page you want to clone or make a list of invisible controls; with their names you could find the cloned counterparts..
The last issue is also important but goes beyond the question: The code only clones the controls directly on the page, not any neseted controls (like RadioButtons
in a GroupBox
!). To do so you would have to write a recursive version!
- Now for the actual question: How can you give the cloned controls their own behaviour?
After cloning all their properties they are like freshly added controls, i.e. they have no event handlers at all.
So you need to
- write new event handlers for the new controls' events
- hook them up
While this is not really hard there are quite a few problems..
We know the naming scheme and so we can know which controls we want to supply with events. The event names are free to choose but to hook them up we need to know which of the new controls we are dealing with..
Here is and example that hooks up the first clone of a Button cb_hello
with a Click
event:
if (cNew.Name == "cb_hello1") cNew.Click += buttonNew_Click;
The code in the event demonstrates more issues:
private void buttonNew_Click(object sender, EventArgs e)
{
Button btn = sender as Button;
Console.WriteLine(btn.Name + " says hiho");
btn.Parent.Controls["panel41"].BackColor = Color.ForestGreen;
((RadioButton)btn.Parent.Controls["radioButton11"]).Checked = true;
}
While casting the sender
to Button
is quite normal we run into trouble when we try to access any of the controls we have just cloned:
Since they were dynamically created we can't access any of them with variables. Instead we need to use the
TabPage
'sControls
collection to find them.We can set
BackColor
or any other property inherited fromControl
but to setRadioButton.Checked
we need to cast toRadioButton
; and we need to access the control from theControls
collection, for example by itsName
.Once you upgrade to recursive cloning you will want to use
Controls.Find(name, true)
to include the nested controls..
As you can see it can be done but it will take a little more effort than coding the original controls and the code feels somewhat fragile as we introduce hidden dependencies: All those references to the cloned names rely on the original names!
Final note: While the regular properiets get cloned, the data
and structure
containers do not, i.e. all Items
, ListViewItems
or Rows
, Columns
collections etc, etc are not cloned!
How to get ALL child controls of a Windows Forms form of a specific type (Button/Textbox)?
Here's another option for you. I tested it by creating a sample application, I then put a GroupBox and a GroupBox inside the initial GroupBox. Inside the nested GroupBox I put 3 TextBox controls and a button. This is the code I used (even includes the recursion you were looking for)
public IEnumerable<Control> GetAll(Control control,Type type)
{
var controls = control.Controls.Cast<Control>();
return controls.SelectMany(ctrl => GetAll(ctrl,type))
.Concat(controls)
.Where(c => c.GetType() == type);
}
To test it in the form load event I wanted a count of all controls inside the initial GroupBox
private void Form1_Load(object sender, EventArgs e)
{
var c = GetAll(this,typeof(TextBox));
MessageBox.Show("Total Controls: " + c.Count());
}
And it returned the proper count each time, so I think this will work perfectly for what you're looking for :)
Related Topics
Getting a System.Type from Type's Partial Name
Lambda Variable Capture in Loop - What Happens Here
Checking If an Object Is Null in C#
How to Install a Certificate into the Local MAChine Store Programmatically Using C#
Why Does Wcf Return Myobject[] Instead of List<T> Like I Was Expecting
In .Net/C# Test If Process Has Administrative Privileges
Why Do I Need a Memory Barrier
ASP.NET Core 3.0 System.Text.JSON Camel Case Serialization
Force JSON.Net to Include Milliseconds When Serializing Datetime (Even If Ms Component Is Zero)
In Mvvmcross How to Do Custom Bind Properties
What's the Difference Between Anonymous Methods (C# 2.0) and Lambda Expressions (C# 3.0)
Can Bindings Create Memory Leaks in Wpf
Why Is It Considered Bad to Expose List<T>