Skip to content

Commit 464a4ae

Browse files
authored
Merge pull request #51 from stutton/features/WindowChrome
Features/window chrome
2 parents a05a630 + ebfada1 commit 464a4ae

8 files changed

Lines changed: 214 additions & 20 deletions

File tree

src/Stutton.DocumentCreator/App.xaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,19 @@
1919
<ResourceDictionary Source="Views/Themes/EditorExpander.xaml" />
2020

2121
</ResourceDictionary.MergedDictionaries>
22+
23+
<Style x:Key="CustomWindowStyle" TargetType="Window">
24+
<Setter Property="WindowChrome.WindowChrome">
25+
<Setter.Value>
26+
<WindowChrome NonClientFrameEdges="None"
27+
GlassFrameThickness="0"
28+
ResizeBorderThickness="3"
29+
CornerRadius="0"
30+
CaptionHeight="48" />
31+
</Setter.Value>
32+
</Setter>
33+
</Style>
34+
2235
</ResourceDictionary>
2336
</Application.Resources>
2437
</Application>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace Stutton.DocumentCreator
8+
{
9+
public interface IWindow
10+
{
11+
bool IsMaximized { get; }
12+
13+
void Close();
14+
void Maximize();
15+
void Restore();
16+
void Minimize();
17+
}
18+
}

src/Stutton.DocumentCreator/MainWindow.xaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
TextOptions.TextFormattingMode="Ideal"
1818
TextOptions.TextRenderingMode="Auto"
1919
Background="{DynamicResource MaterialDesignPaper}"
20-
FontFamily="{StaticResource MaterialDesignFont}">
20+
FontFamily="{StaticResource MaterialDesignFont}"
21+
Style="{StaticResource CustomWindowStyle}">
2122
<Window.Resources>
2223
<ResourceDictionary>
2324
<ResourceDictionary.MergedDictionaries>

src/Stutton.DocumentCreator/MainWindow.xaml.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace Stutton.DocumentCreator
2222
/// <summary>
2323
/// Interaction logic for MainWindow.xaml
2424
/// </summary>
25-
public partial class MainWindow : Window
25+
public partial class MainWindow : Window, IWindow
2626
{
2727
public const string RootDialog = "RootDialog";
2828

@@ -49,13 +49,19 @@ private async void DialogHost_OnLoaded(object sender, RoutedEventArgs e)
4949
#if DEBUG
5050
debugging = true;
5151
#endif
52-
await Setup.DoSetup(MainSnackbar.MessageQueue, debugging);
52+
await Setup.DoSetup(MainSnackbar.MessageQueue, debugging, this);
5353

5454
_shellViewModel = Setup.GetShellViewModel();
5555
ShellView.DataContext = _shellViewModel;
5656

5757
ShellView.EnableNavigation();
5858
await _shellViewModel.LoadAsync();
5959
}
60+
61+
bool IWindow.IsMaximized => WindowState == WindowState.Maximized;
62+
void IWindow.Close() => Close();
63+
void IWindow.Maximize() => WindowState = WindowState.Maximized;
64+
void IWindow.Restore() => WindowState = WindowState.Normal;
65+
void IWindow.Minimize() => WindowState = WindowState.Minimized;
6066
}
6167
}

