C# WPF 数据模板和绑定

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1128897/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 08:52:28  来源:igfitidea点击:

WPF DataTemplate and Binding

c#wpfdata-binding.net-3.5templates

提问by Patrick Desjardins

I continue my understanding of MVVC with the code of MSDNand I have a question.

我用MSDN代码继续我对MVVC的理解,我有一个问题。

In the .xaml they have a list of commands displayed to the screen.

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

From here, I understand that the DataContext is set (not shown here) and it will display the collection of Commands. What I do not understand is the CommandsTemplate that you can see below:

从这里,我了解到 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>

How does the binding is created? How this code tell to check the property Command and DisplayName from the object inside the collection? Is it from the ItemsSource? If yes, I do not understand why it's only at {Binding}. Anyone can explain me please how the DataTemplate binding work from a ContentTemplate?

绑定是如何创建的?这段代码如何告诉从集合内的对象检查属性 Command 和 DisplayName ?它来自 ItemsSource 吗?如果是,我不明白为什么它只在 {Binding}。任何人都可以向我解释一下 DataTemplate 绑定如何从 ContentTemplate 工作?

采纳答案by Michael Sync

As you said, the DataContext is set to the ViewModel class so the control that you mentioned in XAML will be able to access the public properties of that ViewModel.

正如您所说,DataContext 设置为 ViewModel 类,因此您在 XAML 中提到的控件将能够访问该 ViewModel 的公共属性。

For example:

例如:

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

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

The structure of Commander class.

Commander 类的结构。

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

That VM has the property called Commands which might be ObservableCollection. This property can be accessible from XAML.

该 VM 具有名为 Commands 的属性,它可能是 ObservableCollection。可以从 XAML 访问此属性。

You can imagine that HeaderedContentControl is a container. The content of that HeaderedContentControl is a DataTemplate "CommandsTemplate" that has a ItemsControl and it bind to the Commands property of VM.

你可以想象 HeaderedContentControl 是一个容器。该 HeaderedContentControl 的内容是一个 DataTemplate “CommandsTemplate”,它有一个 ItemsControl,它绑定到 VM 的 Commands 属性。

Content="{Binding Path=Commands}"

内容="{绑定路径=命令}"

And then, you can to bind ItemControl with Commands again but that ItemControl is inside the content that bind to Commands. So you don't need to specify the path again. You can just use

然后,您可以再次将 ItemControl 与 Commands 绑定,但该 ItemControl 位于绑定到 Commands 的内容中。所以你不需要再次指定路径。你可以使用

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

Two textblocks are inside ItemControl so they are at the same level as Commander class of Commands ObservableCollection. That's why you can access Text="{Binding Path=DisplayName}" directly.

两个文本块位于 ItemControl 内,因此它们与 Commands ObservableCollection 的 Commander 类处于同一级别。这就是您可以直接访问 Text="{Binding Path=DisplayName}" 的原因。

Hope it helps.

希望能帮助到你。

回答by Ray

The ItemsSource binding to {Binding} binds directly to the DataContext of the ItemsControl (which will look up the chain until it finds a set DataContext). In this case it has been set in the HeaderedContentControl

ItemsSource 绑定到 {Binding} 直接绑定到 ItemsControl 的 DataContext(它将查找链,直到找到设置的 DataContext)。在这种情况下,它已在 HeaderedContentControl 中设置

Each item inside the ItemsControl will then have its DataContext set to an element in the list.

然后 ItemsControl 中的每个项目都将其 DataContext 设置为列表中的一个元素。

The <ItemsControl.ItemTemplate>is setting the template for each Item inside the list, not for the ItemsControl itself. So that {Binding Path=Command}and {Binding Path=DisplayName}will look at those properties on the elements inside the list.

<ItemsControl.ItemTemplate>是为列表中的每个 Item 设置模板,而不是为 ItemsControl 本身设置模板。所以这{Binding Path=Command}{Binding Path=DisplayName}将着眼于在列表中的元素的属性。

回答by Michael Sync

Example:

例子:

XAML

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#

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