Silverlight: How to Make a ShallowCopy of a UIElement
Asked Answered
T

1

1

I need to add a UIElement to two different canvases, but one UIElement can only be a child of ONE canvas, so I have to create a ShallowCopy (DeepCopy not needed) of the UIElement.

I want to use MemberwiseClone, but it's protected, I cannot use it.

I also want to define an extension method UIElement.ShallowCopy, but it sill still call MemberwiseClone, which is protected again.

EDIT:

Tried all the following, but all of them failed in Silverlight environment:

    // System.Runtime.Serialization.InvalidDataContractException was unhandled by user code
    // Message=Type 'System.Windows.UIElement' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. Alternatively, you can ensure that the type is public and has a parameterless constructor - all public members of the type will then be serialized, and no attributes will be required.
    public static T CloneEx<T>(this T obj) where T : class
    {
        T clone;
        DataContractSerializer dcs = new DataContractSerializer(typeof(T));

        using (MemoryStream ms = new MemoryStream())
        {
            dcs.WriteObject(ms, obj);
            ms.Position = 0;
            clone = (T)dcs.ReadObject(ms);
        }

        return clone;
    }

    // This one also throws Access/Invoke exceptions
    private readonly static object _lock = new object();
    public static T MemberwiseCloneEx<T>(this T obj) where T : class
    {
        if (obj == null)
            return null;

        try
        {
            Monitor.Enter(_lock);

            T clone = (T)Activator.CreateInstance(obj.GetType());

            PropertyInfo[] fields = obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
            foreach (PropertyInfo field in fields)
            {
                object val = field.GetValue(obj, null);
                field.SetValue(clone, val, null);
            }

            return clone;
        }
        finally
        {
            Monitor.Exit(_lock);
        }
    }

    // System.MethodAccessException was unhandled by user code
    // Message=Attempt by method 'ToonController.ControllerUtils.MemberwiseCloneEx<System.__Canon>(System.__Canon)' to access method 'System.Object.MemberwiseClone()' failed.
    public static T MemberwiseCloneEx<T>(this T obj) where T : class
    {
        if (obj == null)
            return null;

        MethodInfo mi = obj.GetType().GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic);

        if (mi == null)
            return null;

        return (T)mi.Invoke(obj, null);
    }
Thrall answered 23/11, 2012 at 1:10 Comment(1)
You cannot clone an object unless it was designed to be cloneable. You need to copy it yourself.Inspector
T
1

if you have something that you want to use in multiple ui elements, 'sync them up' then you should create a ViewModel or something similar. This viewmodel would be set to the datacontext of any element you want to use it. Then your shallow reference is simple and you can just create two independent UI elements binding to the same data.

Teneshatenesmus answered 23/2, 2013 at 23:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.