Так что это мне любопытно, так как мне, возможно, придется изменить свою базу кода, если я не смогу получить правильные данные. Я надеялся, что у специалиста по связыванию по WPF было что-то подобное, и он знал, как это сделать. Я следовал этому руководству, http://wpfoughtts.blogspot.com/2015/04/cannot-find-goGovernance-frameworkelement.html для привязки значения в списке, отображаемом в datagrid, к полю со списком. Отлично работает, если ваше свойство в коллекции объектов является примитивным типом. Если сложно, то не так уж и много. Я также хочу, чтобы он обновлял свойство при изменении реализации INotifyPropertyChanged.
Не стесняйтесь загрузить исходный код для более удобного использования: https://github.com/djangojazz/ComboBoxInDataGridViewWPF
BaseViewModel (только для повторного использования INotifyPropertyChanged):
public abstract class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
}
По сути, у меня есть модели как таковые:
public class Type
{
public Type(int typeId, string typeName)
{
TypeId = typeId;
TypeName = typeName;
}
public int TypeId { get; set; }
public string TypeName { get; set; }
}
public class TransactionSimple : BaseViewModel
{
public TransactionSimple(int transactionId, string description, int typeId, decimal amount)
{
TransactionId = transactionId;
Description = description;
TypeId = typeId;
Amount = amount;
}
public int TransactionId { get; set; }
public string Description { get; set; }
private int _typeId;
public int TypeId
{
get { return _typeId; }
set
{
_typeId = value;
OnPropertyChanged(nameof(TypeId));
}
}
public decimal Amount { get; set; }
}
public class TransactionComplex : BaseViewModel
{
public TransactionComplex(int transactionId, string description, int typeId, string typeName, decimal amount)
{
TransactionId = transactionId;
Description = description;
Type = new Type(typeId, typeName);
Amount = amount;
}
public int TransactionId { get; set; }
public string Description { get; set; }
private Type _type;
public Type Type
{
get { return _type; }
set
{
if(_type != null) { MessageBox.Show($"Change to {value.TypeName}"); }
_type = value;
OnPropertyChanged(nameof(Type));
}
}
public decimal Amount { get; set; }
}
И ViewModel:
public sealed class MainWindowViewModel : BaseViewModel
{
private ObservableCollection<TransactionSimple> _simples;
private ObservableCollection<TransactionComplex> _complexes;
public MainWindowViewModel()
{
FakeRepo();
}
private ReadOnlyCollection<Type> _types;
public ReadOnlyCollection<Type> Types
{
get => (_types != null) ? _types : _types = new ReadOnlyCollection<Type>(new List<Type> { new Type(1, "Credit"), new Type(2, "Debit") });
}
public ObservableCollection<TransactionSimple> Simples
{
get { return _simples; }
set
{
_simples = value;
OnPropertyChanged(nameof(Simples));
}
}
public ObservableCollection<TransactionComplex> Complexes
{
get { return _complexes; }
set
{
_complexes = value;
OnPropertyChanged(nameof(Complexes));
}
}
private void FakeRepo()
{
var data = new List<TransactionComplex>
{
new TransactionComplex(1, "Got some money", 1, "Credit", 1000m),
new TransactionComplex(2, "spent some money", 2, "Debit", 100m),
new TransactionComplex(3, "spent some more money", 2, "Debit", 300m)
};
Complexes = new ObservableCollection<TransactionComplex>(data);
Simples = new ObservableCollection<TransactionSimple>(data.Select(x => new TransactionSimple(x.TransactionId, x.Description, x.Type.TypeId, x.Amount)));
}
}
ОБНОВЛЕНО в 14:24 по тихоокеанскому стандартному времени (США): И, наконец, вид (почти рабочий):
<Window x:Class="ComboBoxInDataGridViewWPF.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:ComboBoxInDataGridViewWPF"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<CollectionViewSource x:Key="Types" Source="{Binding Types}"/>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Content="SimpleExample" />
<DataGrid Grid.Row="1" ItemsSource="{Binding Simples}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="TransactionId" Binding="{Binding TransactionId}" />
<DataGridTextColumn Header="Description" Binding="{Binding Description}" />
<DataGridComboBoxColumn Header="Type" ItemsSource="{Binding Source={StaticResource Types}}" DisplayMemberPath="TypeName" SelectedValuePath="TypeId" SelectedValueBinding="{Binding Path=TypeId}" />
<DataGridTextColumn Header="Amount" Binding="{Binding Amount}" />
</DataGrid.Columns>
</DataGrid>
<Border Grid.Row="2" Height="50" Background="Black" />
<Label Content="ComplexObjectExample" Grid.Row="3" />
<DataGrid Grid.Row="4" ItemsSource="{Binding Complexes}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="TransactionId" Binding="{Binding TransactionId}" />
<DataGridTextColumn Header="Description" Binding="{Binding Description}" />
<!--This one works for the displays but not for the updates
<DataGridTemplateColumn Header="Type">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Source={StaticResource Types}}" DisplayMemberPath="TypeName" SelectedItem="{Binding Type, Mode=TwoWay}" SelectedValue="{Binding Type.TypeId}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Type.TypeName}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>-->
<!--This one works but the initial displays are wrong. This seems to be the closest to what I want-->
<DataGridComboBoxColumn Header="Type" SelectedItemBinding="{Binding Type}" >
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Types}"/>
<Setter Property="DisplayMemberPath" Value="TypeName" />
<Setter Property="SelectedItem" Value="{Binding Type}" />
<Setter Property="IsReadOnly" Value="True"/>
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Types}"/>
<Setter Property="DisplayMemberPath" Value="TypeName" />
<Setter Property="SelectedItem" Value="{Binding Type}" />
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
<!--This one does not work at all
<DataGridTemplateColumn Header="Type">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Path=DataContext.Types,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"
DisplayMemberPath="TypeName" SelectedItem="{Binding Type}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>-->
<DataGridTextColumn Header="Amount" Binding="{Binding Amount}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
Проблема отображается следующим образом:
Я, очевидно, могу получить элементы, привязанные к ComboBox, и я это видел, добавив наблюдаемые коллекции (не показаны) и подняв свойства, вызываемые сложным типом. Но он не будет отображаться, что бы я ни пытался. Попытка использовать свойство свойства, такое как Type.TypeName или подобное, с различными комбинациями, не работает. Любые идеи?