The obvious way to implement this is to create a event the control can raise when it sees a column's aggregate is custom. The page can subscribe to the event and provide a value.
The custom aggregate will be triggered when the column's aggregate has the form "CUSTOM(stringvalue)". The event will use a custom event args that includes an Aggregate property that will contain stringvalue. The event will pass a reference to the grid in the sender argument.
If you follow through the blog entry referenced above you will end up with a solution that displays the page below.
We will alter the aggregate for the CanRead and CanWrite columns to display the text "Found" in the appropriate column footer if any properties can be read or written.
Let's start by defining our custom event args in FooterGrid.cs before the definition of the FooterGrid class.
namespace FooterGrid
{
public class FooterValueArgs : EventArgs
{
public string Aggregate
{ get; set; }
public FooterValueArgs(String Aggregate)
{
this.Aggregate = Aggregate;
}
}
public class FooterGrid : DataGrid
public class FooterGrid : DataGrid
{
public delegate String FooterValueEventHandler(object sender, FooterValueArgs args);
public event FooterValueEventHandler
FooterValueEvent;
public String OnFooterValueEvent(FooterValueArgs e)
{
if (FooterValueEvent != null)
return FooterValueEvent(this, e);
else
return "";
}
Now our event is defined we just have to raise it when the column's aggregate starts with CUSTOM. Find CalcFooterItemSource and add a new case. The Column variable simply contains the part of the aggregate between parentheses. ie if the aggregate is "CUSTOM(Age)" then Column contains "Age".
case "CUSTOM":
sResult =
OnFooterValueEvent(new FooterValueArgs(Column));
break;
In MainWindow.xaml we need to tell the footer grid which event handler will process custom aggregates and also create a custom aggregate. Make the following changes...
<cc:FooterGrid AutoGenerateColumns="False" ItemsSource="{Binding PIs}" IsReadOnly="False" HeadersVisibility="Column" ColumnHeaderStyle="{StaticResource Header}" cc:FooterGrid.ColumnFooterStyle="{StaticResource Footer}" FooterValueEvent="FooterGrid_FooterValueEvent">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
<DataGridTextColumn Header="Type" Binding="{Binding Type}" cc:FooterGrid.Aggregate="Total Custom"/>
<DataGridTextColumn Header="Custom Attributes" Binding="{Binding CustomAttributeCount}" cc:FooterGrid.Aggregate="SUM(CustomAttributeCount)">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="HorizontalAlignment" Value="Right"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridCheckBoxColumn Header="CanRead" Binding="{Binding CanRead}" cc:FooterGrid.Aggregate="CUSTOM(CanRead)"/>
<DataGridCheckBoxColumn Header="CanWrite" Binding="{Binding CanWrite}" cc:FooterGrid.Aggregate="CUSTOM(CanWrite)"/>
</DataGrid.Columns>
</cc:FooterGrid>
Finally we have to write FooterGrid_FooterValueEvent in MainWindow.xaml.cs. Just add the following method in the class.
private string
FooterGrid_FooterValueEvent(object sender, FooterGrid.FooterValueArgs args)
{
FooterGrid.FooterGrid fg = sender as FooterGrid.FooterGrid;
switch(args.Aggregate.ToUpper())
{
case "CANREAD":
return (fg.ItemsSource as List<cPI>).Find((pi)
=> pi.CanRead) == null ? "" : "Found";
case "CANWRITE":
return (fg.ItemsSource as List<cPI>).Find((pi)
=> pi.CanWrite) == null ? "" : "Found";
default:
return "";
}
}
Because the entire footer grid is passed as the sender, you can get access to the main grid and footer grid via their template names xMain and xFooter. You can then get to the grids' item sources. The only thing you can't get to is footer values to the right of the footer you are processing because they have not been calculated yet.
The result of our work looks like this.
No comments:
Post a Comment