Элемент в словаре ресурсов уже является потомком другого элемента? - PullRequest
0 голосов
/ 30 апреля 2018

В приложении UWP с таргетингом 10240; Я знаю, когда вы пытаетесь добавить элемент, который уже окрашен в пользовательском интерфейсе, вы получаете:

Элемент уже является потомком другого элемента. '

Однако у меня есть границы в ресурсах страницы, я добавляю их по коду и получаю то же исключение.

<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 голосов
/ 01 мая 2018

Элемент уже является потомком другого элемента. '

Каждый элемент пользовательского интерфейса в UWP может использоваться в пользовательском интерфейсе только в одном месте одновременно. Экземпляр будет создан при загрузке ресурса. Таким образом, вы больше не можете добавлять их на панель. Однако вы можете создать глубокую копию с помощью команды 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);

}
...