Skip to content

Commit 018def6

Browse files
committed
wpf: readd shared WPF controls and styles
Readd various WPF shared controls and styles including: - DialogWindow control - PromptTextBox control - WPF converters - Password Prompt control Reintroduce a password text box control, that supports watermarked text when empty. This is the same control as before, except now it uses a plain System.String, rather than a SecureString (which is pointless in practice). wpf: readd shared WPF styles and colours
1 parent ba1f4d7 commit 018def6

File tree

8 files changed

+658
-0
lines changed

8 files changed

+658
-0
lines changed
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:sharedControls="clr-namespace:Microsoft.Git.CredentialManager.UI.Controls">
4+
5+
<Color x:Key="AccentColor">#0078d7</Color>
6+
<Color x:Key="AccentHoverColor">#429ce3</Color>
7+
<Color x:Key="AccentActiveColor">#005a9e</Color>
8+
<Color x:Key="DisabledBackgroundColor">#cccccc</Color>
9+
<Color x:Key="DisabledForegroundColor">#7e7e7e</Color>
10+
<Color x:Key="ControlBorderColor">#666666</Color>
11+
<Color x:Key="PromptTextColor">#989898</Color>
12+
13+
<SolidColorBrush x:Key="AccentBrush" Color="{StaticResource AccentColor}" />
14+
<SolidColorBrush x:Key="AccentHoverBrush" Color="{StaticResource AccentHoverColor}" />
15+
<SolidColorBrush x:Key="AccentActiveBrush" Color="{StaticResource AccentActiveColor}" />
16+
<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="{StaticResource DisabledBackgroundColor}" />
17+
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="{StaticResource DisabledForegroundColor}" />
18+
<SolidColorBrush x:Key="ControlBorderBrush" Color="{StaticResource ControlBorderColor}" />
19+
20+
<SolidColorBrush x:Key="AccentButtonDefaultBackgroundBrush" Color="{StaticResource AccentColor}" />
21+
<SolidColorBrush x:Key="AccentButtonHoverBackgroundBrush" Color="{StaticResource AccentHoverColor}" />
22+
<SolidColorBrush x:Key="AccentButtonPressedBackgroundBrush" Color="{StaticResource AccentActiveColor}" />
23+
<SolidColorBrush x:Key="AccentButtonDisabledBackgroundBrush" Color="{StaticResource DisabledBackgroundColor}" />
24+
<SolidColorBrush x:Key="AccentButtonDisabledForegroundBrush" Color="{StaticResource DisabledForegroundColor}" />
25+
<SolidColorBrush x:Key="PromptTextBrush" Color="{StaticResource PromptTextColor}" />
26+
27+
<Style x:Key="PromptRoundTextBox" TargetType="sharedControls:PromptTextBox">
28+
<Setter Property="FontSize" Value="14"/>
29+
<Setter Property="BorderBrush" Value="{StaticResource ControlBorderBrush}"/>
30+
<Setter Property="Padding" Value="6"/>
31+
<Setter Property="Template">
32+
<Setter.Value>
33+
<ControlTemplate TargetType="sharedControls:PromptTextBox">
34+
<Grid>
35+
<Border x:Name="Bd"
36+
Background="{TemplateBinding Background}"
37+
Margin="1"
38+
CornerRadius="2"
39+
BorderBrush="{TemplateBinding BorderBrush}"
40+
BorderThickness="{TemplateBinding BorderThickness}"/>
41+
42+
<Grid>
43+
<ScrollViewer x:Name="PART_ContentHost"
44+
Padding="{TemplateBinding Padding}"
45+
Focusable="False"
46+
HorizontalScrollBarVisibility="Hidden"
47+
VerticalScrollBarVisibility="Hidden"
48+
VerticalAlignment="Top"
49+
Margin="0"/>
50+
<Label x:Name="PromptLabel"
51+
HorizontalAlignment="Left"
52+
Foreground="{StaticResource PromptTextBrush}"
53+
FontSize="{TemplateBinding FontSize}"
54+
Padding="{TemplateBinding Padding}"
55+
Opacity="0"
56+
Target="{Binding ElementName=Bd}"
57+
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
58+
Focusable="False"
59+
IsHitTestVisible="False"
60+
VerticalAlignment="Top">
61+
<TextBlock Text="{TemplateBinding PromptText}"
62+
Margin="2,0,0,0"
63+
TextTrimming="CharacterEllipsis"/>
64+
</Label>
65+
</Grid>
66+
</Grid>
67+
68+
<ControlTemplate.Triggers>
69+
<Trigger Property="IsEnabled" Value="False">
70+
<Setter Property="Opacity" Value="0.5"/>
71+
</Trigger>
72+
<Trigger Property="IsKeyboardFocusWithin" Value="True">
73+
<Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource AccentBrush}"/>
74+
<Setter Property="BorderThickness" TargetName="Bd" Value="2"/>
75+
<Setter Property="Margin" TargetName="Bd" Value="0"/>
76+
</Trigger>
77+
<DataTrigger Binding="{Binding Text.Length, RelativeSource={RelativeSource Self}}" Value="0">
78+
<Setter Property="Opacity" Value="0.7" TargetName="PromptLabel" />
79+
<Setter Property="Foreground" Value="Transparent" />
80+
</DataTrigger>
81+
</ControlTemplate.Triggers>
82+
</ControlTemplate>
83+
</Setter.Value>
84+
</Setter>
85+
</Style>
86+
87+
<Style TargetType="sharedControls:PromptTextBox" BasedOn="{StaticResource PromptRoundTextBox}"/>
88+
<Style TargetType="sharedControls:PasswordPromptTextBox" BasedOn="{StaticResource PromptRoundTextBox}"/>
89+
90+
<Style x:Key="RoundButton" TargetType="Button">
91+
<Setter Property="FontSize" Value="14"/>
92+
<Setter Property="MinHeight" Value="23"/>
93+
<Setter Property="MinWidth" Value="46"/>
94+
<Setter Property="Template">
95+
<Setter.Value>
96+
<ControlTemplate TargetType="Button">
97+
<Border Background="{TemplateBinding Background}"
98+
CornerRadius="2">
99+
<ContentPresenter Margin="10,6"
100+
HorizontalAlignment="Center"
101+
VerticalAlignment="Center"
102+
RecognizesAccessKey="True"/>
103+
</Border>
104+
</ControlTemplate>
105+
</Setter.Value>
106+
</Setter>
107+
108+
</Style>
109+
<Style x:Key="AccentButton" TargetType="Button" BasedOn="{StaticResource RoundButton}">
110+
<Setter Property="Foreground" Value="White"/>
111+
<Setter Property="Background" Value="{StaticResource AccentButtonDefaultBackgroundBrush}"/>
112+
<Style.Triggers>
113+
<Trigger Property="IsEnabled" Value="False">
114+
<Setter Property="Foreground" Value="{StaticResource AccentButtonDisabledForegroundBrush}"/>
115+
<Setter Property="Background" Value="{StaticResource AccentButtonDisabledBackgroundBrush}"/>
116+
</Trigger>
117+
<Trigger Property="IsMouseOver" Value="True">
118+
<Setter Property="Background" Value="{StaticResource AccentButtonHoverBackgroundBrush}"/>
119+
</Trigger>
120+
<Trigger Property="IsPressed" Value="True">
121+
<Setter Property="Background" Value="{StaticResource AccentButtonPressedBackgroundBrush}"/>
122+
</Trigger>
123+
</Style.Triggers>
124+
</Style>
125+
126+
<Style TargetType="Button" BasedOn="{StaticResource RoundButton}"/>
127+
128+
<Style TargetType="Hyperlink">
129+
<Setter Property="TextDecorations" Value="" />
130+
<Setter Property="Foreground" Value="{StaticResource AccentBrush}"/>
131+
<Style.Triggers>
132+
<Trigger Property="IsMouseOver" Value="True">
133+
<Setter Property="Foreground" Value="{StaticResource AccentHoverBrush}"/>
134+
</Trigger>
135+
<Trigger Property="IsFocused" Value="True">
136+
<Setter Property="Foreground" Value="{StaticResource AccentActiveBrush}"/>
137+
</Trigger>
138+
<Trigger Property="IsEnabled" Value="False">
139+
<Setter Property="Foreground" Value="{StaticResource DisabledBackgroundBrush}"/>
140+
</Trigger>
141+
</Style.Triggers>
142+
</Style>
143+
</ResourceDictionary>
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
<Window x:Class="Microsoft.Git.CredentialManager.UI.Controls.DialogWindow"
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
6+
xmlns:viewModels="clr-namespace:Microsoft.Git.CredentialManager.UI.ViewModels;assembly=Microsoft.Git.CredentialManager.UI"
7+
Width="414"
8+
SizeToContent="Height"
9+
MinHeight="320"
10+
MaxWidth="414"
11+
MaxHeight="520"
12+
Background="{DynamicResource WindowPanelBrush}"
13+
Foreground="{DynamicResource WindowPanelTextBrush}"
14+
FontFamily="Segoe UI"
15+
FontSize="12"
16+
FontStretch="Normal"
17+
FontStyle="Normal"
18+
FontWeight="Normal"
19+
SnapsToDevicePixels="True"
20+
UseLayoutRounding="True"
21+
WindowStartupLocation="CenterOwner"
22+
WindowStyle="None"
23+
WindowState="Normal"
24+
ResizeMode="NoResize"
25+
ShowInTaskbar="true"
26+
d:DataContext="{d:DesignInstance viewModels:WindowViewModel}"
27+
Title="{Binding Title}">
28+
29+
<Window.Resources>
30+
<Color x:Key="WindowPanelColor">#FBFBFB</Color>
31+
<Color x:Key="WindowPanelTextColor">#1E1E1E</Color>
32+
<Color x:Key="WindowBorderColor">#CCCEDB</Color>
33+
<Color x:Key="WindowButtonColor">#FBFBFB</Color>
34+
<Color x:Key="WindowButtonGlyphColor">#332C21</Color>
35+
<Color x:Key="WindowButtonHoverColor">#FCD8A2</Color>
36+
<Color x:Key="WindowButtonHoverGlyphColor">#332C21</Color>
37+
<Color x:Key="WindowButtonHoverBorderColor">#FFFFFF</Color>
38+
<Color x:Key="WindowButtonDownColor">#FCD8A2</Color>
39+
<Color x:Key="WindowButtonDownGlyphColor">#332C21</Color>
40+
<Color x:Key="WindowButtonDownBorderColor">#FFFFFF</Color>
41+
42+
<SolidColorBrush x:Key="WindowPanelBrush" Color="{DynamicResource WindowPanelColor}" />
43+
<SolidColorBrush x:Key="WindowPanelTextBrush" Color="{DynamicResource WindowPanelTextColor}" />
44+
<SolidColorBrush x:Key="WindowBorderBrush" Color="{DynamicResource WindowBorderColor}" />
45+
<SolidColorBrush x:Key="WindowButtonBrush" Color="{DynamicResource WindowButtonColor}" />
46+
<SolidColorBrush x:Key="WindowButtonGlyphBrush" Color="{DynamicResource WindowButtonGlyphColor}" />
47+
<SolidColorBrush x:Key="WindowButtonHoverBrush" Color="{DynamicResource WindowButtonHoverColor}" />
48+
<SolidColorBrush x:Key="WindowButtonHoverGlyphBrush" Color="{DynamicResource WindowButtonHoverGlyphColor}" />
49+
<SolidColorBrush x:Key="WindowButtonHoverBorderBrush" Color="{DynamicResource WindowButtonHoverBorderColor}" />
50+
<SolidColorBrush x:Key="WindowButtonDownBrush" Color="{DynamicResource WindowButtonDownColor}" />
51+
<SolidColorBrush x:Key="WindowButtonDownGlyphBrush" Color="{DynamicResource WindowButtonDownGlyphColor}" />
52+
<SolidColorBrush x:Key="WindowButtonDownBorderBrush" Color="{DynamicResource WindowButtonDownBorderColor}" />
53+
54+
<Style x:Key="WindowCloseButton" TargetType="{x:Type Button}">
55+
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
56+
<Setter Property="Background" Value="{DynamicResource WindowButtonBrush}"/>
57+
<Setter Property="Foreground" Value="{DynamicResource WindowButtonGlyphBrush}"/>
58+
<Setter Property="BorderBrush" Value="Transparent"/>
59+
<Setter Property="BorderThickness" Value="0"/>
60+
<Setter Property="HorizontalContentAlignment" Value="Center"/>
61+
<Setter Property="VerticalContentAlignment" Value="Center"/>
62+
<Setter Property="Width" Value="46" />
63+
<Setter Property="Height" Value="33" />
64+
<Style.Triggers>
65+
<Trigger Property="IsDefaulted" Value="true">
66+
<Setter Property="Background" Value="{DynamicResource WindowButtonBrush}"/>
67+
<Setter Property="Foreground" Value="{DynamicResource WindowButtonGlyphBrush}"/>
68+
</Trigger>
69+
<Trigger Property="IsKeyboardFocused" Value="true">
70+
<Setter Property="Background" Value="{DynamicResource WindowButtonHoverBrush}"/>
71+
<Setter Property="Foreground" Value="{DynamicResource WindowButtonHoverGlyphBrush}"/>
72+
<Setter Property="BorderBrush" Value="{DynamicResource WindowButtonHoverBorderBrush}"/>
73+
</Trigger>
74+
<Trigger Property="IsMouseOver" Value="true">
75+
<Setter Property="Background" Value="{DynamicResource WindowButtonHoverBrush}"/>
76+
<Setter Property="Foreground" Value="{DynamicResource WindowButtonHoverGlyphBrush}"/>
77+
<Setter Property="BorderBrush" Value="{DynamicResource WindowButtonHoverBorderBrush}"/>
78+
</Trigger>
79+
<Trigger Property="IsPressed" Value="true">
80+
<Setter Property="Background" Value="{DynamicResource WindowButtonDownBrush}"/>
81+
<Setter Property="Foreground" Value="{DynamicResource WindowButtonDownGlyphBrush}"/>
82+
<Setter Property="BorderBrush" Value="{DynamicResource WindowButtonDownBorderBrush}"/>
83+
</Trigger>
84+
<Trigger Property="IsFocused" Value="true">
85+
<Setter Property="Background" Value="{DynamicResource WindowButtonHoverBrush}"/>
86+
<Setter Property="Foreground" Value="{DynamicResource WindowButtonHoverGlyphBrush}"/>
87+
<Setter Property="BorderBrush" Value="{DynamicResource WindowButtonHoverBorderBrush}"/>
88+
</Trigger>
89+
</Style.Triggers>
90+
</Style>
91+
</Window.Resources>
92+
93+
<WindowChrome.WindowChrome>
94+
<WindowChrome
95+
CaptionHeight="0"
96+
ResizeBorderThickness="5" />
97+
</WindowChrome.WindowChrome>
98+
99+
<Border MouseDown="Border_MouseDown"
100+
BorderThickness="1"
101+
Background="{DynamicResource WindowPanelBrush}"
102+
BorderBrush="{DynamicResource WindowBorderBrush}">
103+
<DockPanel>
104+
<DockPanel DockPanel.Dock="Top">
105+
<Label Content="{Binding Title}"
106+
Foreground="{DynamicResource WindowPanelTextBrush}"
107+
DockPanel.Dock="Left"
108+
Margin="9,5,0,0" />
109+
<Button Style="{DynamicResource WindowCloseButton}"
110+
DockPanel.Dock="Right"
111+
HorizontalAlignment="Right"
112+
VerticalAlignment="Top"
113+
IsCancel="True"
114+
Click="CloseButton_Click">
115+
<Path
116+
Width="16"
117+
Height="16"
118+
Fill="{Binding Path=(TextElement.Foreground), RelativeSource={RelativeSource Self}}"
119+
Data="F1M8.583,8L13,12.424 12.424,13 8,8.583 3.576,13 3,12.424 7.417,8 3,3.576 3.576,3 8,7.417 12.424,3 13,3.576z"/>
120+
</Button>
121+
122+
</DockPanel>
123+
124+
<ContentControl x:Name="ContentHolder" Margin="30"/>
125+
</DockPanel>
126+
</Border>
127+
</Window>
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System;
2+
using System.Windows;
3+
using System.Windows.Controls;
4+
using System.Windows.Input;
5+
using System.Windows.Threading;
6+
using Microsoft.Git.CredentialManager.UI.ViewModels;
7+
8+
namespace Microsoft.Git.CredentialManager.UI.Controls
9+
{
10+
public partial class DialogWindow : Window
11+
{
12+
private readonly UserControl _view;
13+
14+
public DialogWindow(UserControl view)
15+
{
16+
InitializeComponent();
17+
18+
DataContextChanged += OnDataContextChanged;
19+
20+
_view = view;
21+
ContentHolder.Content = _view;
22+
}
23+
24+
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
25+
{
26+
if (DataContext is WindowViewModel vm)
27+
{
28+
vm.Accepted += (s, _) =>
29+
{
30+
DialogResult = true;
31+
Close();
32+
};
33+
34+
vm.Canceled += (s, _) =>
35+
{
36+
DialogResult = false;
37+
Close();
38+
};
39+
}
40+
41+
if (_view is IFocusable focusable)
42+
{
43+
// Send a focus request to the child view on idle
44+
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (Action)(() => focusable.SetFocus()));
45+
}
46+
}
47+
48+
private void CloseButton_Click(object sender, RoutedEventArgs e)
49+
{
50+
if (DataContext is WindowViewModel vm)
51+
{
52+
vm.Cancel();
53+
}
54+
}
55+
56+
private void Border_MouseDown(object sender, MouseButtonEventArgs e)
57+
{
58+
if (e.ChangedButton == MouseButton.Left)
59+
{
60+
DragMove();
61+
}
62+
}
63+
}
64+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using System;
2+
using System.Text;
3+
using System.Windows;
4+
using System.Windows.Controls;
5+
6+
namespace Microsoft.Git.CredentialManager.UI.Controls
7+
{
8+
public class PasswordPromptTextBox : PromptTextBox
9+
{
10+
public static readonly DependencyProperty PasswordProperty =
11+
DependencyProperty.RegisterAttached(nameof(Password), typeof(string), typeof(PasswordPromptTextBox));
12+
13+
private const char MaskChar = '●';
14+
15+
public string Password
16+
{
17+
get => (string)GetValue(PasswordProperty);
18+
set
19+
{
20+
if (!StringComparer.Ordinal.Equals(Password, value))
21+
{
22+
SetValue(PasswordProperty, value);
23+
UpdateText();
24+
}
25+
}
26+
}
27+
28+
private bool _updatingTextFromPasswordChange;
29+
30+
private void UpdateText()
31+
{
32+
_updatingTextFromPasswordChange = true;
33+
try
34+
{
35+
Text = new string(MaskChar, Password?.Length ?? 0);
36+
}
37+
finally
38+
{
39+
_updatingTextFromPasswordChange = false;
40+
}
41+
}
42+
43+
protected override void OnTextChanged(TextChangedEventArgs e)
44+
{
45+
if (!_updatingTextFromPasswordChange)
46+
{
47+
var password = new StringBuilder(Password);
48+
int selectionStart = SelectionStart;
49+
foreach (TextChange change in e.Changes)
50+
{
51+
password.Remove(change.Offset, change.RemovedLength);
52+
password.Insert(change.Offset, Text.Substring(change.Offset, change.AddedLength));
53+
}
54+
Password = password.ToString();
55+
UpdateText();
56+
SelectionStart = selectionStart;
57+
}
58+
base.OnTextChanged(e);
59+
}
60+
}
61+
}

0 commit comments

Comments
 (0)