In this article , I am going to enhance Grid splitter in WPF to show Up/Down or Left/Right button like Lotus notes application.
Step 1) We start with creating a custom control which is derived from Existing GridSplitter control and change its control template to have four buttons as needed in Vertical Template and Horizontal Template.
using System.Diagnostics.CodeAnalysis;
using System.Windows;
using System.Windows.Controls;
namespace Controls
{
[TemplatePart(Name = VerticalLeftButtonElement, Type = typeof (Button))]
[TemplatePart(Name = VerticalRightButtonElement, Type = typeof (Button))]
[TemplatePart(Name = HorizontalUpButtonElement, Type = typeof (Button))]
[TemplatePart(Name = HorizontalDownButtonElement, Type = typeof (Button))]
public class CustomGridSplitter : GridSplitter
{
#region Constants
const string VerticalLeftButtonElement = "VerticalLeftButton";
const string VerticalRightButtonElement = "VerticalRightButton";
const string HorizontalUpButtonElement = "HorizontalUpButton";
const string HorizontalDownButtonElement = "HorizontalDownButton";
const string LowerButtonGridElement = "LowerButtonGrid";
const string UpperButtonGridElement = "UpperButtonGrid";
const string MiddleVerticalButtonElement = "MiddleVerticalButton";
#endregion
#region Private Variables
protected Button HorizontalDownButton;
protected Button HorizontalUpButton;
protected Button VerticalLeftButton;
protected Button VerticalRightButton;
protected Button MiddleVerticalButton;
#endregion
#region Methods
/// <summary>
/// It is called while applying templates.
/// </summary>
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
VerticalLeftButton = GetTemplateChild(VerticalLeftButtonElement) as Button;
if (VerticalLeftButton != null)
{
VerticalLeftButton.Click += OnLeftButtonClickEvent;
}
VerticalRightButton = GetTemplateChild(VerticalRightButtonElement) as Button;
if (VerticalRightButton != null)
{
VerticalRightButton.Click += OnRightButtonClickEvent;
}
HorizontalUpButton = GetTemplateChild(HorizontalUpButtonElement) as Button;
if (HorizontalUpButton != null)
{
HorizontalUpButton.Click += OnUpButtonClickEvent;
}
HorizontalDownButton = GetTemplateChild(HorizontalDownButtonElement) as Button;
if (HorizontalDownButton != null)
{
HorizontalDownButton.Click += OnDownButtonClickEvent;
}
MiddleVerticalButton = GetTemplateChild(MiddleVerticalButtonElement) as Button;
if (MiddleVerticalButton != null)
{
MiddleVerticalButton.Click += OnMiddleButtonClick;
}
}
/// <summary>
/// Its called to set width and hight of buttons.
/// </summary>
/// <param name="availableSize"></param>
/// <returns></returns>
protected override Size MeasureOverride(Size availableSize)
{
VerticalRightButton.Width = 8;
VerticalLeftButton.Width = 8;
HorizontalUpButton.Height = 8;
HorizontalDownButton.Height = 8;
return base.MeasureOverride(availableSize);
}
/// <summary>
/// it invokes left click event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnLeftButtonClickEvent(object sender, RoutedEventArgs e)
{
if (LeftButtonClickEvent != null) LeftButtonClickEvent(sender);
}
/// <summary>
/// it invokes right click event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnRightButtonClickEvent(object sender, RoutedEventArgs e)
{
if (RightButtonClickEvent != null) RightButtonClickEvent(sender);
}
/// <summary>
/// it invokes up click event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnUpButtonClickEvent(object sender, RoutedEventArgs e)
{
if (UpButtonClickEvent != null) UpButtonClickEvent(sender);
}
/// <summary>
/// it invokes middle button click event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnMiddleButtonClick(object sender, RoutedEventArgs e)
{
if (MiddleButtonClickEvent != null) MiddleButtonClickEvent(sender);
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnDownButtonClickEvent(object sender, RoutedEventArgs e)
{
if (DownButtonClickEvent != null) DownButtonClickEvent(sender);
}
#endregion
#region Properties
#region Delegates
public delegate void ButtonClickEventHandler(object sender);
#endregion
#region Events
public event ButtonClickEventHandler LeftButtonClickEvent;
public event ButtonClickEventHandler RightButtonClickEvent;
public event ButtonClickEventHandler UpButtonClickEvent;
public event ButtonClickEventHandler DownButtonClickEvent;
public event ButtonClickEventHandler MiddleButtonClickEvent;
#endregion
#region UseHorizontally
/// <summary>
/// UseHorizontally Dependency Property
/// </summary>
public static readonly DependencyProperty UseHorizontallyProperty =
DependencyProperty.Register("UseHorizontally", typeof (bool), typeof (ExtendedGridSplitter),
new FrameworkPropertyMetadata(false));
/// <summary>
/// Gets or sets the UseHorizontally property. This dependency property
/// indicates ....
/// </summary>
public bool UseHorizontally
{
get { return (bool) GetValue(UseHorizontallyProperty); }
set { SetValue(UseHorizontallyProperty, value); }
}
#endregion
#endregion
#region Static Constructor
/// <summary>
/// its a default static contructor.
/// </summary>
static ExtendedGridSplitter()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof (ExtendedGridSplitter),
new FrameworkPropertyMetadata(typeof (ExtendedGridSplitter)));
}
#endregion
}
}
Step 3) You add this Control in your window as shown below
<Grid Grid.Row="1" x:Name="ContainerGrid" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="0.5*" />
</Grid.ColumnDefinitions>
<TabControl Grid.Column="0" />
<controls:ExtendedGridSplitter Grid.Column="1" MouseDoubleClick="GridSplitter_MouseDoubleClick" x:Name="GridSplitter" Margin="0,5" ShowsPreview="True" Background="Transparent" DragCompleted="GridSplitter_DragCompleted" Width="10" LeftButtonClickEvent="GridSplitter_LeftButtonClickEvent" MiddleButtonClickEvent="GridSplitter_MiddleButtonClickEvent" RightButtonClickEvent="GridSplitter_RightButtonClickEvent" HorizontalAlignment="Center" VerticalAlignment="Stretch" > </controls:ExtendedGridSplitter>
<TabControl Grid.Column="2" Background="Transparent"Name="Right" />
</Grid>
Step 4) Put code for GridSplitter_LeftButtonClickEvent and GridSplitter_RightButtonClickEvent to change width of left and right portion as indicated below.
Step 1) We start with creating a custom control which is derived from Existing GridSplitter control and change its control template to have four buttons as needed in Vertical Template and Horizontal Template.
using System.Diagnostics.CodeAnalysis;
using System.Windows;
using System.Windows.Controls;
namespace Controls
{
[TemplatePart(Name = VerticalLeftButtonElement, Type = typeof (Button))]
[TemplatePart(Name = VerticalRightButtonElement, Type = typeof (Button))]
[TemplatePart(Name = HorizontalUpButtonElement, Type = typeof (Button))]
[TemplatePart(Name = HorizontalDownButtonElement, Type = typeof (Button))]
public class CustomGridSplitter : GridSplitter
{
#region Constants
const string VerticalLeftButtonElement = "VerticalLeftButton";
const string VerticalRightButtonElement = "VerticalRightButton";
const string HorizontalUpButtonElement = "HorizontalUpButton";
const string HorizontalDownButtonElement = "HorizontalDownButton";
const string LowerButtonGridElement = "LowerButtonGrid";
const string UpperButtonGridElement = "UpperButtonGrid";
const string MiddleVerticalButtonElement = "MiddleVerticalButton";
#endregion
#region Private Variables
protected Button HorizontalDownButton;
protected Button HorizontalUpButton;
protected Button VerticalLeftButton;
protected Button VerticalRightButton;
protected Button MiddleVerticalButton;
#endregion
#region Methods
/// <summary>
/// It is called while applying templates.
/// </summary>
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
VerticalLeftButton = GetTemplateChild(VerticalLeftButtonElement) as Button;
if (VerticalLeftButton != null)
{
VerticalLeftButton.Click += OnLeftButtonClickEvent;
}
VerticalRightButton = GetTemplateChild(VerticalRightButtonElement) as Button;
if (VerticalRightButton != null)
{
VerticalRightButton.Click += OnRightButtonClickEvent;
}
HorizontalUpButton = GetTemplateChild(HorizontalUpButtonElement) as Button;
if (HorizontalUpButton != null)
{
HorizontalUpButton.Click += OnUpButtonClickEvent;
}
HorizontalDownButton = GetTemplateChild(HorizontalDownButtonElement) as Button;
if (HorizontalDownButton != null)
{
HorizontalDownButton.Click += OnDownButtonClickEvent;
}
MiddleVerticalButton = GetTemplateChild(MiddleVerticalButtonElement) as Button;
if (MiddleVerticalButton != null)
{
MiddleVerticalButton.Click += OnMiddleButtonClick;
}
}
/// <summary>
/// Its called to set width and hight of buttons.
/// </summary>
/// <param name="availableSize"></param>
/// <returns></returns>
protected override Size MeasureOverride(Size availableSize)
{
VerticalRightButton.Width = 8;
VerticalLeftButton.Width = 8;
HorizontalUpButton.Height = 8;
HorizontalDownButton.Height = 8;
return base.MeasureOverride(availableSize);
}
/// <summary>
/// it invokes left click event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnLeftButtonClickEvent(object sender, RoutedEventArgs e)
{
if (LeftButtonClickEvent != null) LeftButtonClickEvent(sender);
}
/// <summary>
/// it invokes right click event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnRightButtonClickEvent(object sender, RoutedEventArgs e)
{
if (RightButtonClickEvent != null) RightButtonClickEvent(sender);
}
/// <summary>
/// it invokes up click event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnUpButtonClickEvent(object sender, RoutedEventArgs e)
{
if (UpButtonClickEvent != null) UpButtonClickEvent(sender);
}
/// <summary>
/// it invokes middle button click event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnMiddleButtonClick(object sender, RoutedEventArgs e)
{
if (MiddleButtonClickEvent != null) MiddleButtonClickEvent(sender);
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnDownButtonClickEvent(object sender, RoutedEventArgs e)
{
if (DownButtonClickEvent != null) DownButtonClickEvent(sender);
}
#endregion
#region Properties
#region Delegates
public delegate void ButtonClickEventHandler(object sender);
#endregion
#region Events
public event ButtonClickEventHandler LeftButtonClickEvent;
public event ButtonClickEventHandler RightButtonClickEvent;
public event ButtonClickEventHandler UpButtonClickEvent;
public event ButtonClickEventHandler DownButtonClickEvent;
public event ButtonClickEventHandler MiddleButtonClickEvent;
#endregion
#region UseHorizontally
/// <summary>
/// UseHorizontally Dependency Property
/// </summary>
public static readonly DependencyProperty UseHorizontallyProperty =
DependencyProperty.Register("UseHorizontally", typeof (bool), typeof (ExtendedGridSplitter),
new FrameworkPropertyMetadata(false));
/// <summary>
/// Gets or sets the UseHorizontally property. This dependency property
/// indicates ....
/// </summary>
public bool UseHorizontally
{
get { return (bool) GetValue(UseHorizontallyProperty); }
set { SetValue(UseHorizontallyProperty, value); }
}
#endregion
#endregion
#region Static Constructor
/// <summary>
/// its a default static contructor.
/// </summary>
static ExtendedGridSplitter()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof (ExtendedGridSplitter),
new FrameworkPropertyMetadata(typeof (ExtendedGridSplitter)));
}
#endregion
}
}
2) You define control template for this control as
<Style TargetType="{x:Type controls:CustomGridSplitter}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="IsTabStop" Value="true"/>
<Setter Property="Width" Value="15"/>
<Setter Property="PreviewStyle" Value="{StaticResource GridSplitterPreviewStyle}"/>
<Setter Property="HorizontalAlignment" Value="Right"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:CustomGridSplitter">
<Grid x:Name="Root" IsHitTestVisible="{TemplateBinding IsEnabled}">
<!-- VSM -->
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver" />
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity" To="0.5" Duration="0" />
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0" />
</VisualStateGroup.Transitions>
<VisualState x:Name="Unfocused" />
<VisualState x:Name="Focused">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="FocusVisual" Storyboard.TargetProperty="Opacity" To="1" Duration="0" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<!-- Background -->
<Border CornerRadius="1" BorderBrush="#8CACDB" BorderThickness="1,1,2,1" >
<Border CornerRadius="1" BorderThickness="0,0,1,0" BorderBrush="DarkBlue" />
</Border>
<!-- Horizontal Template -->
<Grid x:Name="HorizontalTemplate"
Visibility="{Binding UseHorizontally, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type controls:ExtendedGridSplitter}},Converter={StaticResource BoolToVisibilityConverter}}"
HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel Orientation="Horizontal" >
<Button Style="{StaticResource SplitterButtonStyle}" Content="5" x:Name="HorizontalUpButton"
Width="Auto"/>
<Button Style="{StaticResource SplitterButtonStyle}" Content="6" x:Name="HorizontalDownButton"
Width="Auto"/>
</StackPanel>
</Grid>
<!-- Vertical Template -->
<Grid x:Name="VerticalTemplate" HorizontalAlignment="Center"
Visibility="{Binding UseHorizontally,
RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type controls:ExtendedGridSplitter}},
Converter={StaticResource NotBoolToVisibilityConverter}}"
VerticalAlignment="Stretch" >
<Grid.RowDefinitions>
<RowDefinition Height="0.3*"/>
<RowDefinition Height="0.3*"/>
<RowDefinition Height="0.3*"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" ToolTip="Expand Right" Style="{StaticResource SplitterButtonStyle}" VerticalContentAlignment="Bottom" Content="3" x:Name="VerticalLeftButton"
Height="Auto"/>
<Button Grid.Row="2" ToolTip="Expand Left" Style="{StaticResource SplitterButtonStyle}" VerticalContentAlignment="Top" Content="4" x:Name="VerticalRightButton"
Height="Auto"/>
<Button Grid.Row="1" ToolTip="Restore Center" Style="{StaticResource SplitterButtonStyle}" VerticalContentAlignment="Center" x:Name="MiddleVerticalButton"
Height="Auto"/>
</Grid>
<!-- Focus Visual -->
<Rectangle x:Name="FocusVisual" Stroke="#FF45D6FA" StrokeThickness="1" Opacity="0" IsHitTestVisible="false" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Step 3) You add this Control in your window as shown below
<Grid Grid.Row="1" x:Name="ContainerGrid" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="0.5*" />
</Grid.ColumnDefinitions>
<TabControl Grid.Column="0" />
<controls:ExtendedGridSplitter Grid.Column="1" MouseDoubleClick="GridSplitter_MouseDoubleClick" x:Name="GridSplitter" Margin="0,5" ShowsPreview="True" Background="Transparent" DragCompleted="GridSplitter_DragCompleted" Width="10" LeftButtonClickEvent="GridSplitter_LeftButtonClickEvent" MiddleButtonClickEvent="GridSplitter_MiddleButtonClickEvent" RightButtonClickEvent="GridSplitter_RightButtonClickEvent" HorizontalAlignment="Center" VerticalAlignment="Stretch" > </controls:ExtendedGridSplitter>
<TabControl Grid.Column="2" Background="Transparent"Name="Right" />
</Grid>
Step 4) Put code for GridSplitter_LeftButtonClickEvent and GridSplitter_RightButtonClickEvent to change width of left and right portion as indicated below.
private void GridSplitter_LeftButtonClickEvent(object sender) { SetLeftScreenWidth(); }
private void GridSplitter_RightButtonClickEvent(object sender) { SetRightScreenWidth(); }In SetLeftScreenWidth method you will increase size for left side and in
SetRightScreenWidth method you will increase size for right section.
Hi,
ReplyDeleteI was reading your article and I would like to appreciate you for making it very simple and understandable. This article gives me a basic idea of GridSplitter control in WPF. Some good articles also I was found during searching time which also explained very well about WPF GridSplitter Control, that post url are...
http://msdn.microsoft.com/en-us/library/system.windows.controls.gridsplitter.aspx
and
http://www.mindstick.com/Articles/6c64bf8a-6704-4bd7-90ab-524689c390e5/?GridSpliter%20control%20in%20WPF