2009-07-15 7 views
5

Je continue ma compréhension de MVVC avec le code of MSDN et j'ai une question.WPF DataTemplate et la liaison

Dans le .xaml, ils ont une liste de commandes affichées à l'écran.

<Border 
    Grid.Column="0" 
    Style="{StaticResource MainBorderStyle}" 
    Width="170" 
    > 
    <HeaderedContentControl 
     Content="{Binding Path=Commands}" 
     ContentTemplate="{StaticResource CommandsTemplate}" 
     Header="Control Panel" 
     Style="{StaticResource MainHCCStyle}" 
     /> 
    </Border> 

A partir de là, je comprends que le DataContext est réglé (non représenté ici) et il affichera la collection de commandes. Ce que je ne comprends pas la CommandsTemplate que vous pouvez voir ci-dessous:

<DataTemplate x:Key="CommandsTemplate"> 
<ItemsControl IsTabStop="False" ItemsSource="{Binding}" Margin="6,2"> 
    <ItemsControl.ItemTemplate> 
    <DataTemplate> 
     <TextBlock Margin="2,6">pou 
     <Hyperlink Command="{Binding Path=Command}"> 
      <TextBlock Text="{Binding Path=DisplayName}" /> 
     </Hyperlink> 
     </TextBlock> 
    </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 
</DataTemplate> 

Comment la liaison est créée? Comment ce code dit de vérifier la propriété Command et DisplayName de l'objet à l'intérieur de la collection? Est-ce de l'ItemsSource? Si oui, je ne comprends pas pourquoi c'est seulement {Binding}. Tout le monde peut m'expliquer comment la liaison DataTemplate fonctionne à partir d'un ContentTemplate?

Répondre

8

Comme vous l'avez dit, le DataContext est défini sur la classe ViewModel afin que le contrôle que vous avez mentionné dans XAML puisse accéder aux propriétés publiques de ce ViewModel.

Par exemple:

private ObservableCollection<Commander> commands = new ObservableCollection<Commander>(); 

    public ObservableCollection<Commander> Commands { 
     get { return commands; } 
     set { commands = value; } 
    } 

La structure de classe commandant.

public class Commander { 
    public ICommand Command { get; set; } 
    public string DisplayName { get; set; } 
} 

Cette VM a la propriété appelée Commandes pouvant être ObservableCollection. Cette propriété peut être accessible à partir de XAML.

Vous pouvez imaginer que HeaderedContentControl est un conteneur. Le contenu de ce HeaderedContentControl est un DataTemplate "CommandsTemplate" qui a un ItemsControl et il lie à la propriété Commands de VM.

Content = "{Binding Path = Commandes}"

Et puis, vous pouvez lier à ItemControl avec commandes à nouveau, mais que ItemControl est à l'intérieur du contenu qui se lient aux commandes. Vous n'avez donc pas besoin de spécifier à nouveau le chemin. Vous pouvez simplement utiliser

ItemsSource="{Binding}" instead of ItemsSource="{Binding Commands}". 

Deux TextBlocks sont à l'intérieur ItemControl ils sont au même niveau que la classe commandant des commandes ObservableCollection. C'est pourquoi vous pouvez accéder directement à Text = "{Binding Path = DisplayName}".

Espérons que ça aide.

1

La liaison ItemsSource à {Binding} se lie directement au DataContext de ItemsControl (qui recherchera la chaîne jusqu'à ce qu'elle trouve un ensemble DataContext). Dans ce cas, il a été défini dans HeaderedContentControl

Chaque élément à l'intérieur de ItemsControl aura alors son DataContext défini sur un élément de la liste.

Le <ItemsControl.ItemTemplate> définit le modèle pour chaque élément dans la liste, pas pour ItemsControl lui-même. Pour que {Binding Path=Command} et {Binding Path=DisplayName} regardent ces propriétés sur les éléments de la liste.

+0

Si elle se lie directement au DataContext il devrait être binded au contexte de la liste et non l'élément de la liste? –

+0

Cela est vrai pour ItemsControl, mais chaque ** élément ** dans ItemsControl aura un élément de la liste pour son DataContext. – Ray

+0

D'accord, l'utilisation de {Binding} va rechercher un DataContext dans cette collection, n'est-ce pas? –

1

Exemple:

XAML

<Window x:Class="WpfApplication2.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1" Height="300" Width="300" Loaded="Window_Loaded"> 
    <Window.Resources> 
     <DataTemplate x:Key="CommandsTemplate"> 
      <ItemsControl IsTabStop="False" ItemsSource="{Binding}" Margin="6,2"> 
       <ItemsControl.ItemTemplate> 
        <DataTemplate> 
         <TextBlock Margin="2,6">pou 
          <Hyperlink Command="{Binding Path=Command}"> 
           <TextBlock Text="{Binding Path=DisplayName}" /> 
          </Hyperlink> 
         </TextBlock> 
        </DataTemplate> 
       </ItemsControl.ItemTemplate> 
      </ItemsControl> 
     </DataTemplate> 
    </Window.Resources> 
    <Grid> 
     <Border Width="170"> 
      <HeaderedContentControl 
       Content="{Binding Path=Commands}" 
       ContentTemplate="{StaticResource CommandsTemplate}" 
       Header="Control Panel"/> 
     </Border> 
    </Grid> 
</Window> 

C#

/// <summary> 
/// Interaction logic for Window1.xaml 
/// </summary> 
public partial class Window1 : Window { 
    public Window1() { 
     InitializeComponent(); 

     Commands.Add(new Commander() { DisplayName = "DN1" }); 
     Commands.Add(new Commander() { DisplayName = "DN2" }); 
     Commands.Add(new Commander() { DisplayName = "DN3" }); 

     this.DataContext = this; 
    } 

    private void Window_Loaded(object sender, RoutedEventArgs e) { 

    } 

    private ObservableCollection<Commander> commands = new ObservableCollection<Commander>(); 

    public ObservableCollection<Commander> Commands { 
     get { return commands; } 
     set { commands = value; } 
    } 
} 

public class Commander { 
    public ICommand Command { get; set; } 
    public string DisplayName { get; set; } 
} 
Questions connexes