Skip to content

Commit 500f985

Browse files
committed
Add support for setting content in place of the title in a TitleBar
1 parent ccc2e44 commit 500f985

File tree

3 files changed

+116
-21
lines changed

3 files changed

+116
-21
lines changed

src/Wpf.Ui.Gallery/Views/Windows/SandboxWindow.xaml

+59
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,65 @@
3030
<ui:TitleBar.Icon>
3131
<ui:ImageIcon Source="pack://application:,,,/Assets/wpfui.png" />
3232
</ui:TitleBar.Icon>
33+
<ui:TitleBar.HeaderLeft>
34+
<Menu>
35+
<MenuItem Header="File">
36+
<MenuItem
37+
Header="New" />
38+
<MenuItem
39+
Header="New window" />
40+
<MenuItem
41+
Header="Open..." />
42+
<MenuItem
43+
Header="Save" />
44+
<MenuItem
45+
Header="Save As..." />
46+
<Separator />
47+
<MenuItem
48+
Header="Exit" />
49+
</MenuItem>
50+
<ui:MenuItem Header="Debug">
51+
<MenuItem
52+
Header="Undo" />
53+
<Separator />
54+
<MenuItem
55+
Header="Cut" />
56+
<MenuItem
57+
Header="Copy" />
58+
<MenuItem
59+
Header="Paste" />
60+
<MenuItem
61+
Header="Delete"
62+
IsEnabled="False" />
63+
<Separator />
64+
<MenuItem
65+
Header="Search with browser" />
66+
<MenuItem
67+
Header="Find..." />
68+
<MenuItem
69+
Header="Find next" />
70+
<Separator />
71+
<MenuItem
72+
Header="Select All" />
73+
</ui:MenuItem>
74+
</Menu>
75+
</ui:TitleBar.HeaderLeft>
76+
<ui:TitleBar.HeaderRight>
77+
<Menu>
78+
<ui:MenuItem
79+
Foreground="{DynamicResource PaletteDeepOrangeBrush}"
80+
Icon="{ui:SymbolIcon Fire24, True}" />
81+
<ui:MenuItem
82+
Foreground="{DynamicResource PaletteGreenBrush}"
83+
Icon="{ui:SymbolIcon Play24}" />
84+
<ui:MenuItem
85+
Foreground="{DynamicResource PaletteRedBrush}"
86+
Icon="{ui:SymbolIcon Stop24}" />
87+
<ui:MenuItem
88+
Foreground="{DynamicResource PaletteLightBlueBrush}"
89+
Icon="{ui:SymbolIcon ArrowClockwise24}" />
90+
</Menu>
91+
</ui:TitleBar.HeaderRight>
3392
</ui:TitleBar>
3493

3594
<StackPanel Margin="24">

src/Wpf.Ui/Controls/TitleBar/TitleBar.cs

+46-9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// All Rights Reserved.
55

66
using System.Diagnostics;
7+
using System.Windows.Data;
78
using System.Windows.Input;
89
using Wpf.Ui.Designer;
910
using Wpf.Ui.Extensions;
@@ -60,10 +61,20 @@ public class TitleBar : System.Windows.Controls.Control, IThemeControl
6061
);
6162

6263
/// <summary>
63-
/// Property for <see cref="Header"/>.
64+
/// Property for <see cref="HeaderLeft"/>.
6465
/// </summary>
65-
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
66-
nameof(Header),
66+
public static readonly DependencyProperty HeaderLeftProperty = DependencyProperty.Register(
67+
nameof(HeaderLeft),
68+
typeof(object),
69+
typeof(TitleBar),
70+
new PropertyMetadata(null)
71+
);
72+
73+
/// <summary>
74+
/// Property for <see cref="HeaderRight"/>.
75+
/// </summary>
76+
public static readonly DependencyProperty HeaderRightProperty = DependencyProperty.Register(
77+
nameof(HeaderRight),
6778
typeof(object),
6879
typeof(TitleBar),
6980
new PropertyMetadata(null)
@@ -254,12 +265,21 @@ public string Title
254265
}
255266

256267
/// <summary>
257-
/// Gets or sets the content displayed in the <see cref="TitleBar"/>.
268+
/// Gets or sets the content displayed in the left side of the <see cref="TitleBar"/>.
269+
/// </summary>
270+
public object HeaderLeft
271+
{
272+
get => GetValue(HeaderLeftProperty);
273+
set => SetValue(HeaderLeftProperty, value);
274+
}
275+
276+
/// <summary>
277+
/// Gets or sets the content displayed in right side of the <see cref="TitleBar"/>.
258278
/// </summary>
259-
public object Header
279+
public object HeaderRight
260280
{
261-
get => GetValue(HeaderProperty);
262-
set => SetValue(HeaderProperty, value);
281+
get => GetValue(HeaderRightProperty);
282+
set => SetValue(HeaderRightProperty, value);
263283
}
264284

