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

时间:2009-12-24 20:18:07

标签: .net wpf data-binding mvvm datatemplate

我有一个WPF窗口,其视图模型设置为其DataContext,并且具有一个带有DataTemplate的ListBox,其ItemsSource绑定到视图模型,如下例所示:

查看型号:

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:

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

当然,TeamBox的TeamName属性不会显示在ListBox项中,因为LisBox的每个项都是List.ItemTemplate的DataContext,它会覆盖Window的DataContext。

问题是:如何从ListBox的DataTemplate中数据绑定到视图模型(Window.DataContext)的TeamName属性?

4 个答案:

答案 0 :(得分:14)

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

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

答案 1 :(得分:13)

我会将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>

答案 2 :(得分:1)

我为团队成员创建了一个视图模型,其中包含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<>
}

然后你的XAML看起来就像你的例子一样干净。使用MVVM,您不应该在视图中使用任何异国情调的绑定技巧。您应该通过视图模型获得所需的一切。

答案 3 :(得分:0)

为什么不将DataContext绑定到团队,然后将你的itemsource绑定到team.members?

通常我会在我的代码隐藏中分配我的datacontext,但它仍然不适合你。

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

我想这与Aviad建议的完全相同。我只是在代码隐藏中分配datacontext。