It Is Possible to Copy All the Properties of a Certain Control? (C# Window Forms)

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

  1. 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 a CheckBox, 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 other TabPage 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!


  1. 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's Controls collection to find them.

  • We can set BackColor or any other property inherited from Control but to set RadioButton.Checked we need to cast to RadioButton; and we need to access the control from the Controls collection, for example by its Name.

  • 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



Leave a reply



Submit