265285
/// <summary>
@@ -420,6 +440,7 @@ public event TypedEventHandler<TitleBar, RoutedEventArgs> HelpClicked
420440
private System.Windows.Controls.Grid _mainGrid = null!;
421441
private System.Windows.Controls.ContentPresenter _icon = null!;
422442
private readonly TitleBarButton[] _buttons = new TitleBarButton[4];
443+
private readonly TextBlock _titleBlock;
423444

424445
/// <summary>
425446
/// Creates a new instance of the class and sets the default <see cref="FrameworkElement.Loaded"/> event.
@@ -430,6 +451,12 @@ public TitleBar()
430451

431452
dpiScale ??= VisualTreeHelper.GetDpi(this);
432453

454+
_titleBlock = new TextBlock();
455+
_titleBlock.VerticalAlignment = VerticalAlignment.Center;
456+
_titleBlock.SetBinding(System.Windows.Controls.TextBlock.TextProperty, new Binding(nameof(Title)) { Source = this });
457+
_titleBlock.SetBinding(System.Windows.Controls.TextBlock.FontSizeProperty, new Binding(nameof(FontSize)) { Source = this });
458+
HeaderLeft = _titleBlock;
459+
433460
Loaded += OnLoaded;
434461
Unloaded += OnUnloaded;
435462
}
@@ -648,9 +675,19 @@ or User32.WM.NCLBUTTONUP
648675

649676
bool isMouseOverHeaderContent = false;
650677

651-
if (message == User32.WM.NCHITTEST && Header is UIElement headerUiElement)
678+
if (message == User32.WM.NCHITTEST && (HeaderRight is UIElement || HeaderLeft is UIElement))
652679
{
653-
isMouseOverHeaderContent = headerUiElement.IsMouseOverElement(lParam);
680+
UIElement? headerLeftUIElement = HeaderLeft as UIElement;
681+
UIElement? headerRightUiElement = HeaderRight as UIElement;
682+
683+
if (headerLeftUIElement is not null && headerLeftUIElement != _titleBlock)
684+
{
685+
isMouseOverHeaderContent = headerLeftUIElement.IsMouseOverElement(lParam) || (headerRightUiElement?.IsMouseOverElement(lParam) ?? false);
686+
}
687+
else
688+
{
689+
isMouseOverHeaderContent = headerRightUiElement?.IsMouseOverElement(lParam) ?? false;
690+
}
654691
}
655692

656693
switch (message)

src/Wpf.Ui/Controls/TitleBar/TitleBar.xaml

+11-12
Original file line numberDiff line numberDiff line change
@@ -118,42 +118,41 @@
118118
VerticalAlignment="Center">
119119
<Grid.ColumnDefinitions>
120120
<ColumnDefinition Width="Auto" />
121-
<ColumnDefinition Width="Auto" />
122121
</Grid.ColumnDefinitions>
123122

124123
<!-- Custom application icon -->
125124
<ContentPresenter
126125
x:Name="PART_Icon"
127126
Grid.Column="0"
128127
Height="16"
129-
Margin="0,0,12,0"
130128
VerticalAlignment="Center"
131129
Content="{TemplateBinding Icon}"
132130
Focusable="False"
133131
RenderOptions.BitmapScalingMode="HighQuality" />
134-
135-
<!-- Main application title -->
136-
<TextBlock
137-
Grid.Column="1"
138-
VerticalAlignment="Center"
139-
FontSize="{TemplateBinding FontSize}"
140-
Text="{TemplateBinding Title}" />
141132
</Grid>
133+
142134
<Grid Grid.Column="1">
143135
<Grid.ColumnDefinitions>
136+
<ColumnDefinition Width="Auto" />
144137
<ColumnDefinition Width="*" />
145138
<ColumnDefinition Width="Auto" />
146139
</Grid.ColumnDefinitions>
147140

148-
<!-- Additional header content -->
141+
<!-- Title text or other header content -->
149142
<ContentPresenter
150143
Grid.Column="0"
144+
HorizontalAlignment="Left"
145+
Content="{TemplateBinding HeaderLeft}" />
146+
147+
<!-- Additional header content -->
148+
<ContentPresenter
149+
Grid.Column="1"
151150
HorizontalAlignment="Right"
152-
Content="{TemplateBinding Header}" />
151+
Content="{TemplateBinding HeaderRight}" />
153152

154153
<!-- Navigation buttons - Close, Restore, Maximize, Minimize -->
155154
<Grid
156-
Grid.Column="1"
155+
Grid.Column="2"
157156
HorizontalAlignment="Right"
158157
VerticalAlignment="Top">
159158
<Grid.ColumnDefinitions>

0 commit comments

Comments
 (0)