Member 13796002 Ответов: 1

Как я могу работать с combobox внутри datagrid в WPF?


У меня есть combobox, который содержит данные, заполненные из базы данных. Я могу использовать привязку combobox в текстовое поле, например :


Но когда то же самое применяется к 1-му столбцу, функция combobox не срабатывает, она ведет себя так же, как и другое текстовое поле

Что я уже пробовал:

<DataGridTemplateColumn Header="ProductName" ClipboardContentBinding="{Binding ProductName}">
                            <DataGridTemplateColumn.CellTemplate >
                                <DataTemplate >
                                 <TextBox Text="{Binding  ProductName, NotifyOnTargetUpdated=True,  UpdateSourceTrigger=PropertyChanged}" >                                   </TextBox>
                                   
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                            <DataGridTemplateColumn.CellEditingTemplate>
                                <DataTemplate>
                                    <ComboBox IsEditable="True" Name="cmbProductName"  ItemsSource="{StaticResource ProductNames}" SelectedItem="{Binding ProductName ,  Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" IsDropDownOpen="False" >

                                    </ComboBox>
                                </DataTemplate>
                            </DataGridTemplateColumn.CellEditingTemplate>
                        </DataGridTemplateColumn>

1 Ответов

Рейтинг:
2

Graeme_Grant

Вот вам рабочий пример...

Во-первых, базовый класс для INotifyPropertyChanged для уведомлений о привязке данных:

public abstract class ObservableBase : INotifyPropertyChanged
{
    public void Set<TValue>(ref TValue field, TValue newValue,
                            [CallerMemberName] string propertyName = "")
    {
        if (EqualityComparer<TValue>.Default.Equals(field, default(TValue))
            || !field.Equals(newValue))
        {
            field = newValue;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

Далее нам нужна модель данных для хранения каждой строки для редактирования:
public class PersonModel : ObservableBase
{
    private string name;
    public string Name
    {
        get { return name; }
        set { Set(ref name, value); }
    }

    private int age;
    public int Age
    {
        get { return age; }
        set { Set(ref age, value); }
    }

    private int income;
    public int Income
        {
        get { return income; }
        set { Set(ref income, value); }
    }
}

Далее нам нужно иметь ViewModel чтобы связать наши данные с представлением:
class MainViewModel
{
    public MainViewModel()
    {
        Mock();
    }

    private void Mock()
    {
        for (int i = 20; i < 120; i++)
        {
            AgeRange.Add(i);
        }

        for (int i = 0; i < 100; i++)
        {
            IncomeRange.Add(10000 + 10 * i);
        }

        for (int i = 0; i < 100; i++)
        {
            People.Add(new PersonModel
            {
                Name = $"Person {i}",
                Age = AgeRange[rand.Next(0, AgeRange.Count - 1)],
                Income = IncomeRange[rand.Next(0, IncomeRange.Count - 1)]
            });
        }
    }

    private Random rand = new Random();

    public ObservableCollection<PersonModel> People { get; }
        = new ObservableCollection<PersonModel>();

    public ObservableCollection<int> AgeRange { get; }
        = new ObservableCollection<int>();

    public ObservableCollection<int> IncomeRange { get; }
        = new ObservableCollection<int>();
}

Теперь мы можем сделать вид:
<Window x:Class="DataGridColumnComboBox.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:DataGridColumnComboBox"

        mc:Ignorable="d"

        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>
    <DataGrid ItemsSource="{Binding People}"

              AutoGenerateColumns="False"

              GridLinesVisibility="None" Margin="10">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="200"/>

            <DataGridComboBoxColumn Header="Age" Width="75"

                                    SelectedItemBinding="{Binding Age}">
                <DataGridComboBoxColumn.ElementStyle>
                    <Style TargetType="ComboBox">
                        <Setter Property="ItemsSource"

                                Value="{Binding RelativeSource={RelativeSource
                                    FindAncestor, 
                                    AncestorType={x:Type Window}},
                                    Path=DataContext.AgeRange}"/>
                    </Style>
                </DataGridComboBoxColumn.ElementStyle>
                <DataGridComboBoxColumn.EditingElementStyle>
                    <Style TargetType="ComboBox">
                        <Setter Property="ItemsSource"

