Come posso aggiungere un percorso, che è stato definito in XAML ResourceDictionary, più volte per un modulo WPF in fase di esecuzione?

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

Domanda

Ho un percorso definito in 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>

Voglio aggiungere a una WPF Gird e farlo una volta come questo funziona:

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

Comunque se posso aggiungere questo codice su un evento click del pulsante e fare clic sul pulsante due volte, viene generato un errore che indica

  

"specificato visiva è già un bambino   di un'altra visiva o la radice di un   CompositionTarget ".

Allora ho tentato di creare due istanze della risorsa, ma ho continuato a ricevere lo stesso errore. Di seguito è riportato il codice che ho usato per questo test:

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

In quanto tale, come posso aggiungere un percorso di XAML, che è stato definito nella ResourceDictionary, più volte per un modulo WPF in fase di esecuzione?

È stato utile?

Soluzione 2

Da allora ho scoperto che avevo perso una parte importante della documentazione MSDN :

  

Tipi condivisibili e tipi di UIElement:

     

Un dizionario risorse è una tecnica per   definizione dei tipi e valori di condivisibili   questi tipi di XAML. Non tutti i tipi o   I valori sono adatti per l'utilizzo da una   ResourceDictionary. Per più   informazioni su quali tipi sono   considerato condivisibile in Silverlight,   vedi Resource Dizionari.

     

In particolare, tutte le UIElement derivato   tipi non sono condivisibili, a meno che   provengono da modelli e applicazione di   un modello su un controllo specifico   esempio. Escludendo il caso modello,   un UIElement si prevede di esistere solo   in un luogo in un albero oggetto una volta   istanziata, ed avente un'UIElement   essere condivisibile potrebbe potenzialmente violare   questo principio.

Che io riassumere come, non è questo il modo in cui funziona perché Non è la creazione di una nuova istanza ogni volta che esegue il codice - è creare solo un riferimento all'oggetto - è per questo che funziona una volta, ma non più volte. Così, dopo un po 'di più la lettura mi è venuta in mente 3 modi possibili di risoluzione al mio problema.

1) Utilizza una tecnica per creare una copia completa di un nuovo oggetto. Esempio da altra domanda StackOverflow - oggetti clonazione profonda

2) Conservare il XAML nelle stringhe all'interno dell'applicazione e quindi utilizzare il lettore XAML per creare istanze dei percorsi:

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) conserverà i dati sentiero nel dizionario risorse. Creare una nuova istanza di un percorso nel codice, applicare i dati Path per il nuovo percorso e quindi aggiungere le altre proprietà che mi interessano manualmente.

Il XAML - I dati percorso vengono memorizzati come 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>

Il codice C # per poi creare un'istanza e applicare gli altri valori:

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

Altri suggerimenti

C'è un modo più semplice incorporato per effettuare questa operazione. Set x: Shared = "False" sulla risorsa. Ciò permetterà di essere riutilizzato. Quindi utilizzare tutte le volte che vuoi.

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

Basta creare lo stile per il percorso, e applicarla.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top