Привязка элементов внутри элемента с другой привязкой

Возникла следующая проблема.

Есть 2 ObservableCollection: это EmpList и AbsCatList. DataGrid привязывается к EmpList и показывает оттуда данные. Внутри грида есть ComboBox, который хранит данные из AbsCatList. Но его тег необходимо указать из EmpList. И вопрос заключается в следующем, как в ComboBox показывать данные из AbsCatList, а указать его тег - из EmpList?

    <Page.Resources>
        <viewmodel:EmployerList x:Key="emp"/>
        <viewmodel:AbsenceCategoryList x:Key="absCat"/>
    </Page.Resources>

    <Grid Background="White">
        <DataGrid Name="TimeSheetGrid" IsReadOnly="True" AutoGenerateColumns="False"
                  DataContext="{Binding Source={StaticResource emp}}" 
                  ItemsSource="{Binding Path=EmpList}"
                  SelectedValuePath="EmpID">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding EmpName}" Width="Auto">
                    <DataGridTextColumn.Header>Тип</DataGridTextColumn.Header>
                </DataGridTextColumn>
                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <ComboBox Width="230" IsReadOnly="True" 
                                      DataContext="{Binding Source={StaticResource absCat}}" 
                                      ItemsSource="{Binding Path=AbsCatList}" 
                                      DisplayMemberPath="Name" SelectedValuePath="Id" 
                                      Tag="{Binding Path=EmpList, ElementName=EmpID}" 
                                      SelectionChanged="ComboBox_SelectionChanged"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>

Ответы (1 шт):

Автор решения: aepot

Покажу простой пример с вот такой разметкой

<Window x:Class="WpfAppDGCombo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfAppDGCombo"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"
        d:DataContext="{d:DesignInstance local:MainViewModel}">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal">
            <Button Padding="10,5" Content="Click me" Margin="5" Click="Button_Click"/>
        </StackPanel>
        <DataGrid Grid.Row="1" ItemsSource="{Binding Members}" AutoGenerateColumns="False">
            <DataGrid.Resources>
                <CollectionViewSource x:Key="Genders" Source="{Binding Genders}"/>
            </DataGrid.Resources>
            <DataGrid.Columns>
                <DataGridTextColumn Header="Имя" Binding="{Binding Name}"/>
                <DataGridComboBoxColumn Header="Пол" ItemsSource="{Binding Source={StaticResource Genders}}"
                                        DisplayMemberPath="Name"
                                        SelectedValuePath="Id"
                                        SelectedValueBinding="{Binding GenderId}"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

Вот такой код-бихайнд

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new MainViewModel();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        MainViewModel vm = (MainViewModel)DataContext;
        Debug.WriteLine(JsonSerializer.Serialize(vm.Members, new JsonSerializerOptions { WriteIndented = true, Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }));
    }
}

Здесь обработчик события только для простоты, я советую использовать команды.

Вот такие модели

public class Gender
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class Member
{
    public string Name { get; set; }
    public int GenderId { get; set; }
}

И вот такая вьюмодель

public class MainViewModel
{
    public Gender[] Genders { get; }
    public ObservableCollection<Member> Members { get; }

    public MainViewModel() 
    {
        Genders = new Gender[]
        {
            new Gender { Id = 0, Name = "не задан" },
            new Gender { Id = 1, Name = "Мужской" },
            new Gender { Id = 2, Name = "Женский" }
        };

        Members = new ObservableCollection<Member>();
    }
}

Запускаю, заполняю данными таблицу руками

введите сюда описание изображения

Жму кнопку, получаю вывод в консоль студии

[
  {
    "Name": "Анатолий",
    "GenderId": 1
  },
  {
    "Name": "Жанна",
    "GenderId": 2
  },
  {
    "Name": "Кто-то",
    "GenderId": 0
  }
]

Как видите, Tag или обработчик SelectedItemChanged мне не потребовались.

введите сюда описание изображения

Если хотите управлять данными из кода в реальном времени, то реализуйте INotifyPropertyChanged для вьюмодели и классов с изменяемыми из кода данными.

→ Ссылка