我正在开发一个Windows Phone应用程序。我想把一张画布上的孩子复制到另一张画布上。我可以用下面的代码来完成,但问题是我必须先从一个画布中删除它。代码是:

private void add_template_Click(object sender, RoutedEventArgs e)
{
    var childrenList = Template_canvas1.Children.Cast<UIElement>().ToArray();
    root.Children.Clear();
    foreach (var c in childrenList)
    {
        Template_canvas1.Children.Remove(c);
        root.Children.Add(c);
    }
}

我想把这些元素都放在画布上。还有别的办法吗?

最佳答案

与其尝试将相同的Template_canvas1.Children添加到root画布,不如先复制这些Children然后将副本添加到root画布。

public static T CloneXaml<T>(T source)
{
    string xaml = XamlWriter.Save(source);
    StringReader sr = new StringReader(xaml);
    XmlReader xr = XmlReader.Create(sr);
    return (T)XamlReader.Load(xr);
}

然后将循环更改为:
foreach (var c in childrenList)
{
    var copy = CloneXaml(c);
    root.Children.Add(copy);
}

我还没有测试过这段代码,所以您可能需要对它进行一些修改,但它应该会让您朝着正确的方向发展。
或者,您可以使用下面从Dr Herbie's answer复制的代码:
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);
              }
            }
          }
        }
      }
    }
  }
}

如果这些都不适合您,恐怕您必须实现自己的序列化程序。看起来David Poll实现了一个不错的serlizer,所以看看。使用serlizer就像使用XamlWriter一样简单,然后您可以使用XamlReader
public static T CloneXaml<T>(T source)
{
    UiXamlSerializer uxs = new UiXamlSerializer();
    string xaml = uxs.Serialize(source);

    StringReader sr = new StringReader(xaml);
    XmlReader xr = XmlReader.Create(sr);
    return (T)XamlReader.Load(xr);
}

要获得此功能,请下载hisSlab library,转到“binaries”文件夹并将以“slab.utilities.xaml.serializer”开头的所有dll复制到项目中。可能需要其他一些dll作为依赖项。如果你喜欢看代码和学习,他在库中有示例解决方案。

10-05 18:26
查看更多