                                Value="{Binding RelativeSource={RelativeSource
                                    FindAncestor,
                                    AncestorType={x:Type Window}},
                                    Path=DataContext.AgeRange}"/>
                    </Style>
                </DataGridComboBoxColumn.EditingElementStyle>
            </DataGridComboBoxColumn>

            <DataGridComboBoxColumn Header="Income" Width="150"

                                    SelectedItemBinding="{Binding Income}">
                <DataGridComboBoxColumn.ElementStyle>
                    <Style TargetType="ComboBox">
                        <Setter Property="ItemsSource"

                                Value="{Binding RelativeSource={RelativeSource
                                    FindAncestor, 
                                    AncestorType={x:Type Window}},
                                    Path=DataContext.IncomeRange}"/>
                    </Style>
                </DataGridComboBoxColumn.ElementStyle>
                <DataGridComboBoxColumn.EditingElementStyle>
                    <Style TargetType="ComboBox">
                        <Setter Property="ItemsSource"

                                Value="{Binding RelativeSource={RelativeSource
                                    FindAncestor,
                                    AncestorType={x:Type Window}},
                                    Path=DataContext.IncomeRange}"/>
                    </Style>
                </DataGridComboBoxColumn.EditingElementStyle>
            </DataGridComboBoxColumn>
        </DataGrid.Columns>
    </DataGrid>
</Window>

Вид довольно многословен. Вы можете упростить код и уменьшить количество опечаток с помощью стилей:
<DataGrid ItemsSource="{Binding People}"

          AutoGenerateColumns="False"

          GridLinesVisibility="None" Margin="10">
    <DataGrid.Resources>
        <Style TargetType="ComboBox" x:Key="AgeRangeStyle">
            <Setter Property="ItemsSource"

                    Value="{Binding RelativeSource={RelativeSource
                                FindAncestor, 
                                AncestorType={x:Type Window}},
                                Path=DataContext.AgeRange}"/>
        </Style>
        <Style TargetType="ComboBox" x:Key="IncomeRangeStyle">
            <Setter Property="ItemsSource"

                    Value="{Binding RelativeSource={RelativeSource
                                FindAncestor, 
                                AncestorType={x:Type Window}},
                                Path=DataContext.IncomeRange}"/>
        </Style>
    </DataGrid.Resources>
    <DataGrid.Columns>
        <DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="200"/>

        <DataGridComboBoxColumn Header="Age" Width="75"

                                SelectedItemBinding="{Binding Age}"

                                ElementStyle="{StaticResource AgeRangeStyle}"

                                EditingElementStyle="{StaticResource AgeRangeStyle}"/>

        <DataGridComboBoxColumn Header="Income" Width="75"

                                SelectedItemBinding="{Binding Income}"

                                ElementStyle="{StaticResource IncomeRangeStyle}"

                                EditingElementStyle="{StaticResource
                                                                  IncomeRangeStyle}"/>

    </DataGrid.Columns>
</DataGrid>

Наслаждайтесь!

ОБНОВЛЕНИЕ: Изменен первый столбец, чтобы использовать редактор ComboBox... смотри ОП комментариях ниже.

MainViewModel:
class MainViewModel
{
    public MainViewModel()
    {
        Mock();
    }

    private void Mock()
    {
        for (int i = 20; i < 120; i++)
        {
            AgeRange.Add(i);
        }

        for (int i = 0; i < 100; i++)
        {
            IncomeRange.Add(10000 + 10 * i);
        }

        for (int i = 0; i < 100; i++)
        {
            People.Add(new PersonModel
            {
                Name = $"Person {i}",
                Age = AgeRange[rand.Next(0, AgeRange.Count - 1)],
                Income = IncomeRange[rand.Next(0, IncomeRange.Count - 1)]
            });
        }

        Names = new ObservableCollection<string>(People.Select(x => x.Name));
    }

    private Random rand = new Random();

    public ObservableCollection<PersonModel> People { get; }
        = new ObservableCollection<PersonModel>();

    public ObservableCollection<int> AgeRange { get; }
        = new ObservableCollection<int>();

    public ObservableCollection<int> IncomeRange { get; }
        = new ObservableCollection<int>();

    public ObservableCollection<string> Names { get; private set; }
}

А вид-это DataGrid:
<DataGrid ItemsSource="{Binding People}"

          AutoGenerateColumns="False"

          GridLinesVisibility="None" Margin="10">
    <DataGrid.Resources>
        <Style TargetType="ComboBox" x:Key="NamesStyle">
            <Setter Property="ItemsSource"

                    Value="{Binding RelativeSource={RelativeSource
                                FindAncestor, 
                                AncestorType={x:Type Window}},
                                Path=DataContext.Names}"/>
        </Style>
        <Style TargetType="ComboBox" x:Key="AgeRangeStyle">
            <Setter Property="ItemsSource"

                    Value="{Binding RelativeSource={RelativeSource
                                FindAncestor, 
                                AncestorType={x:Type Window}},


Member 13796002

Привет, Graeme_Grant, Спасибо за ответ. Но в приведенном вами примере столбец combobox является вторым столбцом. Он прекрасно работает, когда это второй столбец, но не как первый столбец. Поскольку мне нужно получить данные по другим столбцам на основе выбора combobox

Graeme_Grant

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

Dennis W. M.

Этот пример заставил мое решение работать. Спасибо!

Graeme_Grant

Рад слышать, что это помогло!