我正在开发一个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作为依赖项。如果你喜欢看代码和学习,他在库中有示例解决方案。