Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/281.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在WinRT XAML C#中克隆UIElement?_C#_Xaml_Exception_Windows Runtime_Uielement - Fatal编程技术网

如何在WinRT XAML C#中克隆UIElement?

如何在WinRT XAML C#中克隆UIElement?,c#,xaml,exception,windows-runtime,uielement,C#,Xaml,Exception,Windows Runtime,Uielement,我首先尝试了这种方法,但出现错误“元素已经是另一个元素的子元素” 然后我检查了和,但是XamlWriter和XamlReader在WinRT中不可用。我曾尝试使用,但它抛出异常,“无法使用已与其基础RCW分离的COM对象。System.Runtime.InteropServices.InvalidComObjectException”。那么,有人能告诉我如何将画布中现有的UserControl克隆到自身吗?您可以尝试使用XamlWriter和XamlReader以外的序列化程序来实现链接中描述的

我首先尝试了这种方法,但出现错误“元素已经是另一个元素的子元素”


然后我检查了和,但是XamlWriter和XamlReader在WinRT中不可用。我曾尝试使用,但它抛出异常,“无法使用已与其基础RCW分离的COM对象。
System.Runtime.InteropServices.InvalidComObjectException
”。那么,有人能告诉我如何将画布中现有的UserControl克隆到自身吗?

您可以尝试使用XamlWriter和XamlReader以外的序列化程序来实现链接中描述的相同效果。例如,使用ServiceStack.Text将对象序列化为字符串,然后从该字符串中获取新对象并将其添加到父对象。

我编写了一个
UIElement
扩展,它复制元素的属性和子元素——请注意,它不为克隆设置事件

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using System.Reflection;
using Windows.UI.Xaml.Controls;

namespace UIElementClone
{
    public static class UIElementExtensions
    {
        public static T DeepClone<T>(this T source) where T : UIElement
        {

            T result;

            // Get the type
            Type type = source.GetType();

            // Create an instance
            result = Activator.CreateInstance(type) as T;

            CopyProperties<T>(source, result, type);

            DeepCopyChildren<T>(source, result);

            return result;
        }

        private static void DeepCopyChildren<T>(T source, T result) where T : UIElement
        {
            // Deep copy children.
            Panel sourcePanel = source as Panel;
            if (sourcePanel != null)
            {
                Panel resultPanel = result as Panel;
                if (resultPanel != null)
                {
                    foreach (UIElement child in sourcePanel.Children)
                    {
                        // RECURSION!
                        UIElement childClone = DeepClone(child);
                        resultPanel.Children.Add(childClone);
                    }
                }
            }
        }

