2009-07-15 43 views
5

Tôi tiếp tục hiểu biết về MVVC với số code of MSDN và tôi có một câu hỏi.WPF DataTemplate và Binding

Trong tệp .xaml, chúng có danh sách các lệnh được hiển thị trên màn hình.

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

Từ đây, tôi hiểu rằng DataContext được đặt (không hiển thị ở đây) và nó sẽ hiển thị tập hợp lệnh. Những gì tôi không hiểu là CommandsTemplate mà bạn có thể thấy bên dưới:

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

Liên kết được tạo ra như thế nào? Làm thế nào mã này nói để kiểm tra tài sản Command và DisplayName từ đối tượng bên trong bộ sưu tập? Là nó từ ItemsSource? Nếu có, tôi không hiểu tại sao nó chỉ ở {Binding}. Bất cứ ai có thể giải thích cho tôi xin vui lòng làm thế nào DataTemplate ràng buộc làm việc từ một ContentTemplate?

Trả lời

8

Như bạn đã nói, DataContext được đặt thành lớp ViewModel để điều khiển mà bạn đã đề cập trong XAML sẽ có thể truy cập các thuộc tính công khai của ViewModel đó.

Ví dụ:

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

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

Cấu trúc của lớp Commander.

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

Máy ảo đó có thuộc tính được gọi là Lệnh có thể là ObservableCollection. Bạn có thể truy cập thuộc tính này từ XAML.

Bạn có thể tưởng tượng rằng HeaderedContentControl là một vùng chứa. Nội dung của HeaderedContentControl đó là một DataTemplate "CommandsTemplate" có một ItemsControl và nó liên kết với thuộc tính Commands của VM.

Content = "{Binding Path = Lệnh}"

Và sau đó, bạn có thể để ràng buộc ItemControl với lệnh một lần nữa nhưng điều đó ItemControl là bên trong nội dung mà liên kết với Lệnh. Vì vậy, bạn không cần phải xác định đường dẫn một lần nữa. Bạn chỉ có thể sử dụng

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

Hai khối chữ nằm bên trong mụcControl để chúng ở cùng cấp với lớp lệnh Commander ObservableCollection. Đó là lý do tại sao bạn có thể truy cập trực tiếp vào Text = "{Binding Path = DisplayName}".

Hy vọng điều đó sẽ hữu ích.

1

Các mụcCác liên kết nguồn tới {Binding} liên kết trực tiếp với DataContext của ItemsControl (sẽ tìm kiếm chuỗi cho đến khi nó tìm thấy một DataContext được đặt). Trong trường hợp này, nó đã được đặt trong HeaderedContentControl

Mỗi mục bên trong ItemsControl sẽ có DataContext được đặt thành một phần tử trong danh sách.

<ItemsControl.ItemTemplate> đang đặt mẫu cho từng Mục trong danh sách, không phải cho chính ItemsControl. Vì vậy, {Binding Path=Command}{Binding Path=DisplayName} sẽ xem xét các thuộc tính đó trên các phần tử bên trong danh sách.

+0

Nếu nó liên kết trực tiếp đến DataContext nó nên được binded đến bối cảnh của Danh mục và không nguyên tố của danh sách? –

+0

Đó là sự thật cho ItemsControl, nhưng mỗi mục ** trong ItemsControl sẽ có một phần tử của danh sách cho DataContext của nó. – Ray

+0

Được rồi, vì vậy việc sử dụng {Binding} sẽ tìm kiếm một DataContext bên trong bộ sưu tập này đúng không? –

1

Ví dụ:

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