2012-04-01 8 views
2

Ich habe zwei Klassen, die die dritte Referenz:Wiederverwenden von Elementen und Datacontext

class Data1 
{ 
    public Named Xxx { get; set; } 
    public SomeClass1 Foo { get; set; } 
    ... 
} 

class Data2 
{ 
    public Named Yyy { get; set; } 
    public SomeClass2 Bar { get; set; } 
    ... 
} 

class Named 
{ 
    public string Name { get; set; } 
    ... 
} 

Nun würde Ich mag beide angezeigt werden Data1 & Data2:

<TreeView DataContext={Binding Path=Data1}> 
    <TreeView.Items> 
    <TreeViewItem> 
     <TreeViewItem.Header> 
     <StackPanel Orientation="Horizontal"> 
      <ContentControl xml:space="preserve">Name: </ContentControl> 
      <ContentControl Content="{Binding Path=Xxx.Name}" /> 
     </StackPanel> 
     </TreeViewItem.Header> 
    </TreeViewItem> 
    <TreeViewItem><!-- somehow display Foo --></TreeViewItem> 
    <!-- More TreeViewItems, specific to Data1 --> 
    </TreeView.Items> 
</TreeView> 

<TreeView DataContext={Binding Path=Data2}> 
    <TreeView.Items> 
    <TreeViewItem> 
     <TreeViewItem.Header> 
     <StackPanel Orientation="Horizontal"> 
      <ContentControl xml:space="preserve">Name: </ContentControl> 
      <ContentControl Content="{Binding Path=Yyy.Name}" /> 
     </StackPanel> 
     </TreeViewItem.Header> 
    </TreeViewItem> 
    <TreeViewItem><!-- somehow display Bar --></TreeViewItem> 
    <!-- More TreeViewItems, specific to Data2 --> 
    </TreeView.Items> 
</TreeView> 

So Markup ist anders, außer für TreeViewItem, die Klasse anzeigt. Ich möchte Markup für diese TreeViewItem wiederverwenden. Es ist zu einfach, UserControl davon zu machen, aber es ist immer noch ein wenig komplizierter als im Beispiel gezeigt. Also, ich würde wirklich etwas zu tun:

<ResourceDictionary> 
    <TreeViewItem x:Key="Named"> 
    <TreeViewItem.Header> 
     <StackPanel Orientation="Horizontal"> 
     <ContentControl xml:space="preserve">Name: </ContentControl> 
     <ContentControl Content="{Binding Path=Name}" /> 
     </StackPanel> 
    </TreeViewItem.Header> 
    </TreeViewItem> 
</ResourceDictionary> 

Und dann ist es wie folgt verwenden:

<TreeView DataContext={Binding Path=Data1}> 
    <TreeView.Items> 
    <StaticResource ResourceKey="Named" /> 
    </TreeView.Items> 
</TreeView> 

Wie Sie sehen können, Data1 ‚s Eigenschaftsname für Named ist Xxx, während Data2 's Eigentumsname für ist Yyy. Also muss ich das irgendwie an meine Ressource weitergeben. Aber wie?

z. Wie setze ich die DataContext dieses Teilbaums Xxx für Data1StaticResource?

So etwas funktioniert nicht:

<StaticResource ResourceKey="Named" DataContext={Binding Path=Xxx} /> 

Sorry für die lange Frage.

bearbeiten:

Alles, was ich will, ist ein Stück von XAML, eine Named Instanz darstellen kann. Also, ich möchte in der Lage sein, anzugeben, wo die Instanz (Xxx oder Yyy) außerhalb von diesem Stück zu bekommen, so dass ich es wiederverwenden kann.

EDIT2: hier ist die Lösung mit ControlTemplate, aber es ist nicht gut funktioniert: die TreeViewItem unselectable wird. Was ist los mit dir?

<ControlTemplate x:Key="Named" TargetType="TreeViewItem"> 
    <TreeViewItem> 
     <TreeViewItem.Header> 
      <StackPanel Orientation="Horizontal"> 
       <TextBlock Text="Name: " /> 
       <TextBlock Text="{Binding Path=Name}" /> 
      </StackPanel> 
     </TreeViewItem.Header> 
    </TreeViewItem> 
