I've been trying to get a tooltip to work inside of each row of a datagrid. I was able to displaythe info inside the Tooltipproperty using a simple StackPanel and some labels, but now I wanted to insert a view to use as a tooltip.
I was able to display the ciew and the viewmodel is working, yet I cannot make the custom object to work(named AppointmentConfirmationNotification). I am able to use the empty object 'ToolTipContent' yet I want to bind it to the Datagrid.
here is the code I'm cureently working on. Be aware that I left a comment on my working Stackpanel 'experiment'. Basically I assume somehow I have to inser a mere ´{Binding}´ somewhere... But not sure where.
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Resources>
<model:AppointmentConfirmationNotification x:Key="ToolTipContent">
</model:AppointmentConfirmationNotification>
</Style.Resources>
<Setter Property="ToolTip">
<Setter.Value >
<!--
OLD STACKPANEL WORKING SAMPLE
<StackPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<WrapPanel Grid.Row="0">
<Label>ID : </Label>
<Label Content="{Binding AppointmentConfirmation.AppointmentID}"/>
</WrapPanel>
</Grid>
</StackPanel>
-->
<v:APTooltipView>
<v:APTooltipView.DataContext>
<ObjectDataProvider ObjectType="{x:Type vm:APTooltipViewModel}">
<ObjectDataProvider.ConstructorParameters>
<StaticResource ResourceKey="ToolTipContent"/>
</ObjectDataProvider.ConstructorParameters>
</ObjectDataProvider>
</v:APTooltipView.DataContext>
</v:APTooltipView>
</Setter.Value>
</Setter>
<Setter Property="TextElement.FontWeight" Value="{Binding Path=Read,Converter={StaticResource BooleanToFontweight}}"/>
</Style>
</DataGrid.RowStyle>
I was trying to do this on the XAML in order to follow a more MVVM approach, but feel free to advice another approach. Thank you
You can just make a new view and pass the DataContext through. You could put whatever you like in that view. It would look like this in your main view.
<StackPanel>
<local:"YOUR_VIEW" DataContext="{Binding AppointmentConfirmation, Mode=TwoWay}"/>
</StackPanel>
Your freshly made view will look like this. You can add whatever you like (as long as it exists in your DataContext) and maybe reuse this view for other purposes.
<UserControl x:Name="YOUR_VIEW" ....
...... >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<WrapPanel Grid.Row="0">
<Label>ID : </Label>
<Label Content="{Binding AppointmentID}"/>
</WrapPanel>
</Grid>
</UserControl>
Related
In a WPF project I am creating a wizard comprising of many steps. Each step has its own view. Currently, each view has the same outer XAML elements, like a TextBlock for the title of the step, but different content below that.
So, for example a typical view would look like:
STEP X VIEW
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Step X text goes here"/>
<Grid Grid.Row="1">
<!-- CONTENT OF STEP X GOES HERE -->
</Grid>
</Grid>
What I would like to do is be able to 'factor out' the common outer XAML for each step into another view and just place the content of each step as the content of that new factored out view. That way, I can avoid the repetition of the same outer XAML, and if I decide to change the implementation of each step title, I only have to do it in one place.
I'm sure ContentPresenter is the part of the solution. So, something like:
WRAPPERVIEW:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Step X text goes here"/>
<Grid Grid.Row="1">
<ContentPresenter Content="Content of Step X ??????"/>
</Grid>
</Grid>
My questions are:
1) Is my implementation of WrapperView the right way to go?
2) What is the binding for the ContentPresenter content property in WrapperView?
3) How can I customise the Text of the TextBlock for each step using WrapperView?
4) How can I get the client XAML using WrapperView for the XAML of any step view to look like.
So, using WrapperView for StepXView ,
New STEP X VIEW
<Grid>
<WrapperView TitleText ="Step X Title Text">
<!-- XAML for Step X View -->
</WrapperView>
</Grid>
You had a good intuition about using a ContentPresenter. To me, it looks exactly like you need a HeaderedContentControl, which is a templatable Control which handles both a Header and a Content property.
Although you could directly use HeaderedContentControl, I find it clearer to inherit from it in case you want to customize it further later:
public class WrapperView : HeaderedContentControl { }
And in your XAML, you can template it and use it as you wish:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1">
<Window.Resources>
<Style TargetType="{x:Type local:WrapperView}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:WrapperView">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ContentPresenter HorizontalAlignment="Center" Grid.Row="0" Content="{TemplateBinding Header}"/>
<Grid Grid.Row="1" HorizontalAlignment="Center">
<ContentPresenter Content="{TemplateBinding Content}"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<local:WrapperView Header ="Step X Title Text">
<Rectangle Width="50" Height="50" Fill="Blue"/>
</local:WrapperView>
</Grid>
</Window>
The key here is the use of TemlateBinding which answers your second question.
To make it even cleaner, you could move this Style away from your Window.Resources and set it in Themes\Generics.xaml so that the Style gets applied by default.
I'm currently working on making an application CUIT-Generator ready. That means that, as an example, I'm adding XAML setters to the styles for DataGridRow that set Automation.ID and AutomationName. Works just fine.
Now my issue is that there is a ListView where the ItemTemplate contains a DataTemplate which in turn has a custom UI control.
When recording any action on the text controls inside the custom UI control, it only grabs the custom UI control and the hierarchy below it, but it doesn't record that it is inside a ListView and a ListViewItem.
Due to this, the control can not be found during test execution or when selecting the control in the UIMap and clicking Search UI control.
I tried setting the AutomationID/Name on the ListViewItem and the ListView but that does not have an impact on the recorded hierarchy.
XAML code for the ListView:
<ListView x:Name="sampleControl" Margin="3" ItemsSource="{Binding ObservableCollectionOfViewModelItems}">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="AutomationProperties.Name">
<Setter.Value>
<Binding Path="AutoID"/>
</Setter.Value>
</Setter>
<Setter Property="AutomationProperties.AutomationId">
<Setter.Value>
<Binding Path="AutoID"/>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<SampleNamespace:CustomUIControlView />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Code for the CustomUIControlView:
<UserControl x:Class="SampleNamespace.CustomUIControlView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d">
<Border BorderThickness="3">
<Expander>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<TextBox Grid.Column="1" Grid.Row="0" Name="SampleBox1" Height="20" Margin="5" Text="{Binding SampleProp1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBox Grid.Column="1" Grid.Row="1" Name="SampleBox2" Height="20" Margin="5" Text="{Binding SampleProp2, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBox Grid.Column="1" Grid.Row="2" Name="SampleBox3" Height="20" Margin="5" Text="{Binding SampleProp3, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBox Grid.Column="1" Grid.Row="3" Grid.ColumnSpan="7" Name="SampleBox4" Height="20" Margin="5" Text="{Binding SampleProp4, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</Grid>
</Expander>
</Border>
</UserControl>
The recorded hierarchy for an action recorded on SampleBox1 looks like this:
SampleAppWindow
---- CustomUIControlView
-------- Expander
------------ SampleBox1/TextBox
Obviously none of the controls, aside from the Window are going to be found.
I know that I could transfer the recorded actions to C# code and then edit the hierarchy and search properties myself but I would like to avoid doing this as I would have to remember doing that every time a ListView is involved in a recorded test.
I'm mentioning this as most solutions here on SO or on other websites come down to working around the problem like that.
This is on Visual Studio 2017 15.3.5 and .NET Framework 4.5.2.
I'm fairly certain you are asking for something beyond what the CodedUi Code Generator can handle.
I would point out from the generated object structure it missed entirely the ListView. The route I would recommend is first being sure you can locate the ListView, generated or your own code, probably call DrawHighlight to be sure. I get your trying to avoid your own code for defining object definitions but it is probably only feasible to write your own.
Now specifically for your CustomUIControlView, I would urge you to define a matching CodedUI object that matches it. As is, an Expander with 4 children TextBoxes. This would cut down coding this definition several times. If you look at the generated code as examples to write these.
Depending on your view on designer files, you could also declare the immediately expected parent node of your ListView or itself as a partial class to hook in these unmatched children elements in a separate file to avoid it getting wiped by the generator. Then you would only need to update the designer file with the small partial statement edits.
I have a ListBox that presents a databound list of objects via its ItemSource. Because each object has special display needs I’m defining an ItemTemplateSelector that returns the appropriate DataTemplate depending on the object. That all works without a hitch.
The DataTemplates for each object follow a common formula, but contains custom elements in the middle. For example:
<DataTemplate x:Key="collectibleTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border BorderBrush="LightGray" BorderThickness="1">
<Expander IsExpanded="True" Header="{Binding ComponentName}" Background="WhiteSmoke">
<StackPanel>
<TextBlock Margin="5,5,5,0" Text="{Binding EditDescription}" TextWrapping="Wrap" />
<!-- This is the only custom part of each template -->
<StackPanel Margin="0,10,5,0" Orientation="Horizontal">
<Label Content="Type:" />
<ComboBox Height="22" HorizontalAlignment="Left" SelectedItem="{Binding Path=CollectibleType, Mode=TwoWay}"
ItemsSource="{Binding Source={StaticResource collectibleTypeFromEnum}}" />
</StackPanel>
<!-- End custom part -->
<StackPanel Margin="0,0,0,5">
<Label Content="Available Actions:" >
<Label.Style>
<Style TargetType="Label">
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding EditActions.Count}" Value="0">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
<ItemsControl ItemsSource="{Binding EditActions}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding}" Content="{Binding Title}" ToolTip="{Binding ToolTip}" Margin="5,0,5,0"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</StackPanel>
</Expander>
</Border>
</Grid>
</DataTemplate>
As you can see there’s lots of shared XAML, wrapping a small custom section in the middle.
Additional data templates will be written by other engineers (they’ll want to create one for each new object type that they add), so I’m interested in making the creation of a new DataTemplate as fool-proof and painless as possible. No copying of the entire DataTemplate with the custom “stuff” added in the middle, of course – but I’m also not partial to extracting parts of the template as reusable parts and referencing them in because it still leads to lots of duplicate code in each new DataTemplate, and that means possible errors and hard maintainability. I.e., this right here is a more maintainable approach but still feels suboptimal:
<DataTemplate x:Key="collectibleTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border BorderBrush="LightGray" BorderThickness="1">
<Expander IsExpanded="True" Header="{Binding ComponentName}" Background="WhiteSmoke">
<StackPanel>
<TextBlock Margin="5,5,5,0" Text="{Binding EditDescription}" TextWrapping="Wrap" />
<!-- This is the only custom part of each template -->
[...]
<!-- End custom part -->
<ContentPresenter Content="{StaticResource AvailableActions}" />
</StackPanel>
</Expander>
</Border>
</Grid>
</DataTemplate>
<StackPanel Margin="0,0,0,5" x:Key="AvailableActions" x:Shared="false">
<Label Content="Available Actions:" >
<Label.Style>
<!--
[Bottom half of shared XAML from the first example, offloaded here]
-->
</StackPanel>
So: what is my best strategy to solve this? AFAIK I’m stuck with using DataTemplates because that’s the only element that a ListBox ItemTemplateSelector accepts. Is there a way to create a compound DataTemplate in the DataTemplateSelector? I'd provide the stock DataTemplate that is shared by all objects, and the DataTemplateSelector references in the bit of custom XAML needed for each object type. Other engineers would hook into that generalized code behavior.
Not sure, fumbling a bit in the dark here as whether there is a pattern that allows me to solve this elegantly.
And, just for reference: my current DataTemplateSelector is super straightforward. This is where I would expect to construct the final DataTemplate, rather than simply returning one that's hardcoded in XAML.
public class NodeComponentDataTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
FrameworkElement element = container as FrameworkElement;
if (element != null && item != null)
{
if (item is CollectibleComponent)
return element.FindResource("collectibleTemplate") as DataTemplate;
// [...]
}
}
}
You could create the DataTemplate dynamically using the XamlReader.Parse or XamlReader.Load method, e.g.:
string template = "<DataTemplate xmlns =\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xmlns:x =\"http://schemas.microsoft.com/winfx/2006/xaml\"><StackPanel>[PLACEHOLDER]</StackPanel></DataTemplate>".Replace("[PLACEHOLDER]", "...custom code...");
return System.Windows.Markup.XamlReader.Parse(template) as DataTemplate;
The custom parts could be defined as UserControls.
I am afraid there is no way to base a DataTemplate on another one in pure XAML though.
You could create a new CustomControl that fits your needs. It will apply the style by itself and you can give additional DepdendencyProperties to make it more convinient. In the end you can still put it in a DataTemplate to use it with your DataTemplateSelector.
I'm new to WPF, but have been able make a lot of progress in short time thanks to a good book on the topic, and of course, quality posts on sites like this one. However, now I've come across something I can seem to figure out by those means, so I posting my first question.
I've have a ControlTemplate in a resource dictionary which I apply to several UserControl views. The template provides a simple overlay border and two buttons: Save and Cancel. The templated user control holds various text boxes, etc., and is bound to some ViewModel depending on the context. I'm trying to figure out how to bind the commands to the Save/Cancel buttons when I use/declare the UserControl in some view. Is this is even possible, or am I doing something very wrong?
First, the template:
<ControlTemplate x:Key="OverlayEditorDialog"
TargetType="ContentControl">
<Grid>
<Border HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="DarkGray"
Opacity=".7"/>
<Border HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="DarkGray">
<Grid>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ContentPresenter Grid.Row="0"/>
<Grid Grid.Row="1"
Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Grid.Column="1"
Content="Cancel"
***Command="{Binding CancelCommand}}"**
/>
<Button Grid.Column="0"
Content="Save"
***Command="{Binding Path=SaveCommand}"***/>
</Grid>
</Grid>
</Border>
</Grid>
</ControlTemplate>
The template in turn is used in the CustomerEditorOverlay user control
<UserControl x:Class="GarazhApp.View.CustomerEditorOverlay"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
<UserControl.Resources>
<ResourceDictionary Source="Dictionary1.xaml"/>
</UserControl.Resources>
<ContentControl Template="{StaticResource ResourceKey=OverlayEditorDialog}">
<Grid Grid.Row="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<SomeElement/>
<SomeOtherElement/>
</Grid>
</ContentControl>
...and finally, the user control is used as part of a view like so:
<local:CustomerEditorOverlay Visibility="{Binding Path=CustomerViewModel.ViewMode, Converter={StaticResource myConverter}, FallbackValue=Collapsed}"
d:IsHidden="True" />
So, based on what I've learned from a project I have been on forever and a half, we have a workable pattern.
Let's say you have a bunch of modal windows that all get applied the same style within the application. To have Save and Cancel buttons on each view, the UserControl used for all of the modal windows has several dependency properties. In addition, we specify virtual methods for your commands (e.g. OnSaveCommand, OnCancelCommand, CanExecuteSaveCommand, CanExecuteCancelCommand) and the commands themselves as properties in a base ViewModel that is inherited by your views.
Ultimately, what happens is we create new modal windows by simply doing this:
<my:YourBaseView x:class="MyFirstView" xmlns:whatever="whatever" [...]>
<my:YourBaseView.PrimaryButton>
<Button Content="Save" Command="{Binding SaveCommand}" />
</my:YourBaseView.PrimaryButton>
<!-- some content -->
</my:YourBaseView>
With accompanying code-behind:
public class MyFirstView : YourBaseView
{
[Import] /* using MEF, but you can also do MvvmLight or whatever */
public MyFirstViewModel ViewModel { /* based on datacontext */ }
}
And a ViewModel:
public class MyFirstViewModel : ViewModelBase
{
public override OnSaveCommand(object commandParameter)
{
/* do something on save */
}
}
The template for this UserControl specifies ContentControls in a grid layout with the Content property bound to the PrimaryButton and SecondaryButton. Of course, the content for the modal is stored in the Content property of the UserControl and displayed in a ContentPresenter as well.
<Style TargetType="{x:Type my:YourBaseView}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type my:YourBaseView}">
<Grid>
<!-- ignoring layout stuff -->
<ContentControl Content="{TemplateBinding Content}" />
<ContentControl Content="{TemplateBinding PrimaryButton}" />
<ContentControl Content="{TemplateBinding SecondaryButton}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
UserControl code:
public class YourBaseView : UserControl
{
public static readonly DependencyProperty PrimaryButtonProperty =
DependencyProperty.Register("PrimaryButton", typeof(Button), typeof(YourBaseView), new PropertyMetadata(null));
public Button PrimaryButton
{
get { return (Button)GetValue(PrimaryButtonProperty); }
set { SetValue(PrimaryButtonProperty, value); }
}
/* and so on */
}
You can change the style for each instance of your templated view, of course. We just happen to stick with one base style.
TL;DR edit: I may have gone a bit overboard since I think you just need the understanding that exposing dependency properties of type Button which are set up through the XAML each time you create a new overlay. That, or you could probably RelativeSource your way back up to the visual tree with something like {Binding DataContext.SaveCommand, RelativeSource={RelativeSource AncestorType={x:Type MyView}}} but it's a little dirtier.
Just being new to WPF I"m not sure what control or approach would be best for this requirement, for a WPF application.
I want to present a summary table of information, but the user should be able to decide to view the information based on either: "All Time", Month, Week or Day.
I'd like to visually have the selection of the option appear at the top of this section and have it appear as a TabControl
I'm not sure however whether TabControl is the best choice re repeating the table for each Tab Item
So overall functionally what would work is just radio buttons across the top, however what I want visually is a TabControl look
What would be the best way to achieve the TabControl look but with a programming approach for which I don't have to repeat things in each Tab Item?
For example, would I use a TabControl and then a WPF template to do the equivalent of an include in each Tab Item but with a different input parameter? (haven't used WPF templates before)
Thanks
Since you want the behavior of a group of RadioButtons and you want the visual appearance of a TabItem, you should use RadioButton controls and style them such that they look like TabItem controls. Here is a very simple example:
<Window x:Class="TabTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<Style TargetType="{x:Type RadioButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RadioButton}">
<Border x:Name="tabBorder" BorderThickness="1" BorderBrush="Black"
Margin="0,0,-4,0"
CornerRadius="2,12,0,0"
Background="White"
SnapsToDevicePixels="True">
<ContentPresenter
Margin="12,2,12,2"
VerticalAlignment="Center"
HorizontalAlignment="Left"
RecognizesAccessKey="True"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Panel.ZIndex" Value="100" />
<Setter TargetName="tabBorder" Property="Background" Value="LightBlue" />
<Setter TargetName="tabBorder" Property="BorderThickness" Value="1,1,1,0" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid Margin="4">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,-1" Panel.ZIndex="1">
<RadioButton>All Time</RadioButton>
<RadioButton IsChecked="True">Month</RadioButton>
<RadioButton>Week</RadioButton>
<RadioButton>Day</RadioButton>
</StackPanel>
<Border Grid.Row="1" Background="LightBlue"
BorderThickness="1" BorderBrush="Black"
SnapsToDevicePixels="True">
<Button Margin="10" Grid.Row="1">This is a test</Button>
</Border>
</Grid>
</Window>
In this example, the Button is the place where you would put your summary table.
Greg, I suppose, grouping grid would be the most ideal control of your requirement. Either you can customize the datagrid as explained in the following article. But this would take more time to get things right.
http://blog.smoura.com/wpf-toolkit-datagrid-part-iv-templatecolumns-and-row-grouping/
or else you could make use of commercial WPF Grid grouping control which would match you requirement.
What would be the best way to achieve the TabControl look but with a programming approach for which I don't have to repeat things in each Tab Item?
Use a TabControl. Have each TabItem contain a CollectionViewSource based on the same underlying collection of data, but with a different filter. Use a DataTemplate to present the CollectionViewSource.
Filtering requires some kind of code-behind, but here's a XAML-only demo that does sorting:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase">
<Page.Resources>
<XmlDataProvider x:Key="Data">
<x:XData>
<Data xmlns="">
<Item Date="2010-01-01" Value="January"/>
<Item Date="2010-02-01" Value="February"/>
<Item Date="2010-03-01" Value="March"/>
<Item Date="2010-04-01" Value="April"/>
<Item Date="2010-05-01" Value="May"/>
<Item Date="2010-06-01" Value="June"/>
<Item Date="2010-07-01" Value="July"/>
<Item Date="2010-08-01" Value="August"/>
<Item Date="2010-09-01" Value="September"/>
</Data>
</x:XData>
</XmlDataProvider>
<CollectionViewSource x:Key="ByDate" Source="{Binding Source={StaticResource Data}, XPath=Data/Item}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="#Date"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
<CollectionViewSource x:Key="ByValue" Source="{Binding Source={StaticResource Data}, XPath=Data/Item}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="#Value"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
<DataTemplate DataType="{x:Type CollectionViewSource}">
<Border Margin="5" BorderBrush="DodgerBlue" BorderThickness="1" CornerRadius="4">
<DockPanel Margin="5">
<Label DockPanel.Dock="Top">This is here to show how you can make the layout of your TabItems complex without repeating yourself.</Label>
<ListBox DockPanel.Dock="Top" x:Name="Items" ItemsSource="{Binding}" DisplayMemberPath="#Value" SelectedValuePath="#Value"/>
<DockPanel>
<Label>Selected item: </Label>
<Label Content="{Binding ElementName=Items, Path=SelectedValue}"/>
</DockPanel>
</DockPanel>
</Border>
</DataTemplate>
</Page.Resources>
<Grid>
<TabControl>
<TabItem Header="By date" Content="{StaticResource ByDate}"/>
<TabItem Header="By value" Content="{StaticResource ByValue}"/>
</TabControl>
</Grid>
</Page>