Шаблон данных WPF и привязка - PullRequest
6 голосов
/ 15 июля 2009

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

В .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?

Ответы [ 3 ]

9 голосов
/ 15 июля 2009

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

Например:

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

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

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

Content = "{Binding Path = Commands}"

И затем вы можете снова связать ItemControl с командами, но этот ItemControl находится внутри содержимого, связываемого с командами. Таким образом, вам не нужно указывать путь снова. Вы можете просто использовать

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

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

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

1 голос
/ 15 июля 2009

Пример:

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; }
}
1 голос
/ 15 июля 2009

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...