src/Stutton.DocumentCreator/Setup.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ namespace Stutton.DocumentCreator
3333
public static class Setup
3434
{
3535
private static IUnityContainer _container;
36-
public static async Task DoSetup(ISnackbarMessageQueue messageQueue, bool debugging)
36+
public static async Task DoSetup(ISnackbarMessageQueue messageQueue, bool debugging, IWindow mainWindow)
3737
{
38-
Configure(messageQueue);
38+
Configure(messageQueue, mainWindow);
3939
await LoadInitialSettings();
4040
await InitializeTelemetryService();
4141
await LoadFirstRunTemplates();
@@ -56,9 +56,10 @@ public static void Dispose()
5656
_container.Dispose();
5757
}
5858

59-
private static void Configure(ISnackbarMessageQueue messageQueue)
59+
private static void Configure(ISnackbarMessageQueue messageQueue, IWindow mainWindow)
6060
{
6161
_container = new UnityContainer();
62+
_container.RegisterInstance(mainWindow, new ExternallyControlledLifetimeManager());
6263
_container.RegisterInstance<IContext>(new WpfContext(), new ContainerControlledLifetimeManager());
6364
_container.RegisterType<INavigationService, NavigationService>(new ContainerControlledLifetimeManager());
6465
_container.RegisterType<ISettingsService, SettingsService>(new ContainerControlledLifetimeManager());

src/Stutton.DocumentCreator/Stutton.DocumentCreator.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
<Compile Include="Fields\FieldTemplateMapperProfile.cs" />
108108
<Compile Include="Fields\FieldTemplateModelBase.cs" />
109109
<Compile Include="Fields\FieldTemplateDtoBase.cs" />
110+
<Compile Include="IWindow.cs" />
110111
<Compile Include="Services\Vsts\VstsWorkItemMapperProfile.cs" />
111112
<Compile Include="Shared\IContext.cs" />
112113
<Compile Include="Shared\IExpandable.cs" />

src/Stutton.DocumentCreator/ViewModels/ShellViewModel.cs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,12 @@ namespace Stutton.DocumentCreator.ViewModels
1818
{
1919
public class ShellViewModel : Observable
2020
{
21-
public ShellViewModel(INavigationService navigationService)
21+
private readonly IWindow _mainWindow;
22+
23+
public ShellViewModel(INavigationService navigationService, IWindow mainWindow)
2224
{
2325
Navigator = navigationService ?? throw new ArgumentNullException(nameof(navigationService));
26+
_mainWindow = mainWindow;
2427
}
2528

2629
public INavigationService Navigator { get; }
@@ -41,6 +44,47 @@ public bool IsSideBarShown
4144

4245
private static async Task ShowAbout() => await DialogHost.Show(new AboutDialogViewModel(), MainWindow.RootDialog);
4346

47+
#region Close Command
48+
49+
private ICommand _closeCommand;
50+
public ICommand CloseCommand => _closeCommand ?? (_closeCommand = new RelayCommand(Close));
51+
52+
private void Close()
53+
{
54+
_mainWindow.Close();
55+
}
56+
57+
#endregion
58+
59+
#region ToggleMaxMin Command
60+
61+
private ICommand _toggleMaxMinCommand;
62+
public ICommand ToggleMaxMinCommand => _toggleMaxMinCommand ?? (_toggleMaxMinCommand = new RelayCommand(ToggleMaxMin));
63+
64+
private void ToggleMaxMin()
65+
{
66+
if (_mainWindow.IsMaximized)
67+
{
68+
_mainWindow.Restore();
69+
return;
70+
}
71+
_mainWindow.Maximize();
72+
}
73+
74+
#endregion
75+
76+
#region Minimize Command
77+
78+
private ICommand _MinimizeCommand;
79+
public ICommand MinimizeCommand => _MinimizeCommand ?? (_MinimizeCommand = new RelayCommand(Minimize));
80+
81+
private void Minimize()
82+
{
83+
_mainWindow.Minimize();
84+
}
85+
86+
#endregion
87+
4488
public async Task LoadAsync()
4589
{
4690
await Navigator.NavigateTo(DocumentsPageViewModel.Key);

src/Stutton.DocumentCreator/Views/ShellView.xaml

Lines changed: 123 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@
3333
<Grid>
3434
<DockPanel>
3535
<materialDesign:ColorZone x:Name="TitleColorZone"
36-
Height="64"
37-
Padding="8"
36+
Height="48"
3837
materialDesign:ShadowAssist.ShadowDepth="Depth0"
3938
DockPanel.Dock="Top"
4039
Mode="PrimaryMid">
41-
<DockPanel>
40+
<DockPanel Margin="8,0,0,0">
4241
<Grid>
4342
<ToggleButton Width="32"
43+
WindowChrome.IsHitTestVisibleInChrome="True"
4444
IsChecked="{Binding Navigator.CurrentPage.IsInEditMode, Mode=OneWay}"
4545
Visibility="{Binding Navigator.CurrentPage.IsInEditMode, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}">
4646
<i:Interaction.Triggers>
@@ -62,6 +62,7 @@
6262
<Button VerticalAlignment="Center"
6363
Command="{Binding ToggleMenuCommand}"
6464
DockPanel.Dock="Left"
65+
WindowChrome.IsHitTestVisibleInChrome="True"
6566
Style="{DynamicResource MaterialDesignToolForegroundButton}"
6667
Visibility="{Binding Navigator.CurrentPage.IsInEditMode, Mode=OneWay, Converter={StaticResource InverseBooleanToVisibilityConverter}}">
6768
<materialDesign:PackIcon Width="32"
@@ -72,18 +73,114 @@
7273

7374
</Grid>
7475

75-
<Ellipse Width="32"
76-
Height="32"
77-
DockPanel.Dock="Right"
78-
Visibility="{Binding ProfilePicture, Converter={StaticResource NullToVisibilityConverter}}">
79-
<Ellipse.Fill>
80-
<ImageBrush ImageSource="{Binding ProfilePicture}" Stretch="UniformToFill" />
81-
</Ellipse.Fill>
82-
</Ellipse>
76+
<Button Width="44"
77+
Height="48"
78+
DockPanel.Dock="Right"
79+
WindowChrome.IsHitTestVisibleInChrome="True"
80+
Command="{Binding CloseCommand}">
81+
<materialDesign:PackIcon Kind="Close"
82+
Width="24"
83+
Height="24"/>
84+
<Button.Style>
85+
<Style TargetType="{x:Type Button}">
86+
<Setter Property="Background" Value="Transparent"/>
87+
<Setter Property="Foreground" Value="White" />
88+
<Setter Property="Template">
89+
<Setter.Value>
90+
<ControlTemplate TargetType="{x:Type Button}">
91+
<Border Background="{TemplateBinding Background}">
92+
<ContentPresenter VerticalAlignment="Center"
93+
HorizontalAlignment="Center"/>
94+
</Border>
95+
</ControlTemplate>
96+
</Setter.Value>
97+
</Setter>
98+
<Style.Triggers>
99+
<Trigger Property="IsMouseOver" Value="True">
100+
<Setter Property="Background" Value="#FFE6002B"/>
101+
</Trigger>
102+
<DataTrigger Binding="{Binding Navigator.CurrentPage.IsInEditMode, Mode=OneWay}" Value="True">
103+
<Setter Property="Foreground" Value="{DynamicResource MaterialDesignBody}" />
104+
</DataTrigger>
105+
</Style.Triggers>
106+
</Style>
107+
</Button.Style>
108+
</Button>
109+
110+
<Button Width="44"
111+
Height="48"
112+
DockPanel.Dock="Right"
113+
WindowChrome.IsHitTestVisibleInChrome="True"
114+
Command="{Binding ToggleMaxMinCommand}">
115+
<materialDesign:PackIcon Kind="WindowMaximize"
116+
Width="24"
117+
Height="24"/>
118+
<Button.Style>
119+
<Style TargetType="{x:Type Button}">
120+
<Setter Property="Background" Value="Transparent"/>
121+
<Setter Property="Foreground" Value="White" />
122+
<Setter Property="Template">
123+
<Setter.Value>
124+
<ControlTemplate TargetType="{x:Type Button}">
125+
<Grid>
126+
<Border Background="{TemplateBinding Background}"/>
127+
<ContentPresenter VerticalAlignment="Center"
128+
HorizontalAlignment="Center"/>
129+
</Grid>
130+
</ControlTemplate>
131+
</Setter.Value>
132+
</Setter>
133+
<Style.Triggers>
134+
<Trigger Property="IsMouseOver" Value="True">
135+
<Setter Property="Background" Value="#33000000"/>
136+
</Trigger>
137+
<DataTrigger Binding="{Binding Navigator.CurrentPage.IsInEditMode, Mode=OneWay}" Value="True">
138+
<Setter Property="Foreground" Value="{DynamicResource MaterialDesignBody}" />
139+
</DataTrigger>
140+
</Style.Triggers>
141+
</Style>
142+
</Button.Style>
143+
</Button>
144+
145+
<Button Width="44"
146+
Height="48"
147+
DockPanel.Dock="Right"
148+
WindowChrome.IsHitTestVisibleInChrome="True"
149+
Command="{Binding MinimizeCommand}">
150+
<materialDesign:PackIcon Kind="WindowMinimize"
151+
Width="24"
152+
Height="24"/>
153+
<Button.Style>
154+
<Style TargetType="{x:Type Button}">
155+
<Setter Property="Background" Value="Transparent"/>
156+
<Setter Property="Foreground" Value="White" />
157+
<Setter Property="Template">
158+
<Setter.Value>
159+
<ControlTemplate TargetType="{x:Type Button}">
160+
<Grid>
161+
<Border Background="{TemplateBinding Background}"/>
162+
<ContentPresenter VerticalAlignment="Center"
163+
HorizontalAlignment="Center"/>
164+
</Grid>
165+
</ControlTemplate>
166+
</Setter.Value>
167+
</Setter>
168+
<Style.Triggers>
169+
<Trigger Property="IsMouseOver" Value="True">
170+
<Setter Property="Background" Value="#33000000"/>
171+
</Trigger>
172+
<DataTrigger Binding="{Binding Navigator.CurrentPage.IsInEditMode, Mode=OneWay}" Value="True">
173+
<Setter Property="Foreground" Value="{DynamicResource MaterialDesignBody}" />
174+
</DataTrigger>
175+
</Style.Triggers>
176+
</Style>
177+
</Button.Style>
178+
</Button>
83179

84180
<materialDesign:PopupBox DockPanel.Dock="Right"
85181
PlacementMode="BottomAndAlignRightEdges"
86-
StaysOpen="False">
182+
StaysOpen="False"
183+
WindowChrome.IsHitTestVisibleInChrome="True">
87184
<materialDesign:PopupBox.Style>
88185
<Style BasedOn="{StaticResource {x:Type materialDesign:PopupBox}}" TargetType="{x:Type materialDesign:PopupBox}">
89186
<Style.Triggers>
@@ -99,7 +196,17 @@
99196
</StackPanel>
100197
</materialDesign:PopupBox>
101198

199+
<Ellipse Width="32"
200+
Height="32"
201+
DockPanel.Dock="Right"
202+
Visibility="{Binding ProfilePicture, Converter={StaticResource NullToVisibilityConverter}}">
203+
<Ellipse.Fill>
204+
<ImageBrush ImageSource="{Binding ProfilePicture}" Stretch="UniformToFill" />
205+
</Ellipse.Fill>
206+
</Ellipse>
207+
102208
<Button VerticalAlignment="Center"
209+
WindowChrome.IsHitTestVisibleInChrome="True"
103210
Command="{Binding Navigator.CurrentPage.ToolBar.Refresh.Command}"
104211
DockPanel.Dock="Right"
105212
Style="{DynamicResource MaterialDesignToolForegroundButton}"
@@ -110,6 +217,7 @@
110217
</Button>
111218

112219
<Button VerticalAlignment="Center"
220+
WindowChrome.IsHitTestVisibleInChrome="True"
113221
Command="{Binding Navigator.CurrentPage.ToolBar.Save.Command}"
114222
DockPanel.Dock="Right"
115223
Style="{DynamicResource MaterialDesignToolForegroundButton}"
@@ -122,6 +230,7 @@
122230
</Button>
123231

124232
<Button VerticalAlignment="Center"
233+
WindowChrome.IsHitTestVisibleInChrome="True"
125234
Command="{Binding Navigator.CurrentPage.ToolBar.Export.Command}"
126235
DockPanel.Dock="Right"
127236
Style="{DynamicResource MaterialDesignToolForegroundButton}"
@@ -150,6 +259,7 @@
150259
</TextBlock>
151260

152261
<materialDesign:ColorZone Height="40"
262+
WindowChrome.IsHitTestVisibleInChrome="True"
153263
MaxWidth="400"
154264
Margin="24,0,0,0"
155265
Padding="8,0,8,0"
@@ -159,7 +269,7 @@
159269
materialDesign:ShadowAssist.ShadowDepth="Depth1"
160270
CornerRadius="2"
161271
Mode="Standard"
162-
Visibility="{Binding Navigator.CurrentPage.ToolBar.SearchBar.IsShown, Converter={StaticResource BooleanToVisibilityConverter}}">
272+
Visibility="Collapsed">
163273
<DockPanel>
164274
<Button Command="{Binding Navigator.CurrentPage.ToolBar.SearchBar.Command}"
165275
DockPanel.Dock="Left"

0 commit comments

Comments
 (0)