Я сделал минималистичный пример своей проблемы. Сначала здесь диаграмма классов Диаграмма классов
Что я хочу: я хочу отобразить каждое свойство из класса A в сетке данных WPF с возможностью редактирования каждого свойства.
Если я просто добавлю объект A в ObservableCollection и добавлю его в качестве ItemsSource в DataGrid, результат, как и ожидалось, не тот, который мне нужен.
Вот почему я добавил следующий класс:
public class DataGridRowObjects
{
public A ObjectA { get; set; }
public B ObjectB { get; set; }
public AbstractC ObjectC { get; set; }
}
Проблема в том, что некоторые ячейки будут пустыми из-за AbstractC . Если у меня ConcreteC1 , я хочу, чтобы столбцы, заданные ConcreteC1 , были доступны для редактирования. Если в этой строке есть объект ConcreteC2 , я хочу отключить эти ячейки с помощью некоторого текста, например свойство недоступно .
Я получил решение этой проблемы,но моя проблема в качестве кода (очень некрасивое решение) с мыслью о поддержке.
Это мой подход к решению проблемы, чтобы иметь возможность редактировать каждое свойство в этой сетке данных Результат в действии :
<DataGrid x:Name="dataGridForA" AutoGenerateColumns="False" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn Header="PropertyAA" Binding="{Binding ObjectA.PropertyAA}"/>
<DataGridTextColumn Header="PropertyAB" Binding="{Binding ObjectA.PropertyAB}"/>
<DataGridTextColumn Header="PropertyBA" Binding="{Binding ObjectB.PropertyBA}"/>
<DataGridTextColumn Header="PropertyAbstractCA" Binding="{Binding ObjectC.PropertyAbstractCA}" />
<DataGridTemplateColumn Header="PropertyConcreteC1A">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding ObjectC}">
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type model:ConcreteC1}">
<TextBlock Text="{Binding PropertyConcreteC1A}" />
</DataTemplate>
<DataTemplate DataType="{x:Type model:ConcreteC2}">
<TextBlock Text="Property not available" />
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<!-- Some cool stuff to edit properties -->
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="PropertyConcreteC2A">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding ObjectC}">
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type model:ConcreteC2}">
<TextBlock Text="{Binding PropertyConcreteC2A}" />
</DataTemplate>
<DataTemplate DataType="{x:Type model:ConcreteC1}">
<TextBlock Text="Property not available" />
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<!-- Some cool stuff to edit properties -->
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Проблема в части с DataGridTemplateColumn . В этом примере это выглядит довольно просто. Но в моей реальной задаче у меня есть еще много свойств и в настоящее время четыре класса, которые происходят от AbstractC . Который в конечном итоге будет выглядеть как четыре DataTemplates для каждого ConcreteC-Class и для каждого свойства этих ConcreteC-Classes . XAML в моей реальной проблеме взорвется и не подлежит ремонту. Может быть, у некоторых из вас есть другое решение?
Приложение
Вот классы, может быть, для лучшего обзора и как я настраиваю Datagrid ItemsSource
public class A
{
public string PropertyAA { get; set; }
public string PropertyAB { get; set; }
public List<B> ListB { get; set; }
}
public class B
{
public string PropertyBA { get; set; }
public List<AbstractC> ListAbstractC { get; set; }
}
public abstract class AbstractC
{
public string PropertyAbstractCA { get; set; }
}
public class ConcreteC1 : AbstractC
{
public string PropertyConcreteC1A { get; set; }
}
public class ConcreteC2 : AbstractC
{
public string PropertyConcreteC2A { get; set; }
}
Настройка:
public class DataGridRowObjects
{
public A ObjectA { get; set; }
public B ObjectB { get; set; }
public AbstractC ObjectC { get; set; }
}
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public List<A> aList = new List<A>();
public ObservableCollection<DataGridRowObjects> modelList = new ObservableCollection<DataGridRowObjects>();
public MainWindow()
{
InitializeComponent();
ConcreteC1 concreteC1A = new ConcreteC1 { PropertyAbstractCA = "TestA1", PropertyConcreteC1A = "TestConcrete1A" };
ConcreteC2 concreteC2A = new ConcreteC2 { PropertyAbstractCA = "TestA2", PropertyConcreteC2A = "TestConcrete2A" };
ConcreteC1 concreteC1B = new ConcreteC1 { PropertyAbstractCA = "TestB1", PropertyConcreteC1A = "TestConcrete1B" };
ConcreteC2 concreteC2B = new ConcreteC2 { PropertyAbstractCA = "TestB2", PropertyConcreteC2A = "TestConcrete2B" };
List<AbstractC> concreteAs = new List<AbstractC>();
concreteAs.Add(concreteC1A);
concreteAs.Add(concreteC2A);
B bA = new B { ListAbstractC = concreteAs, PropertyBA = "bA" };
List<AbstractC> concreteBs = new List<AbstractC>();
concreteBs.Add(concreteC1B);
concreteBs.Add(concreteC2B);
B bB = new B { ListAbstractC = concreteBs, PropertyBA = "bB" };
List<B> bList = new List<B>();
bList.Add(bA);
bList.Add(bB);
A objectA = new A {PropertyAA = "AA", PropertyAB = "AB", ListB = bList};
aList.Add(objectA);
foreach (A a in aList)
{
foreach (B b in a.ListB)
{
foreach (AbstractC c in b.ListAbstractC)
{
this.modelList.Add(new DataGridRowObjects { ObjectA = a, ObjectB = b, ObjectC = c });
}
}
}
this.dataGridForA.ItemsSource = modelList;
}
}