2009-07-23 5 views
6
<Window x:Class="WpfApplication1.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:WpfApplication1" 
    Title="Window1"> 
    <Grid> 
     <local:ElementType x:Name="FirstElementName"> 
      <local:ElementType x:Name="SecondElementName" Grid.Column="1" Grid.Row="1" /> 
     </local:ElementType> 
    </Grid> 
</Window> 

Und das ist in anderen Dateien ...Wie kann ich benutzerdefinierte XAML-Elemente verschachteln?

<Grid x:Name="InternalElementName" x:Class="WpfApplication1.ElementType" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:WpfApplication1"> 
</Grid> 

Und ...

public partial class ElementType : System.Windows.Controls.Grid { } 

Alles funktioniert gut, außer dem zweiten Element.
Ich bekomme den Fehler:
Kann Name Attribut Wert 'SecondElementName' auf Element 'ElementType' nicht festlegen. 'ElementType' liegt im Bereich des Elements 'ElementType', für das bereits ein Name registriert wurde, als dieser in einem anderen Bereich definiert wurde.

Die benutzerdefinierten Raster sind ordnungsgemäß definiert. Der Code wird kompiliert und ausgeführt werden, wenn ich aus dem Eigentum nehmen ---

x:Name="SecondElementName" 

--- in Window1.xaml

Was diesen Fehler verursacht? Wie komme ich dazu? Ich muss eines dieser benutzerdefinierten Gitter in das andere verschachteln, und ich brauche Namen auf beiden, damit ich sie an separate Daten binden kann.

Vielen Dank im Voraus.

Antwort

5

Um zu wissen, was mit verschachtelten Markup-Objekten zu tun ist, wird der XAML-Parser unter anderem untersuchen, ob die .NET-Klasse eine standardmäßige "content" -Eigenschaft definiert, die als Container für solche untergeordneten Objekte verwendet werden soll. Dies geschieht mit dem "ContentPropertyAttribute".

In Ihrem Fall, da ich denke, man verschachtelte Objekte innerhalb des Grid gehen will, und da die Kinder eines Gitters in der „Kinder“ Eigentum Sammlung gehen, müssen Sie nur Folgendes tun:

[ContentProperty("Children")] 
public partial class ElementType : Grid 
{ 
    // your code here... 
} 

Wenn Sie beim Hinzufügen von untergeordneten Elementen zu Ihrem Steuerelement Logik ausführen müssen (z. B. nur bestimmte Typen als untergeordnete Elemente des ElementType-Steuerelements zulassen), können Sie stattdessen von IAddChild erben und die AddChild- und AddText-Methoden implementieren.

Wie für das Benennungsproblem scheint es, dass nur die nackten Kontrollen benannte Kinder in einem instanziierten Bereich haben können. Im Grunde genommen können Sie benannte Kinder in ElementType.xaml haben, aber keine benannten Kinder in anderen Markups, in denen Sie ElementType instanziieren. Ich schätze, es liegt an der Art, wie sie den logischen Baum oder etwas anderes optimieren. Eine lookless Kontrolle ist andererseits eine Kontrolle mit nur Code. Also, wenn Sie Ihre Klasse in eine einfache alte leere Unterklasse von Grid drehen, funktioniert es:

public class ElementType : Grid 
{ 
} 

Yay! Weniger Code!

+0

Das ist auch interessant, aber es erlaubt mir immer noch nicht, den Eltern- und Kind-Elementtyp-Objekten verschiedene Namen zu geben. Weiß jemand wie ich sie getrennt voneinander nennen kann? – Giffyguy

+0

Oh yeah, sorry ... Ich werde meine Antwort oben ausfüllen. – Ludovic

1

Wenn Sie eine in der anderen wollen, sollten Sie die innere in der Content-Eigenschaft des ersten setzen:

<local:ElementType x:Name="FirstElementName"> 
    <local:ElementType.Content> 
     <local:ElementType x:Name="SecondElementName" Grid.Column="1" Grid.Row="1" /> 
    </local:ElementType.Content> 
</local:ElementType> 

Auch ich bin nicht sicher, was Sie versuchen, hier zu tun aber ich fürchte es.

+0

Klingt wie dies die richtige Richtung zu sein. In Bezug auf Ihre endgültige sentance: HA! Ich habe absichtlich alles weggelassen, was die Einzelheiten preisgeben würde - glaub mir, du willst es nicht wissen. In Bezug auf Ihre Lösung bekomme ich einen Fehler: "Die anfügbar Eigenschaft 'Inhalt' wurde nicht im Typ 'ElementType' gefunden" Ich habe "Grid.Content" an seiner Stelle versucht und ich bekomme ungefähr den gleichen Fehler. Irgendwelche weiteren Ideen? – Giffyguy

+0

Ich meinte "Kinder", nicht Inhalt. Sieht so aus, als hättest du es doch verstanden. –

0

Wenn Sie das Benutzersteuerelement nicht ändern möchten, verwenden Sie ein angehängtes Verhalten. Du brauchst es also nur dort, wo der XAML-Compile fehlgeschlagen ist! Nur 1 Verhalten für jedes UserControl, das Probleme macht.

in XAML:

<preview:PreviewControl> 
    <i:Interaction.Behaviors> 
     <behaviors:UserControlNameBehavior Name="ICanSetNames"/> 
    </i:Interaction.Behaviors> 
</preview:PreviewControl> 

in C#:

public class UserControlNameBehavior : Behavior<UserControl> 
    { 
     public string Name { get; set; } 

     protected override void OnAttached() 
     { 
      this.AssociatedObject.Loaded += OnLoaded; 
      base.OnAttached(); 
     } 

     private void OnLoaded(object sender, RoutedEventArgs routedEventArgs) 
     { 
      this.AssociatedObject.Name = this.Name; 
     } 
    } 
+0

Was ist die Verhaltensklasse? Was ist ich? –