3

I have a cached control object form a UserControl in asp.net cache. I like to access my control and make a copy of it to freely change it without having any affect on the base cached control.

4
  • Can you post some of your control/cache code? Commented Apr 5, 2011 at 17:39
  • I don't think there is Clone command, as in each control can have children Controls, and they can as well, and so forth. Commented Apr 5, 2011 at 18:36
  • How much "fidelity" you need? A while ago, I ended up "serializing" an entire (customizable) UI and recovering it later (it was WinForms, not ASP, but the concepts are the same). Also, how much do you know in advance about the control? If it's going to have a well-known type, you can just create a new instance and copy each field/property you need. Otherwise, reflection can help, but you should provide some more details before I can guide you through that approach. Commented Apr 5, 2011 at 18:58
  • 1
    Why are you caching the control? Are you trying to cache the data within it? What are you trying to accomplish? Commented Apr 5, 2011 at 20:05

5 Answers 5

2

Hi I found the code that I was looking for. I put it here maybe it helps you too.

/// <summary>
/// this method makes a copy of object as a clone function
/// </summary>
/// <param name="o"></param>
/// <returns></returns>
public static object Clone_Control(object o)
{

    Type type = o.GetType();
    PropertyInfo[] properties = type.GetProperties();
    Object retObject = type.InvokeMember("", System.Reflection.BindingFlags.CreateInstance, null, o, null);
    foreach (PropertyInfo propertyInfo in properties)
    {
        if (propertyInfo.CanWrite)
        {
            propertyInfo.SetValue(retObject, propertyInfo.GetValue(o, null), null);
        }
    }
    return retObject;
}
Sign up to request clarification or add additional context in comments.

1 Comment

Hi. I've been using this "hack" for a few years now. But lately I found out that this doesn't seem to work with MONO. Gives an exception: System.Reflection.TargetException: Non-static method requires a target
1

It is certainly possible to do what you are asking to do. And it is very straightforward. Something like this maybe?

private static void ChangeMyControlTextFromCache(string controlName, string newText, Panel containingPanel)
{
    MyControl original = ViewState[controlName] as MyControl;
    if (original == null)
    {
        original = new MyControl();
        ViewState[controlName] = original;
    }    
    MyControl clone = CloneMyControl(original);
    clone.Text = newText;
    if (containingPanel.Children.Contains(original))
        containingPanel.Children.Remove(original);
    containingPanel.Children.Add(clone);
}

private static MyControl CloneMyControl(MyControl original)
{
    MyControl clone = new MyControl();
    clone.Text = original.Text;
    clone.SomeOtherProperty = original.SomeOtherProperty;
    return clone;
}

1 Comment

Hi friends ,I load a user control from file (Page.LoadControl("ascx file name")) and this is a time consuming process and I like to cache loaded user control in cache to prevent loading it from file , but this cached control is used in in different places with different setting and I want to make different copies of it in different usages to prevent the source cached control from any change . Please tell me how can I make a copy of my cached user control (this user control has different child controls, I like to make a copy exactly the same of the source)
1

Here is another clone method that will also work with MONO. It clones the passed control and it's children. Note: A cloned control cannot be added to a different page (or in a later post-back) even it has not been added to any page yet. It might seem to work on Windows but will crash on MONO so I guess it is generally not meant to be done.

public static Control CloneControl(Control c) {
    var clone = Activator.CreateInstance(c.GetType()) as Control;
    if (c is HtmlControl) {
        clone.ID = c.ID;
        foreach (string key in ((HtmlControl)c).Attributes.Keys)
            ((HtmlControl)clone).Attributes.Add(key, (string)((HtmlControl)c).Attributes[key]);
    }
    else {
        foreach (PropertyInfo p in c.GetType().GetProperties()) {
            // "InnerHtml/Text" are generated on the fly, so skip them. "Page" can be ignored, because it will be set when control is added to a Page.
            if (p.CanRead && p.CanWrite && p.Name != "InnerHtml" && p.Name != "InnerText" && p.Name != "Page") {
                try {
                    p.SetValue(clone, p.GetValue(c, p.GetIndexParameters()), p.GetIndexParameters());
                }
                catch {
                }
            }
        }
    }
    for (int i = 0; i < c.Controls.Count; ++i)
        clone.Controls.Add(CloneControl(c.Controls[i]));
    return clone;
}

Comments

0

try this for page includes LiteralControl and ResourceBasedLiteralControl.

public static System.Web.UI.Control CloneControl(Control c)
            {
                Type type = c.GetType();
                var clone = (0 == type.GetConstructors().Length) ? new Control() : Activator.CreateInstance(type) as Control;
                if (c is HtmlControl)
                {
                    clone.ID = c.ID;
                    AttributeCollection attributeCollection = ((HtmlControl)c).Attributes;
                    System.Collections.ICollection keys = attributeCollection.Keys;
                    foreach (string key in keys)
                    {
                        ((HtmlControl)c).Attributes.Add(key, (string)attributeCollection[key]);
                    }
                }else if(c is System.Web.UI.LiteralControl){
                    clone = new System.Web.UI.LiteralControl(((System.Web.UI.LiteralControl)(c)).Text);
                }
                else
                {
                    PropertyInfo[] properties = c.GetType().GetProperties();
                    foreach (PropertyInfo p in properties)
                    {
                        // "InnerHtml/Text" are generated on the fly, so skip them. "Page" can be ignored, because it will be set when control is added to a Page.
                        if (p.Name != "InnerHtml" && p.Name != "InnerText" && p.Name != "Page" && p.CanRead && p.CanWrite)
                        {
                            try
                            {
                                ParameterInfo[] indexParameters = p.GetIndexParameters();
                                p.SetValue(clone, p.GetValue(c, indexParameters), indexParameters);
                            }
                            catch
                            {
                            }
                        }
                    }
                }
                int cControlsCount = c.Controls.Count;
                for (int i = 0; i < cControlsCount; ++i)
                {
                    clone.Controls.Add(CloneControl(c.Controls[i]));
                }
                return clone;
            }

ref: Dynamic Web Controls, Postbacks, and View State By Scott Mitchell

Comments

0

Upvoted answers didn't work for me. Here's my solution to creating a copy of an ASP.NET control object.

    // Copies the custom properties on the control. To use it, cast your object to it. 
    public static object CopyUserControl(object obj, object obj2)
    {
        Type type = obj.GetType();
        PropertyInfo[] properties = type.GetProperties();

        Type type2 = obj2.GetType();
        PropertyInfo[] properties2 = type.GetProperties();

        foreach (PropertyInfo property in properties)
        {
            foreach (PropertyInfo property2 in properties2)
            {
                // Match the loops and ensure it's not a non-custom property 
                if (property.Name == property2.Name && property.SetMethod != null && !property.SetMethod.IsSecuritySafeCritical)
                    property2.SetValue(obj2, property.GetValue(obj, null));
            }
        }
        return obj2;
    }

It's useful when you have to copy an ASCX control on the same page with a different html id. Usage:

// Copying myAscxControl1 onto myAscxControl2
myAscxControl2 = (ObjectNameToBeCasted)CopyUserControl(myAscxControl1, myAscxControl2);

It should work with different typed objects too. Property names that you want to copy must match though.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.