2012-04-01 2 views
2

У меня есть два класса, которые ссылаются на третий:Повторное использование элементов и 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; } 
    ... 
} 

Теперь, я хотел бы показать, как 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> 

Таким образом, разметка отличается, за исключением для TreeViewItem, который отображает Named класс. Я хотел бы повторно использовать разметку для этого TreeViewItem. Слишком просто сделать UserControl, но это все еще немного сложнее, чем показано в примере. Таким образом, я действительно хотел бы сделать что-то вроде этого:

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

, а затем просто использовать его как это:

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

Как вы можете видеть, имя свойства Data1 «s для Named является Xxx, в то время как Data2 's property name for Named является Yyy. Итак, я должен передать это как-то моему ресурсу. Но как?

E.g. как мне установить DataContext этого StaticResource поддерева до Xxx для Data1?

Что-то вроде этого не работает:

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

Извините за длинный вопрос.

Edit:

Все, что я хочу, это кусок XAML, способный отображать Named экземпляр. Итак, я хочу указать, где можно получить экземпляр (от Xxx или Yyy) за пределами этой части, поэтому я могу ее повторно использовать.

Edit2: вот решение с ControlTemplate, однако он не работает: TreeViewItem становится неактивна. Что не так?

<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}" /> 
    ... 

ответ

0

Хорошо, я вздремнул сегодня, и когда я проснулся, я вдруг понял, что ответ! Вот оно:

<!-- 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

вы должны изучить всю тему шаблонов. Вместо того, чтобы вручную создавать экземпляры TreeViewItem, вы должны связать список объектов с свойством TreeView.ItemsSource, а затем указать TreeView.ItemTemplate, который является вашим многоразовым статическим ресурсом. Если смешанные типы данных, то вы можете использовать TreeView.ItemTemplateSelector динамически выбрать DataTemplate вы хотите

См http://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.itemtemplateselector.aspx для получения дополнительной информации

+0

Спасибо, Мартин. Я знаю «ItemsSource», однако в этом случае, как вы можете видеть, нет привязки к коллекции. – torvin

0

В соответствии с вашими комментариями, Torvin, вы должны использовать DataTemplate. Не только ItemsControl поддерживает шаблоны, у ContentControl также есть эта функция. Существует свойство ContentTemplate. ContentControl также автоматически перехватывает шаблон, используя свойство DataTemplate.DataType.

Таким образом, вы можете создать DataTemplate, который представляет собой именованный объект:

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

Затем вы должны установить именованный объект в качестве содержания:

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

Это все! Надеюсь, я правильно понял вас на этот раз :)

+0

Ух ... Давай! Слишком много кода! На этом этапе было бы проще просто написать UserControl ... – torvin

+0

Даже если у вас есть UserControl, это не поможет вам избежать спецификации Xxx или Yyy. Мое решение тоже не идеально, потому что оно не позволяет WPF отслеживать изменения свойства Name. Но конвертер может быть изменен для достижения этого. Я отредактировал свой ответ. –

+0

Спасибо, Марат, но похоже, что ты меня неправильно понял. У меня есть два совершенно разных 'TreeView', они не связаны с одним и тем же источником. Поэтому мне не нужно избегать спецификации Xxx или Yyy. Я просто хочу избежать этой спецификации в общей разметке. Другими словами, я просто хочу, чтобы часть XAML отображала класс «Named», не зная, где находится экземпляр «Named» внутри этой части. Я должен добавить это к вопросу ... – torvin

Смежные вопросы