Как я могу добавить путь, который был определен в XAML ResourceDictionary, несколько раз в форму WPF во время выполнения?
-
21-09-2019 - |
Вопрос
У меня есть определенный путь в 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 и примените его.