</ControlTemplate> 

<!-- now use the template: --> 
<TreeView> 
    <TreeView.Items> 
    <TreeViewItem Template="{StaticResource Named}" 
        DataContext="{Binding Path=Xxx}" /> 
    ... 

Antwort

0

OK, ich habe heute ein Nickerchen gemacht und als ich aufwachte, wurde mir plötzlich klar, was die Antwort ist! Hier ist sie:

<!-- In resources: --> 
<Style TargetType="TreeViewItem" x:Key="Named"> 
    <Setter Property="Header" Value="{Binding Name}" /> 
    <Setter Property="HeaderTemplate"> 
    <Setter.Value> 
     <DataTemplate> 
     <StackPanel Orientation="Horizontal"> 
      <TextBlock Text="Name: " /> 
      <TextBlock Text="{Binding}" /> 
     </StackPanel> 
     </DataTemplate> 
    </Setter.Value> 
    </Setter> 
</Style> 

<!-- now use the template: --> 
<TreeView> 
    <TreeView.Items> 
    <TreeViewItem Style="{StaticResource Named}" 
        DataContext="{Binding Path=Xxx}" /> 
    ... 
1

sollten Sie in das ganze Templating-Thema schauen. Anstatt Instanzen von TreeViewItem manuell zu erstellen, sollten Sie eine Liste von Elementen an die Eigenschaft TreeView.ItemsSource binden und dann eine TreeView.ItemTemplate angeben, die Ihre wiederverwendbare statische Ressource ist. Wenn Sie Typen gemischt Daten haben, dann können Sie TreeView.ItemTemplateSelector verwenden, um dynamisch ein DataTemplate wählen Sie

http://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.itemtemplateselector.aspx für weitere Informationen wünschen

+0

Danke, Martin. Ich kenne "ItemsSource", aber in diesem Fall gibt es, wie Sie sehen, keine Sammlung, an die gebunden werden kann. – torvin

0

Nach Ihre Kommentare, Torvin, sollten Sie Datatemplate verwenden. Nicht nur ItemsControl unterstützt Templating, auch ContentControl hat diese Funktion. Es gibt ContentTemplate-Eigenschaft. ContentControl hakt auch automatisch Vorlagen mithilfe der DataTemplate.DataType-Eigenschaft.

So können Sie Datatemplate erstellen, das Objekt mit dem Namen repräsentiert:

<...Resources> 
    <DataTemplate DataType="{x:Type local:Named}"> 
     <TextBlock Text="{Binding Name}"/> 
    </DataTemplate> 
</...Resources> 

Dann sollten Sie benannte Objekt als Inhalt ein:

<TreeViewItem.Header> 
    <StackPanel Orientation="Horizontal"> 
     <ContentControl xml:space="preserve">Name: </ContentControl> 
     <ContentControl Content="{Binding Path=Xxx}" /> 
    </StackPanel> 
</TreeViewItem.Header> 

Das ist alles! Ich hoffe, ich verstehe dich diesmal richtig :)

+0

Ugh .. Komm schon! Zu viel Code! An dieser Stelle wäre es einfacher, ein UserControl zu schreiben ... – torvin

+0

Selbst wenn Sie ein UserControl haben, kann es Ihnen nicht helfen, Xxx oder Yyy-Spezifikation zu vermeiden. Meine Lösung ist auch nicht perfekt, weil es WPF nicht erlaubt, Änderungen der Eigenschaft Name zu verfolgen. Aber Konverter kann geändert werden, um dies zu erreichen. Ich habe meine Antwort bearbeitet. –

+0

Danke, Marat, aber es sieht so aus, als hättest du mich falsch verstanden. Ich habe zwei völlig verschiedene 'TreeView's, sie sind nicht an dieselbe Quelle gebunden. Also muss ich die Xxx oder Yyy Spezifikation nicht vermeiden. Ich möchte diese Spezifikation nur im gemeinsamen Markup vermeiden. Mit anderen Worten, ich möchte nur, dass ein Stück XAML die 'Named' Klasse anzeigt, ohne zu wissen, wo die Instanz von' Named' in dieses Stück kommt. Ich sollte das zur Frage hinzufügen ... – torvin

Verwandte Themen