Como posso adicionar um caminho definido no ResourceDictionary XAML várias vezes a um formulário WPF em tempo de execução?

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

Pergunta

Tenho um caminho definido em 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>

Quero adicioná-lo a um WPF Gird e fazê-lo uma vez assim funciona:

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

No entanto, se eu adicionar este código em um evento de clique de botão e clicar duas vezes no botão, um erro será gerado informando

"O Visual especificado já é um filho de outro visual ou a raiz de um CompositionTarget".

Em seguida, tentei criar duas instâncias do recurso, mas continuei recebendo o mesmo erro.Abaixo está o código que usei para este teste:

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

Dessa forma, como posso adicionar um caminho XAML, que foi definido no ResourceDictionary, várias vezes a um formulário WPF em tempo de execução?

Foi útil?

Solução 2

Desde então, descobri que havia perdido uma parte importante do documentação do MSDN:

Tipos compartilháveis ​​e tipos UIElement:

Um dicionário de recursos é uma técnica para definir tipos e valores compartilháveis ​​desses tipos no XAML.Nem todos os tipos ou valores são adequados para uso de um recurso.Para obter mais informações sobre quais tipos são considerados compartilháveis ​​no Silverlight, consulte os dicionários de recursos.

Em particular, todos os tipos derivados de UIELEMENT não são compartilháveis, a menos que venham de modelos e aplicação de um modelo em uma instância de controle específica.Excluindo o caso do modelo, espera -se que exista um em um local em um local em uma árvore de objetos, uma vez instanciados, e ter um uiellemento compartilhável violaria esse princípio.

O que vou resumir como, não é assim que funciona porque não está criando uma nova instância cada vez que executo esse código – ele está apenas criando uma referência ao objeto – e é por isso que funciona uma vez, mas não várias vezes.Então, depois de ler um pouco mais, descobri três maneiras possíveis de resolver meu problema.

1) Use uma técnica para criar uma cópia profunda para um novo objeto.Exemplo de outra pergunta StackOverflow - Clonagem profunda de objetos

2) Armazene o XAML em strings no aplicativo e use o leitor XAML para criar instâncias dos Paths:

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) Armazene apenas os dados do Caminho no Dicionário de Recursos.Crie uma nova instância de um Path no código, aplique os dados do Path ao novo Path e adicione manualmente as outras propriedades nas quais estou interessado.

Os dados XAML – The Path são armazenados como um 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>

O código C# para então criar uma instância e aplicar os outros valores:

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);

Outras dicas

Há uma maneira mais fácil e interna de fazer isso. Set x: shared = "false" no recurso. Isso permitirá que seja reutilizado. Em seguida, use -o quantas vezes quiser.

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

Basta criar estilo para o caminho e aplicá -lo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top