WPF custom control for side layout
I want to create a custom control so that I can do something like this:
<SideBySide>
<StackPanel SideBySide.Left="True">...</StackPanel>
<StackPanel SideBySide.Right="False">...</StackPanel>
</SideBySide>
I'll be using this all over the place, with obviously more options (size, etc.).
I've considered using a Panel subclass, but that doesn't seem right (there is a notion of a selected item between left and right).
So I'm trying to subclass ItemsControl - does anyone now know how to put items in the control template for ItemsControl?
This is a shorthand template for SideBySide:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfCustomControlLibrary1">
<Style TargetType="{x:Type local:SideBySideControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:SideBySideControl}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Rectangle}">
<Setter Property="Margin"
Value="5" />
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0"
VerticalAlignment="Stretch">
<!-- PART_LeftContent goes here -->
</Grid>
<GridSplitter Width="3"
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Stretch"
ShowsPreview="False">
</GridSplitter>
<Grid Grid.Column="2">
<!-- PART_RightContent goes here -->
</Grid>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
source to share
Direct answer: you need ItemsPresenter
in yours ControlTemplate
, which will look something like this:
<ItemsControl x:Class="ItemsControlExample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<Border SnapsToDevicePixels="True">
<!-- Collection items are displayed by the ItemsPresenter. -->
<ItemsPresenter SnapsToDevicePixels="True" />
</Border>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<!-- Replace the default vertical StackPanel with horizontal. -->
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="...">
<!-- The same container style applies to all items so where do you put the splitter? -->
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
But by now it should be obvious what ItemsControl
doesn't fit your use case. However, you can implement it both Control
with the help ControlTemplate
you already have with and grid cells:ContentControl
PART_LeftContent
PART_RightContent
<!-- LeftSideContent is a DependencyProperty of type object -->
<ContentControl x:Name="LeftContentControl" Content="{TemplateBinding LeftSideContent}" />
Then extend your code to handle mouse events ContentControl
to select and add style triggers for the selected look, but these are pretty simple things. Unless you've implemented useless controls, before you should know that you cannot define event callbacks in a template, but instead need to link them to code:
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
ContentControl lc = (ContentControl)base.GetTemplateChild("LeftContentControl"));
// check for null in case the active template doesn't have a 'LeftContentControl' element
if (lc != null)
{
// Use these events to set SelectedItem DependencyProperty and trigger selected item
// highlight style. Don't forget to capture the mouse for proper click behavior.
lc.MouseDown += new MouseButtonEventHandler(LeftSide_MouseDown);
lc.MouseUp += new MouseButtonEventHandler(LeftSide_MouseUp);
}
}
source to share