Skip to main content

Microsoft Silverlight

Answered Question Can't add a cloned object to an UI element in SilverLight 2.0RSS Feed

(0)

patrick_chen
patrick_...

Member

Member

1 points

3 Posts

Can't add a cloned object to an UI element in SilverLight 2.0

Hi All,

       First, Let me tell my work. I want to create a bird view, just like the google map. In my design, I generate a view first, and then create a deep clone object as the bird view. If someone have another design, please tell me, it is appreciate!!

      Then, let's go to the problem. after finished the deep clone, I add the cloned object to an UI element (make it as the bird view). This process can work in SilverLight 2.0 beta, but doesn't in SilverLight 2.0

      to reproduce the step, I add the code below.

      

1            OverViewControl _cloned = (OverViewControl)SilverlightExtensions.Clone(this._overview);
2            if (_cloned != null)
3            {
4                //bird-view change handler
5                this.Birdview = _cloned;
6            }
7    
8            internal OverViewControl Birdview
9            {
10               get
11               {
12                   return this._birdview;
13               }
14               set
15               {
16                   if (this._birdview == null)
17                       this._birdview = value;
18                   else
19                   {
20                       this.GridforBirdView.Children.Remove(this._birdview);
21                       this._birdview = value;
22                   }
23                   this.GridforBirdView.Children.Add(value);
24               }
25           }
26   
      the error prompt in the line 23,  Catastrophic failure (Exception from HRESULT: 0x8000FFFF(E_UNEXPECTED))
      And below is the clone method:
       
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Reflection;
using System.Diagnostics;

namespace GraphControl.com.graph.clone
{
    public static class SilverlightExtensions
    {
        /// <summary>
        /// Clones the specified source.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <returns></returns>
        public static object Clone(object source)
        {
            return Clone(source, null);
        }

        /// <summary>
        /// Clones the specified source.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">The source.</param>
        /// <returns></returns>
        private static object Clone(object source, object parent)
        {
            object cloned = null;

            double _leftProperty = 0.0;
            double _topProperty = 0.0;
            int _zIndexProperty = 0;
            bool _uiElement = false;

            if (source.GetType().IsSubclassOf(typeof(UIElement)))
            {
                _uiElement = true;
                UIElement _r = (UIElement)source;
                if (_r != null)
                {
                    _leftProperty = Canvas.GetLeft(_r);
                    _topProperty = Canvas.GetTop(_r);
                    _zIndexProperty = Canvas.GetZIndex(_r);
                }
            }

