Skip to main content
Home Forums Silverlight Programming Report a Silverlight Bug Can't add a cloned object to an UI element in SilverLight 2.0
4 replies. Latest Post by samcov on November 30, 2008.
(0)
patrick_...
Member
1 points
3 Posts
11-02-2008 11:16 PM |
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; } } }
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; } } }
11-03-2008 9:11 PM |
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 L...
All-Star
25052 points
2,747 Posts
11-04-2008 2:43 AM |
Hello, can you post some code of your OverViewControl? Do you have a Name property for it? I modified your Clone method:
{
}
...
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.
11-04-2008 3:08 AM |
Hi Yi,
Thanks for your answer, you get the point!
This problem caused by the duplicate "Name".
samcov
Participant
969 points
379 Posts
11-30-2008 3:16 AM |
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...