资源字典中的元素已经是另一个元素的子元素了?

时间:2018-04-30 10:21:40

标签: c# xaml uwp-xaml

在面向10240的UWP应用中;我知道当您尝试添加已在您收到的UI中绘制的元素时:

  

元素已经是另一个元素的子元素了。'

但是我在页面的资源中有一个边框,按代码添加它,并收到相同的异常。

<Page
x:Class="App13.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Page.Resources>
    <Border Width="100" Height="100" Background="Red" x:Name="Border" x:Key="Border" />        
</Page.Resources>

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Button Height="100" Width="100" Content="Add" Tapped="Button_Tapped"/>
</Grid>

using Windows.UI.Xaml.Input;

namespace App13
{ 
    public sealed partial class MainPage : Page
    {
        public MainPage() => InitializeComponent();

        private void Button_Tapped(object sender, TappedRoutedEventArgs e)
        {
            var border = Resources["Border"] as Border;
            if (!(Content is Panel panel)) return;

            panel.Children.Add(border);
        }
    }
}

如果元素在资源字典中,但尚未呈现,那么它又如何成为另一个元素的子元素?

1 个答案:

答案 0 :(得分:2)

  

元素已经是另一个元素的子元素了。&#39;

UWP中的每个UI元素一次只能在一个位置的UI中使用。加载资源时将生成实例。因此,您无法再将它们添加到面板中。但是,您可以通过关注UIElementExtensions创建深层副本,然后将副本添加到面板中。

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") 
            {
                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);
                        }
                    }
                }
            }
        }
    }
}

<强>用法

private void Button_Tapped(object sender, TappedRoutedEventArgs e)
{
    var border = Resources["Border"] as Border;
    if (!(Content is Panel panel)) return;
    var NewBorder = border.DeepClone<Border>();
    panel.Children.Add(NewBorder);

}