2009-07-15 3 views
5

Я продолжаю понимать MVVC с code of MSDN, и у меня есть вопрос.WPF DataTemplate и привязка

В .xaml у них есть список команд, отображаемых на экране.

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

Отсюда, я понимаю, что DataContext устанавливается (не показан), и он будет отображать коллекцию команд. То, что я не понимаю, это CommandsTemplate, что вы можете увидеть ниже:

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

Как связывание создается? Как этот код говорит проверить свойство Command и DisplayName из объекта внутри коллекции? Это из ItemsSource? Если да, я не понимаю, почему это только в {Binding}. Кто-нибудь может объяснить мне, как работает привязка DataTemplate из ContentTemplate?

ответ

8

Как вы сказали, DataContext установлен в класс ViewModel, поэтому элемент управления, который вы упомянули в XAML, сможет получить доступ к общедоступным свойствам этой ViewModel.

Например:

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

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

Структура класса Commander.

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

Эта виртуальная машина имеет свойство Commands, которое может быть ObservableCollection. Это свойство можно получить из XAML.

Вы можете себе представить, что HeaderedContentControl - это контейнер. Содержимое этого HeaderedContentControl представляет собой DataTemplate «CommandsTemplate», который имеет элемент ItemsControl и привязывает его к свойству Commands VM.

Content = "{Binding Path = Команды}"

И потом, вы можете связать ItemControl с помощью команд снова, но что ItemControl внутри содержимого, связываются с командами. Поэтому вам не нужно указывать путь еще раз. Вы можете просто использовать

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

Два TextBlocks внутри ItemControl так что они находятся на том же уровне, что и класс Commander команд ObservableCollection. Вот почему вы можете напрямую получить доступ к Text = "{Binding Path = DisplayName}".

Надеюсь, это поможет.

1

Связывание ItemsSource с {Binding} связывается непосредственно с DataContext элемента ItemsControl (который будет искать цепочку, пока не найдет набор DataContext). В этом случае он установлен в HeaderedContentControl

Каждый элемент внутри ItemsControl будет иметь свой DataContext для элемента в списке.

<ItemsControl.ItemTemplate> устанавливает шаблон для каждого элемента внутри списка, а не для самого элемента ItemsControl. Так что {Binding Path=Command} и {Binding Path=DisplayName} будут просматривать эти свойства на элементах внутри списка.

+0

Если он связывается непосредственно к DataContext он должен быть переплетены в контексте списка и не элемента списка? –

+0

Это верно для ItemsControl, но каждый ** элемент ** в ItemsControl будет иметь элемент списка для своего DataContext. – Ray

+0

Хорошо, поэтому с помощью {Binding} будет искать DataContext внутри этой коллекции? –

1

Пример:

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; } 
} 
Смежные вопросы