Я имею Окно WPF с целью образцовый набор как его DataContext и имею ListBox с DataTemplate и его ItemsSource, связанным с моделью представления, как в следующем примере:
Модель View:
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 класса Команды не отображено в объектах ListBox, потому что каждым объектом LisBox является DataContext Списка. ItemTemplate, и это переопределяет DataContext Окна.
Вопрос: Как я связываю с данными к свойству TeamName модели представления (Окно. DataContext) из DataTemplate ListBox?
Я бы извлек объявление 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>
Я бы создал модель представления для члена команды с 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 вам не понадобятся какие-либо экзотические трюки привязки в представлении. Все, что вам нужно, должно быть доступно через модель просмотра.
Вы также можете использовать привязку RelativeSource, это не так уж и сложно:
<TextBlock Text="{Binding Path=DataContext.TeamName, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" Margin="4"/>
Почему вы не связываете свой DataContext с командой, а затем не связываете свой источник данных с team.members?
обычно я назначаю свой dataacontext в коде позади, но он все равно не должен быть для вас равнозначным.
itemsouce="{Binding Path="team.Members"}
Я думаю, что на самом деле это то же самое, что и то, что предложил Aviad. Просто я присваиваю текст данных в своем коде.