This requirement is to have different headers on different child grids of a XamDataGrid. It's a difficult requirement to meet for any data bound grid and the XamDataGrid solution is no worse or better than other grids I've done this for.
In this scenario I have a grid of financial documents and each document has multiple financial accounts. Each document uses one of two account structures. Each account structure has multiple account sections, each of which has it's own name. When we are displaying accounts for a document that uses account structure 1, we must use labels for account structure 1.
I define two account structures each of which contains a list of section headings. I also define two documents that use these account structures and an account for each document.
Start a new WPF project and call it XamDataGridAltBindings.
Let's start with simple XAML that does not have bound labels for the child rows. We'll add them later.
<Window x:Class="XamDataGridAltBindings.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:XamDataGridAltBindings"
xmlns:igDP="http://infragistics.com/DataPresenter"
mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Window.Resources>
<FrameworkElement x:Key="ProxyElement"/>
<local:AccountStructureConverter x:Key="AccountStructureConverter"/>
</Window.Resources>
<Grid>
<ContentControl Visibility="Collapsed" Content="{StaticResource ProxyElement}"/>
<igDP:XamDataGrid DataSource="{Binding Documents}">
<igDP:XamDataGrid.FieldLayoutSettings>
<igDP:FieldLayoutSettings AutoGenerateFields="False" ExpansionIndicatorDisplayMode="Always"/>
</igDP:XamDataGrid.FieldLayoutSettings>
<igDP:XamDataGrid.FieldLayouts>
<igDP:FieldLayout Key="Documents">
<igDP:FieldLayout.Fields>
<igDP:TextField Label="Document" Name="DocumentName" Width="*"/>
<igDP:Field Label="Accounts" Name="Accounts"/>
</igDP:FieldLayout.Fields>
</igDP:FieldLayout>
<igDP:FieldLayout ParentFieldLayoutKey="Documents" ParentFieldName="Accounts">
<igDP:FieldLayout.Settings>
<igDP:FieldLayoutSettings AutoGenerateFields="False" ExpansionIndicatorDisplayMode="Never"/>
</igDP:FieldLayout.Settings>
<igDP:FieldLayout.Fields>
<igDP:TextField Name="Value1"/>
</igDP:FieldLayout.Fields>
</igDP:FieldLayout>
</igDP:XamDataGrid.FieldLayouts>
</igDP:XamDataGrid>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
namespace XamDataGridAltBindings
{
public partial class MainWindow : Window
{
public class cDocument
{
public String DocumentName { get; set; }
public cAccountStructure AccountStructure { get; set; }
public List<cAccount> Accounts { get; set; }
public cDocument(String
DocumentName, cAccountStructure
AccountStructure)
{
this.DocumentName = DocumentName;
this.AccountStructure = AccountStructure;
this.Accounts = new List<cAccount>();
}
}
public class cAccountStructure
{
public String Name { get; set; }
public List<String> Heading { get; set; }
public cAccountStructure(String
Name, List<String> Heading)
{
this.Name = Name;
this.Heading = Heading;
}
}
public class cAccount
{
public String Value1 { get; set; }
public String Value2 { get; set; }
public String Value3 { get; set; }
public cAccount(String
Value1, String Value2, String Value3)
{
this.Value1 = Value1;
this.Value2 = Value2;
this.Value3 = Value3;
}
}
public List<cDocument> Documents { get; set; }
public cAccountStructure AccountStructure1;
public cAccountStructure AccountStructure2;
public MainWindow()
{
AccountStructure1 = new cAccountStructure("K12",new List<String> { "Fu","Rs","Y" });
AccountStructure2 = new cAccountStructure("College", new List<String> { "Fu","Ls","Si" });
Documents = new List<cDocument>() { new cDocument("Document 1 K12", AccountStructure1) , new cDocument("Document 2
College",
AccountStructure2) };
Documents[0].Accounts.Add(new cAccount("01", "0000", "0"));
Documents[1].Accounts.Add(new cAccount("12", "20", "9022"));
InitializeComponent();
}
}
}
The default column label is the path of the column. |
<igDP:TextField Name="Value1"/>
with this XAML that allows us to bind the label explicitly...
<igDP:TextField Name="Value1">
<igDP:TextField.Settings>
<igDP:FieldSettings>
<igDP:FieldSettings.LabelPresenterStyle>
<Style TargetType="igDP:LabelPresenter">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type igDP:LabelPresenter}}, Path=(igDP:HeaderPresenter.RecordManager).ParentDataRecord, Converter={StaticResource AccountStructureConverter}, ConverterParameter=0}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</igDP:FieldSettings.LabelPresenterStyle>
</igDP:FieldSettings>
</igDP:TextField.Settings>
</igDP:TextField>
Now replace the code with this. The DataRecord passed to us contains our Document in its DataItem property. Our Document contains a reference to the AccountStructure for the document. We can use the parameter to find the correct label for the data column.
using Infragistics.Windows.DataPresenter;
using System;
using System.Windows.Data;
using static XamDataGridAltBindings.MainWindow;
namespace XamDataGridAltBindings
{
public class AccountStructureConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo
culture)
{
if
(value == null) return string.Empty;
DataRecord parentRecord = value as
DataRecord;
cDocument Document = parentRecord.DataItem as cDocument;
return Document.AccountStructure.Heading[int.Parse((String)parameter)];
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo
culture)
{
throw
new NotImplementedException();
}
}
}
When we run the solution now (with the other two account sections added) we see we have bound labels that differ from child to child.