В WPF, как привязать данные к окну DataContext из DataTemplate содержимого ListBox? - PullRequest
8 голосов
/ 24 декабря 2009

У меня есть окно WPF с моделью представления, установленной как его DataContext, и ListBox с DataTemplate и его 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>

Конечно, свойство TeamName класса Team не отображается в элементах ListBox, поскольку каждый элемент LisBox является DataContext объекта List.ItemTemplate и переопределяет DataContext окна.

Вопрос заключается в следующем: как привязать данные к свойству TeamName модели представления (Window.DataContext) из DataTemplate ListBox?

Ответы [ 4 ]

14 голосов
/ 25 декабря 2009

Вы также можете использовать привязку RelativeSource, это не так сложно:

<TextBlock Text="{Binding Path=DataContext.TeamName, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" Margin="4"/>
13 голосов
/ 24 декабря 2009

Я бы извлекла объявление 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>
1 голос
/ 25 декабря 2009

Я бы создал модель представления для члена команды со свойством 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 вам не понадобятся какие-либо экзотические приемы привязки в представлении. Все, что вам нужно, должно быть доступно через модель представления.

0 голосов
/ 26 декабря 2009

Почему вы не привязываете свой DataContext к команде, а затем привязываете свой источник предметов к team.members?

Обычно я присваиваю свой текстовый текст в своем коде, но он все равно не должен отличаться от вас.

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

Полагаю, это то же самое, что предлагал Авиад. Просто я назначаю datacontext в моем коде.

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