简体   繁体   English

在WPF中,如何从包含ListBox的DataTemplate内部数据绑定到Window DataContext?

[英]In WPF, how to databind to the Window DataContext from inside the DataTemplate of a contained ListBox?

I have a WPF Window with a view model set as its DataContext, and have a ListBox with a DataTemplate and its ItemsSource bound to the view model, like in the following example: 我有一个WPF窗口,其视图模型设置为其DataContext,并且具有一个带有DataTemplate的ListBox,其ItemsSource绑定到视图模型,如下例所示:

View model: 查看型号:

using System.Collections.Generic;

namespace Example
{
    class Member
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

    class Team
    {
        private List<Member> members = new List<Member>();

        public string TeamName { get; set; }
        public List<Member> Members { get { return members; } }
    }
}

MainWindow.xaml: MainWindow.xaml:

<Window x:Class="Example.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:l="clr-namespace:Example" 
    Title="Example" Height="300" Width="300" Name="Main">

 <Window.DataContext>
  <l:Team TeamName="The best team">
   <l:Team.Members>
    <l:Member Name="John Doe" Age="23"/>
    <l:Member Name="Jane Smith" Age="20"/>
    <l:Member Name="Max Steel" Age="24"/>
   </l:Team.Members>
  </l:Team>
 </Window.DataContext>

 <ListBox ItemsSource="{Binding Path=Members}">
  <ListBox.ItemTemplate>
   <DataTemplate>
    <StackPanel Orientation="Horizontal">
     <TextBlock Text="{Binding Path=TeamName}" Margin="4"/>
     <TextBlock Text="{Binding Path=Name}" Margin="4"/>
    </StackPanel>
   </DataTemplate>
  </ListBox.ItemTemplate>
 </ListBox>
</Window>

Of course, the TeamName property of the Team class is not displayed in the ListBox items because each item of the LisBox is the DataContext of the List.ItemTemplate, and it overrides the DataContext of the Window. 当然,Team类的TeamName属性不会显示在ListBox项中,因为LisBox的每个项都是List.ItemTemplate的DataContext,它会覆盖Window的DataContext。

The question is: How do I databind to the TeamName property of the view model (Window.DataContext) from within the ListBox's DataTemplate? 问题是:如何从ListBox的DataTemplate中数据绑定到视图模型(Window.DataContext)的TeamName属性?

I would extract the l:Team declaration to the Window.Resources section, and reference it from within the DataContext and the DataTemplate: 我将l:Team声明提取到Window.Resources部分,并从DataContext和DataTemplate中引用它:

<Window x:Class="Example.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:l="clr-namespace:Example" 
    Title="Example" Height="300" Width="300" Name="Main">

 <Window.Resources>
  <l:Team x:Key="data" TeamName="The best team">
   <l:Team.Members>
    <l:Member Name="John Doe" Age="23"/>
    <l:Member Name="Jane Smith" Age="20"/>
    <l:Member Name="Max Steel" Age="24"/>
   </l:Team.Members>
  </l:Team>
 <Window.Resources>

 <Window.DataContext>
     <StaticResource ResourceKey="data"/>
 </Window.DataContext>

 <ListBox ItemsSource="{Binding Path=Members}">
  <ListBox.ItemTemplate>
   <DataTemplate>
    <StackPanel Orientation="Horizontal">
     <TextBlock Text="{Binding Source={StaticResource data}, Path=TeamName}" Margin="4"/>
     <TextBlock Text="{Binding Path=Name}" Margin="4"/>
    </StackPanel>
   </DataTemplate>
  </ListBox.ItemTemplate>
 </ListBox>
</Window>

你也可以使用RelativeSource绑定,它并不复杂:

<TextBlock Text="{Binding Path=DataContext.TeamName, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" Margin="4"/>

I'd create a view model for a team member, with a TeamName property, something like: 我将为团队成员创建一个视图模型,其中包含TeamName属性,例如:

class MemberViewModel
{
    ...
    private TeamViewModel _team; 
    public string TeamName{ get { return _team.Name; } } 
}

class TeamViewModel
{
    public List< MemberViewModel > Members { get{ ... } }
    // You may consider using ObservableCollection<> instead of List<>
}

Then your XAML will look as clean as in your example. 然后你的XAML看起来就像你的例子一样干净。 With MVVM, you shouldn't need any exotic binding tricks in the view. 使用MVVM,您不应该在视图中使用任何异国情调的绑定技巧。 All you need should be available via the view model. 您应该通过视图模型获得所需的一切。

Why dont you bind your DataContext to team, then make your itemsource bound to team.members? 为什么不将DataContext绑定到团队,然后将您的itemsource绑定到team.members?

usually I am assigning my datacontext in my codebehind but its still shouldnt be anydifferent for you. 通常我在我的代码隐藏中分配我的datacontext但它仍然不应该对你有任何不同。

itemsouce="{Binding Path="team.Members"} itemsouce =“{Binding Path =”team.Members“}

I guess really its the same thing as what Aviad suggested. 我想这与Aviad建议的完全相同。 Just I assign datacontext in my codebehind. 我只是在代码隐藏中分配datacontext。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM