Как я могу добавить путь, который был определен в XAML ResourceDictionary, несколько раз в форму WPF во время выполнения?

StackOverflow https://stackoverflow.com/questions/1377658

Вопрос

У меня есть определенный путь в XAML:

<UserControl.Resources>
    <ResourceDictionary>
        <Path x:Key="N44" Width="20" Height="80" Stretch="Fill" Fill="#FF000000" Data="M 20,25.2941L 20,29.4118L 15.9091,29.4118L 15.9091,40L 12.2727,40L 12.2727,29.4118L 2.54313e-006,29.4118L 2.54313e-006,25.6985L 13.4872,7.62939e-006L 15.9091,7.62939e-006L 15.9091,25.2941L 20,25.2941 Z M 12.2727,25.2941L 12.2727,5.28493L 2.09517,25.2941L 12.2727,25.2941 Z M 20,65.2941L 20,69.4118L 15.9091,69.4118L 15.9091,80L 12.2727,80L 12.2727,69.4118L -5.08626e-006,69.4118L -5.08626e-006,65.6985L 13.4872,40L 15.9091,40L 15.9091,65.2941L 20,65.2941 Z M 12.2727,65.2941L 12.2727,45.2849L 2.09517,65.2941L 12.2727,65.2941 Z "/>
    </ResourceDictionary>
</UserControl.Resources>

Я хочу добавить это в пояс WPF и сделать это один раз, как это работает:

System.Windows.Shapes.Path aPath = new System.Windows.Shapes.Path();
aPath = (System.Windows.Shapes.Path)this.Resources["N44"];
LayoutRoot.Children.Add(aPath); 

Однако, если я добавлю этот код в событие нажатия кнопки, а затем дважды нажму кнопку, выдается сообщение об ошибке с указанием

"Указанный визуал уже является дочерним элементом другого визуала или корневым элементом CompositionTarget".

Затем я попытался создать два экземпляра ресурса, но продолжал получать ту же ошибку.Ниже приведен код, который я использовал для этого теста:

private void cmbTest_Click(object sender, System.Windows.RoutedEventArgs e)
  {
   System.Windows.Shapes.Path aPath = new System.Windows.Shapes.Path();
   aPath = (System.Windows.Shapes.Path)this.Resources["N44"];

   if (LayoutRoot.Children.Contains(aPath) == true){
    System.Windows.Shapes.Path bPath = (System.Windows.Shapes.Path)this.Resources["N44"];
    LayoutRoot.Children.Add(bPath); 
   }else{
    aPath.Name = "a";
    aPath.Tag = "a";
    LayoutRoot.Children.Add(aPath);
   }
  }

Таким образом, как я могу добавить путь XAML, который был определен в ResourceDictionary, несколько раз в форму WPF во время выполнения?

Это было полезно?

Решение 2

С тех пор я обнаружил, что упустил важную часть документация из MSDN:

Совместно используемые типы и пользовательские элементы:

Словарь ресурсов - это метод для определения совместно используемых типов и значений этих типов в XAML.Не все типы или значения подходят для использования из ResourceDictionary.Для получения дополнительной информации о том, какие типы считаются общими в Silverlight, смотрите Словари ресурсов.

В частности, все производные от UIElement типы недоступны для совместного использования, если они не получены из шаблонов и применения шаблона к конкретному экземпляру элемента управления .Исключая случай шаблона, ожидается, что UIElement будет существовать только в одном месте в дереве объектов один раз созданный экземпляр, и наличие UIElement с возможностью совместного использования потенциально нарушит этот принцип.

Который я резюмирую следующим образом: это работает не так, потому что это не создание нового экземпляра каждый раз, когда я выполняю этот код, он создает только ссылку на объект, вот почему он работает один раз, но не несколько.Итак, еще немного почитав, я пришел к выводу о 3 потенциальных способах решения моей проблемы.