        private static void CopyProperties<T>(T source, T result, Type type) where T : UIElement
        {
            // Copy all properties.

            IEnumerable<PropertyInfo> properties = type.GetRuntimeProperties();

            foreach (var property in properties)
            {
                if (property.Name != "Name") // do not copy names or we cannot add the clone to the same parent as the original.
                {
                    if ((property.CanWrite) && (property.CanRead))
                    {
                        object sourceProperty = property.GetValue(source);

                        UIElement element = sourceProperty as UIElement;
                        if (element != null)
                        {
                            UIElement propertyClone = element.DeepClone();
                            property.SetValue(result, propertyClone);
                        }
                        else
                        {
                            try
                            {
                                property.SetValue(result, sourceProperty);
                            }
                            catch (Exception ex)
                            {
                                System.Diagnostics.Debug.WriteLine(ex);
                            }
                        }
                    }
                }
            }
        }        
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
使用Windows.UI.Xaml;
运用系统反思;
使用Windows.UI.Xaml.Controls;
命名空间UIElementClone
{
公共静态类UIElementExtensions
{
公共静态T DeepClone(此T源),其中T:UIElement
{
T结果;
//获取类型
Type Type=source.GetType();
//创建一个实例
结果=Activator.CreateInstance(类型)作为T;
CopyProperties(源、结果、类型);
DeepCopyChildren(来源、结果);
返回结果;
}
私有静态void DeepCopyChildren(T source,T result),其中T:UIElement
{
//深度复制儿童。
Panel sourcePanel=源作为面板;
if(sourcePanel!=null)
{
面板结果面板=作为面板的结果;
if(resultPanel!=null)
{
foreach(sourcePanel.Children中的UIElement子元素)
{
//递归!
UIElement childClone=深度克隆(子级);
resultPanel.Children.Add(childClone);
}
}
}
}
私有静态void CopyProperties(T源、T结果、类型),其中T:UIElement
{
//复制所有属性。
IEnumerable properties=type.GetRuntimeProperties();
foreach(属性中的var属性)
{
如果(property.Name!=“Name”)//请不要复制名称,否则我们无法将克隆添加到与原始克隆相同的父级。
{
if((property.CanWrite)和&(property.CanRead))
{
对象sourceProperty=property.GetValue(源);
UIElement=sourceProperty作为UIElement;
if(元素!=null)
{
UIElement PropertyCyclone=element.DeepClone();
SetValue(结果,PropertyCyclone);
}
其他的
{
尝试
{
SetValue(结果,sourceProperty);
}
捕获(例外情况除外)
{
系统.诊断.调试.写线(ex);
}
}
}
}
}
}        
}
}

如果您觉得此代码有用,请随意使用。

通过克隆UIElements,您试图解决什么问题?可能有更好的方法。我尝试了Json.Net作为ServiceStack。文本在WinRT中不可用。不幸的是,它在序列化时引发异常。当我使用
jsonvert.SerializeObject(this)
时,它抛出
StackOverflowException
,当我使用
jsonvert.SerializeObjectAsync(this)
时,它抛出
JsonSerializationException
(从“Callisto.Controls.WatermarkTextBox”上的“水印”获取值时出错)请注意,我的用户控件使用工具箱中的其他用户控件,我建议不要克隆MyImageControl。例如,如果要实现的效果是在画布上放置两个相互重复的笑脸,请添加新创建的MyImageControl,并将新控件的imagesource(或任何适当的)属性设置为与第一个相同。如果您说手工复制的属性太多,那么有些方法会使用反射来循环使用可用的属性并复制它们的值。例如,请参见上面的解决方案在WinRT中也不起作用,因为WinRT中对like
Type的方法支持有限。GetFields()
在WinRT中不可用。最后,我成功地编写了
CloneHelper
类,但输出没有达到要求。我将很快更新问题的更多细节,感谢Boluc的帮助。
UIElement
是一种参考类型,因此您的代码相当于
((Canvas)this.Parent)。Children.Add(this)
-我希望您能看到这是行不通的。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using System.Reflection;
using Windows.UI.Xaml.Controls;

namespace UIElementClone
{
    public static class UIElementExtensions
    {
        public static T DeepClone<T>(this T source) where T : UIElement
        {

            T result;

            // Get the type
            Type type = source.GetType();

            // Create an instance
            result = Activator.CreateInstance(type) as T;

            CopyProperties<T>(source, result, type);

            DeepCopyChildren<T>(source, result);

            return result;
        }

        private static void DeepCopyChildren<T>(T source, T result) where T : UIElement
        {
            // Deep copy children.
            Panel sourcePanel = source as Panel;
            if (sourcePanel != null)
            {
                Panel resultPanel = result as Panel;
                if (resultPanel != null)
                {
                    foreach (UIElement child in sourcePanel.Children)
                    {
                        // RECURSION!
                        UIElement childClone = DeepClone(child);
                        resultPanel.Children.Add(childClone);
                    }
                }
            }
        }

        private static void CopyProperties<T>(T source, T result, Type type) where T : UIElement
        {
            // Copy all properties.

            IEnumerable<PropertyInfo> properties = type.GetRuntimeProperties();

            foreach (var property in properties)
            {
                if (property.Name != "Name") // do not copy names or we cannot add the clone to the same parent as the original.
                {
                    if ((property.CanWrite) && (property.CanRead))
                    {
                        object sourceProperty = property.GetValue(source);

                        UIElement element = sourceProperty as UIElement;
                        if (element != null)
                        {
                            UIElement propertyClone = element.DeepClone();
                            property.SetValue(result, propertyClone);
                        }
                        else
                        {
                            try
                            {
                                property.SetValue(result, sourceProperty);
                            }
                            catch (Exception ex)
                            {
                                System.Diagnostics.Debug.WriteLine(ex);
                            }
                        }
                    }
                }
            }
        }        
    }
}