            if (!source.Equals(typeof(ControlTemplate)))
            {
                try
                {
                    cloned = Activator.CreateInstance(source.GetType());
                }
                catch (MissingMethodException ex)
                {
                    Debug.WriteLine(ex.Message);
                }

                foreach (PropertyInfo curPropInfo in source.GetType().GetProperties())
                {
                    //It's possible to set and get PropertyInfo
                    if (curPropInfo.GetGetMethod() != null && (curPropInfo.GetSetMethod() != null) || curPropInfo.Name.Equals("Children"))
                    {
                        //Children is type of UIElementCollection
                        // Handle Non-indexer properties
                        if (curPropInfo.Name != "Item")
                        {
                            // get property from source
                            object getValue = curPropInfo.GetGetMethod().Invoke(source, new object[] { });

                            // clone if needed
                            // getValue is DependencyObject && !(getValue is DependencyObject) Object also needed to be cloned
                            if (getValue != null)
                            {
                                object _parent = null;

                                if (getValue is DependencyObject)
                                {
                                    //out of ControlTemplate
                                    //shouldn't copy Children - UIElementCollection
                                    if (curPropInfo.Name.Equals("Children"))
                                    {
                                        _parent = cloned.GetType().InvokeMember("Children", BindingFlags.GetProperty, null, cloned, new object[] { });
                                    }
                                    getValue = Clone((DependencyObject)getValue, _parent);
                                }
                                else if (getValue is System.ValueType)
                                {
                                    //Clone point, Value copy, just copy value
                                    getValue = getValue;
                                }
                            }
                            // set property on cloned
                            //void to reset ControlTemplate properties
                            //SilverLight 2.0 doesn't allow to change ControlTemplate
                            if (getValue != null && !curPropInfo.Name.Equals("Template") && !curPropInfo.Name.Equals("TargetType"))
                            {
                                //check if it's readonly UIElement isn't readonly
                                if (curPropInfo.CanWrite)
                                {
                                    try
                                    {
                                        curPropInfo.GetSetMethod().Invoke(cloned, new object[] { getValue });
                                    }
                                    catch (Exception ex)
                                    {
                                        Debug.WriteLine(ex.Message);
                                    }
                                }
                            }
                        }
                        else
                        {
                            //  handle indexer
                            //  get count for indexer
                            //  check if parent isn't null
                            //  Recursive input from previous level
                            if (parent != null)
                            {
                                int numberofItemInColleciton = (int)curPropInfo.ReflectedType.GetProperty("Count").GetGetMethod().Invoke(source, new object[] { });

                                // run on indexer
                                for (int i = 0; i < numberofItemInColleciton; i++)
                                {
                                    // get item through Indexer
                                    object getValue = curPropInfo.GetGetMethod().Invoke(source, new object[] { i });
                                    //Debug.WriteLine(getValue.GetType().ToString());

                                    // clone if needed
                                    if (getValue != null && getValue is DependencyObject)
                                    {
                                        //parent isn't null, for current container parent must be null
                                        getValue = Clone((DependencyObject)getValue, null);
                                    }
                                    // add item to collection
                                    try
                                    {
                                        parent.GetType().GetMethod("Add").Invoke(parent, new object[] { getValue });
                                    }
                                    catch (Exception ex)
                                    {
                                        Debug.WriteLine(ex.Message);
                                    }
                                }
                            }
                            else if (!(source is UIElement))
                            {
                                //possible to clone properties , but without parent container
                                int numberofItemInColleciton = (int)curPropInfo.ReflectedType.GetProperty("Count").GetGetMethod().Invoke(source, new object[] { });

                                // run on indexer
                                for (int i = 0; i < numberofItemInColleciton; i++)
                                {
                                    // get item through Indexer
                                    object getValue = curPropInfo.GetGetMethod().Invoke(source, new object[] { i });
                                    //Debug.WriteLine(getValue.GetType().ToString());

                                    // clone if needed
                                    if (getValue != null && !(getValue is DependencyObject))
                                    {
                                        //for current container parent must be null
                                        //Collection value copy
                                        getValue = Clone(getValue, null);
                                    }
                                    // add item to collection
                                    try
                                    {
                                        cloned.GetType().GetMethod("Add").Invoke(cloned, new object[] { getValue });
                                    }
                                    catch (Exception ex)
                                    {
                                        Debug.WriteLine(ex.Message);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (_uiElement)
            {
                UIElement _x = (UIElement)cloned;
                //set attached property
                if (_leftProperty != 0.0)
                {
                    Canvas.SetLeft(_x, _leftProperty);
                }

                if (_topProperty != 0.0)
                {
                    Canvas.SetTop(_x, _topProperty);
                }

                if (_zIndexProperty != 0)
                {
                    Canvas.SetZIndex(_x, _zIndexProperty);
                }
            }
            return cloned;
        }
    }
}
 
 

patrick_chen
patrick_...

Member

Member

1 points

3 Posts

Re: Can't add a cloned object to an UI element in SilverLight 2.0

As all the code can work in SL 2.0 beta, I think it is a bug for SL 2.0!

My system is Windows XP.

Yi-Lun Luo - MSFT
Yi-Lun L...

All-Star

All-Star

25052 points

2,747 Posts

Answered Question

Re: Re: Can't add a cloned object to an UI element in SilverLight 2.0

Hello, can you post some code of your OverViewControl? Do you have a Name property for it? I modified your Clone method:

foreach (PropertyInfo curPropInfo in source.GetType().GetProperties())

{

if (curPropInfo.Name == "Name")

{

continue;

}

...

 

Then I tested the Clone method with a Button, and added the cloned Button to the element tree. It worked fine. The Name property should not be cloned for obvious reason.

shanaolanxing - I'll transfer to the Windows Azure team, and will have limited time to participate in the Silverlight forum. Apologize if I don't answer your questions in time.

patrick_chen
patrick_...

Member

Member

1 points

3 Posts

Re: Re: Can't add a cloned object to an UI element in SilverLight 2.0

Hi Yi,

      Thanks for your answer, you get the point!

      This problem caused by the duplicate "Name".

samcov
samcov

Participant

Participant

969 points

379 Posts

Re: Re: Can't add a cloned object to an UI element in SilverLight 2.0

Your clone method works GREAT, with the addition of ignoring the name.

However, it's painfully slow. 

I guess you have to pick the situations where it can be used, but many thanks!

Sam...

"The difference between genius and stupidity is that genius has its limits." - Albert Einstein
  • Unanswered Question
  • Answered Question
  • Announcement
Microsoft Communities