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