1) Используйте технику для создания глубокой копии нового объекта.Пример из другого вопроса StackOverflow - Глубокое клонирование объектов

2) Сохраните XAML в виде строк внутри приложения, а затем используйте программу чтения XAML для создания экземпляров путей:

System.Windows.Shapes.Path newPath = (System.Windows.Shapes.Path)System.Windows.Markup.XamlReader.Parse("<Path xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'  Width='20' Height='80' Stretch='Fill' Fill='#FF000000' Data='M 20,25.2941L 20,29.4118L 15.9091,29.4118L 15.9091,40L 12.2727,40L 12.2727,29.4118L 2.54313e-006,29.4118L 2.54313e-006,25.6985L 13.4872,7.62939e-006L 15.9091,7.62939e-006L 15.9091,25.2941L 20,25.2941 Z M 12.2727,25.2941L 12.2727,5.28493L 2.09517,25.2941L 12.2727,25.2941 Z M 20,65.2941L 20,69.4118L 15.9091,69.4118L 15.9091,80L 12.2727,80L 12.2727,69.4118L -5.08626e-006,69.4118L -5.08626e-006,65.6985L 13.4872,40L 15.9091,40L 15.9091,65.2941L 20,65.2941 Z M 12.2727,65.2941L 12.2727,45.2849L 2.09517,65.2941L 12.2727,65.2941 Z ' HorizontalAlignment='Left' VerticalAlignment='Top' Margin='140,60,0,0'/>");
LayoutRoot.Children.Add(newPath);

3) Храните данные Пути только в Словаре ресурсов.Создайте новый экземпляр Пути в коде, примените данные Пути к новому Пути, а затем добавьте другие интересующие меня свойства вручную.

XAML - данные Пути хранятся в виде StreamGeometry:

<UserControl.Resources>
    <ResourceDictionary>
        <StreamGeometry x:Key="N44">M 20,25.2941L 20,29.4118L 15.9091,29.4118L 15.9091,40L 12.2727,40L 12.2727,29.4118L 2.54313e-006,29.4118L 2.54313e-006,25.6985L 13.4872,7.62939e-006L 15.9091,7.62939e-006L 15.9091,25.2941L 20,25.2941 Z M 12.2727,25.2941L 12.2727,5.28493L 2.09517,25.2941L 12.2727,25.2941 Z M 20,65.2941L 20,69.4118L 15.9091,69.4118L 15.9091,80L 12.2727,80L 12.2727,69.4118L -5.08626e-006,69.4118L -5.08626e-006,65.6985L 13.4872,40L 15.9091,40L 15.9091,65.2941L 20,65.2941 Z M 12.2727,65.2941L 12.2727,45.2849L 2.09517,65.2941L 12.2727,65.2941 Z</StreamGeometry>
    </ResourceDictionary>
</UserControl.Resources>

Код на C # для последующего создания экземпляра и применения других значений:

System.Windows.Shapes.Path bPath = new System.Windows.Shapes.Path();
bPath.Data = (System.Windows.Media.Geometry)this.FindResource("N44");

bPath.Width = 20;
bPath.Height = 80;

bPath.VerticalAlignment = System.Windows.VerticalAlignment.Top;
bPath.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;

left = left + 40;

System.Windows.Thickness thickness = new System.Windows.Thickness(left,100,0,0);
bPath.Margin = thickness;

bPath.Fill = System.Windows.Media.Brushes.Black;
LayoutRoot.Children.Add(bPath);

Другие советы

Есть более простой встроенный способ сделать это.Установите x:Shared="False" для ресурса.Это позволит использовать его повторно.Затем используйте его столько раз, сколько захотите.

<UserControl.Resources>
    <ResourceDictionary>
        <Path x:Shared="False" x:Key="N44" Width="20" Height="80" Stretch="Fill" Fill="#FF000000" Data="..."/>
    </ResourceDictionary>
</UserControl.Resources>

Просто создайте стиль для Path и примените его.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top