WPF pivoted table (vertical columns)

Source code: download

I struggled some time to find a way to create a pivoted table where the columns are shown vertical instead of horizontal.
This is a dynamic table where databinding is used to retrieve the data and by clicking the columns they also needed to be sorted.
Sorting is not included in this sample, but this is easily accomplished by adding a command to the columns (buttons).
With some googling I came accross the dependency property named "SharedSizeGroup" and that did the trick.

image 

First you create your DataTemplate with the rowdefinitions where every row has its own SharedSizeGroup.
Then you define the controltemplate for the listbox that is databound to the data.
This template also contains the same amount of rows and all rows that need to line up share the same SharedSizeGroup as defined in the DataTemplate.
If someone has a better solution, I am eager to learn!! Drop me a line.

<Window x:Class="VerticalGridColumns.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:data="clr-namespace:VerticalGridColumns" Title="Pivoted Grid" Height="300" Width="300"> <Window.Resources> <ObjectDataProvider x:Key="PersonsProvider" ObjectType="{x:Type data:Persons}" /> <ControlTemplate x:Key="HeaderButtonTemplate" TargetType="{x:Type Button}"> <Border Width="auto" Height="auto" BorderThickness="1" BorderBrush="Gray" Padding="10,3,10,3" Background="Gainsboro"> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="True"/> </Border> </ControlTemplate> <DataTemplate x:Key="MyDataTemplate"> <Border BorderThickness="1" BorderBrush="Gray"> <Grid ShowGridLines="True"> <Grid.RowDefinitions> <RowDefinition Height="auto" SharedSizeGroup="NameRow" /> <RowDefinition Height="auto" SharedSizeGroup="AgeRow" /> <RowDefinition Height="auto" SharedSizeGroup="GenderRow" /> </Grid.RowDefinitions> <TextBlock Grid.Row="0" VerticalAlignment="Center" Padding="3,0,3,0" Text="{Binding Path=Name}" /> <TextBlock Grid.Row="1" VerticalAlignment="Center" Padding="3,0,3,0" Text="{Binding Path=Age}" /> <TextBlock Grid.Row="2" VerticalAlignment="Center" Padding="3,0,3,0" Text="{Binding Path=Gender}" /> </Grid> </Border> </DataTemplate> <ControlTemplate x:Key="MyListBoxTemplate"> <Grid Grid.IsSharedSizeScope="True"> <DockPanel> <Border BorderThickness="1"> <Grid DockPanel.Dock="Left"> <Grid.RowDefinitions> <RowDefinition Height="auto" SharedSizeGroup="NameRow" /> <RowDefinition Height="auto" SharedSizeGroup="AgeRow" /> <RowDefinition Height="auto" SharedSizeGroup="GenderRow" /> </Grid.RowDefinitions> <Button Template="{StaticResource HeaderButtonTemplate}" Grid.Row="0">Name</Button> <Button Template="{StaticResource HeaderButtonTemplate}" Grid.Row="1" Content="Age" /> <Button Template="{StaticResource HeaderButtonTemplate}" Grid.Row="2" Content="Gender"/> </Grid> </Border> <VirtualizingStackPanel IsItemsHost="True" Orientation="Horizontal" /> </DockPanel> </Grid> </ControlTemplate> </Window.Resources> <Grid> <StackPanel Margin="10,10,10,10"> <TextBlock Text="This is an example of a pivoted grid" Margin="0,10, 0, 10" /> <ListBox x:Name="MyListBox" Height="auto" ItemTemplate="{StaticResource MyDataTemplate}" Template="{StaticResource MyListBoxTemplate}" ItemsSource="{Binding Source={StaticResource PersonsProvider}}" VerticalAlignment="Top" /> </StackPanel> </Grid> </Window>

WPF implementation of a basic Accordion control

Source: WPF Accordion Control Source

WPF does not contain an out of the box accordion control, but it does provide an expander control.
Since an accordion control is nothing more than a stack of expanders it is very easy to build one ourselves.
This shows just a basic control, Feel free to pimp the control with a custom template or extend it with your functionality.

image_thumb

First create a WPF Custom control library.
Then add a "Custom Control (WPF)" item to the project and name it "Accordion.cs"
Add the following code into this file:

Note: As you can see, the Accordion control is just a custom stackpanel with functionality to expand/collapse the expanders within the stackpanel.

namespace WpfDemoControlLibrary { public class Accordion : StackPanel { static Accordion() { DefaultStyleKeyProperty.OverrideMetadata(typeof(Accordion), new FrameworkPropertyMetadata(typeof(Accordion))); } protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); this.InitializeAccordion(); } protected void InitializeAccordion() { Expander selectedExpander; foreach (UIElement element in this.Children) { selectedExpander = element as Expander; if (selectedExpander != null) { selectedExpander.Expanded += new RoutedEventHandler(selectedExpander_Expanded); } } } void selectedExpander_Expanded(object sender, RoutedEventArgs e) { Expander selectedExpander = sender as Expander; Expander otherExpander = null; ContentPresenter contentPresenter = null; double totalExpanderHeight = 0; if (selectedExpander != null) { foreach (UIElement element in this.Children) { otherExpander = element as Expander; if (otherExpander != null & otherExpander != selectedExpander) { if (otherExpander.IsExpanded) { contentPresenter = otherExpander.Template.FindName("ExpandSite", otherExpander) as ContentPresenter; if(contentPresenter != null) totalExpanderHeight -= contentPresenter.ActualHeight; } otherExpander.IsExpanded = false; totalExpanderHeight += otherExpander.ActualHeight; } } if (selectedExpander.IsExpanded) { contentPresenter = selectedExpander.Template.FindName("ExpandSite", selectedExpander) as ContentPresenter; if(contentPresenter != null) contentPresenter.Height = this.ActualHeight - totalExpanderHeight - selectedExpander.ActualHeight; } } } } }

When the prior file was created it added a section to the Theme\General.xaml file.
Make sure it reflects the following line:
<Style TargetType="{x:Type local:Accordion}"></Style>

By adding the following line to the "Properties\AssemblyInfo.cs" file, the control can later be referenced by your personal namespace.

[assembly: XmlnsDefinition("http://schemas.rooijakkers.net/presentation", "WpfDemoControlLibrary")]

Now, Create a test WPF application that references the created control library.
Note: Make sure that you add the previously defined namespace to the top of the window.

image_thumb[5]

That's it.