¿Cómo puedo añadir un camino, que se ha definido en el XAML ResourceDictionary, varias veces a una forma de WPF en tiempo de ejecución?

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

Pregunta

Tengo una trayectoria definida en 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>

Quiero añadir a un ceñidor WPF y hacerlo una vez como esto funciona:

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

Sin embargo, si añado este código en un evento de clic de botón y haga clic en el botón dos veces, se produce un error que indica

  

"especificado visual ya es un niño   de otro visual o la raíz de una   CompositionTarget ".

Entonces intentó crear dos instancias del recurso, sino que he seguido recibiendo el mismo error. A continuación se muestra el código que he utilizado para esta prueba:

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

Como tal, ¿cómo puedo añadir una ruta de XAML, que ha sido definida en el ResourceDictionary, varias veces a una forma de WPF en tiempo de ejecución?

¿Fue útil?

Solución 2

Desde entonces, he descubierto que me había perdido una parte importante de la documentación de MSDN :

  

Tipos compartibles y tipos de UIElement:

     

Un diccionario de recursos es una técnica para   la definición de tipos y valores de compartibles   estos tipos en XAML. No todos los tipos o   los valores son adecuados para el uso de una   ResourceDictionary. Para más   información sobre qué tipos son   considerado compartible en Silverlight,   ver diccionarios de recursos.

     

En particular, todos UIElement deriva   tipos no son compartibles a menos que   provienen de plantillas y aplicación de   una plantilla en un control específico   ejemplo. Excluyendo el caso plantilla,   Se espera UIElement a sólo existen   en un solo lugar en un árbol de objetos vez   instanciada, y que tiene un UIElement   compartible ser potencialmente violar   este principio.

¿Qué voy a resumir como, esa no es la forma en que funciona, porque No es la creación de una nueva instancia cada vez que ejecutar ese código - que sólo está creando una referencia al objeto - que es por qué funciona vez, pero no varias veces. Así que después de un poco más de lectura que he llegado con 3 posibles formas de resolución de mi problema.

1) Utilice una técnica para crear una copia profunda a un nuevo objeto. Ejemplo de otra pregunta StackOverflow - objetos de clonación profundas

2) Almacenar el XAML en cadenas dentro de la aplicación y luego utilizar el lector XAML para crear instancias de los caminos:

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) Sólo almacenar los datos de trayectoria en el diccionario de recursos. Crear una nueva instancia de un camino en el código, aplicar los datos de ruta de la nueva ruta y luego agregar las otras propiedades Estoy interesado en forma manual.

El XAML - los datos de trayectoria se almacena como un 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>

El código C # a continuación, crear una instancia y aplicar los otros 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);

Otros consejos

Hay una manera más fácil, incorporado para realizar esta acción. Set x: Compartido = "false" en el recurso. Esto permitirá que pueda ser reutilizado. Luego usarlo tantas veces como desee.

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

Hay que crear el estilo de Ruta, y aplicarlo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top