Skip to content

Commit 67b17d7

Browse files
committed
Update SmartHint styles to better match the material design specification
1 parent a7ae250 commit 67b17d7

9 files changed

+107
-35
lines changed

MaterialDesignThemes.Wpf/HintProxyFabric.ComboBox.cs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public ComboBoxHintProxy(ComboBox comboBox)
2626
_comboBox.SelectionChanged += ComboBoxSelectionChanged;
2727
_comboBox.Loaded += ComboBoxLoaded;
2828
_comboBox.IsVisibleChanged += ComboBoxIsVisibleChanged;
29+
_comboBox.IsKeyboardFocusWithinChanged += ComboBoxIsKeyboardFocusWithinChanged;
2930
}
3031

3132
public object Content
@@ -48,16 +49,16 @@ public object Content
4849

4950
public bool IsVisible => _comboBox.IsVisible;
5051

51-
public bool IsEmpty()
52-
{
53-
return string.IsNullOrEmpty(_comboBox.Text);
54-
}
52+
public bool IsEmpty() => string.IsNullOrEmpty(_comboBox.Text);
53+
54+
public bool IsFocused() => _comboBox.IsEditable && _comboBox.IsKeyboardFocusWithin;
5555

5656
public event EventHandler ContentChanged;
5757

5858
public event EventHandler IsVisibleChanged;
5959

6060
public event EventHandler Loaded;
61+
public event EventHandler FocusedChanged;
6162

6263
private void ComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
6364
{
@@ -79,12 +80,18 @@ private void ComboBoxTextChanged(object sender, TextChangedEventArgs e)
7980
ContentChanged?.Invoke(sender, EventArgs.Empty);
8081
}
8182

83+
private void ComboBoxIsKeyboardFocusWithinChanged(object sender, DependencyPropertyChangedEventArgs e)
84+
{
85+
FocusedChanged?.Invoke(sender, EventArgs.Empty);
86+
}
87+
8288
public void Dispose()
8389
{
8490
_comboBox.RemoveHandler(TextBoxBase.TextChangedEvent, _comboBoxTextChangedEventHandler);
8591
_comboBox.Loaded -= ComboBoxLoaded;
8692
_comboBox.IsVisibleChanged -= ComboBoxIsVisibleChanged;
87-
_comboBox.SelectionChanged -= ComboBoxSelectionChanged;
93+
_comboBox.SelectionChanged -= ComboBoxSelectionChanged;
94+
_comboBox.IsKeyboardFocusWithinChanged -= ComboBoxIsKeyboardFocusWithinChanged;
8895
}
8996
}
9097
}

MaterialDesignThemes.Wpf/HintProxyFabric.PasswordBox.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@ private sealed class PasswordBoxHintProxy : IHintProxy
1717

1818
public bool IsVisible => _passwordBox.IsVisible;
1919

20+
public bool IsFocused() => _passwordBox.IsKeyboardFocused;
21+
2022
public event EventHandler ContentChanged;
2123
public event EventHandler IsVisibleChanged;
2224
public event EventHandler Loaded;
25+
public event EventHandler FocusedChanged;
2326

2427
public PasswordBoxHintProxy(PasswordBox passwordBox)
2528
{
@@ -29,6 +32,12 @@ public PasswordBoxHintProxy(PasswordBox passwordBox)
2932
_passwordBox.PasswordChanged += PasswordBoxPasswordChanged;
3033
_passwordBox.Loaded += PasswordBoxLoaded;
3134
_passwordBox.IsVisibleChanged += PasswordBoxIsVisibleChanged;
35+
_passwordBox.IsKeyboardFocusedChanged += PasswordBoxIsKeyboardFocusedChanged;
36+
}
37+
38+
private void PasswordBoxIsKeyboardFocusedChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e)
39+
{
40+
FocusedChanged?.Invoke(this, EventArgs.Empty);
3241
}
3342

3443
private void PasswordBoxIsVisibleChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e)
@@ -51,6 +60,7 @@ public void Dispose()
5160
_passwordBox.PasswordChanged -= PasswordBoxPasswordChanged;
5261
_passwordBox.Loaded -= PasswordBoxLoaded;
5362
_passwordBox.IsVisibleChanged -= PasswordBoxIsVisibleChanged;
63+
_passwordBox.IsKeyboardFocusedChanged -= PasswordBoxIsKeyboardFocusedChanged;
5464
}
5565

5666
}

MaterialDesignThemes.Wpf/HintProxyFabric.TextBox.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,12 @@ private sealed class TextBoxHintProxy : IHintProxy
1818

1919
public bool IsEmpty() => string.IsNullOrEmpty(_textBox.Text);
2020

21+
public bool IsFocused() => _textBox.IsKeyboardFocused;
22+
2123
public event EventHandler ContentChanged;
2224
public event EventHandler IsVisibleChanged;
2325
public event EventHandler Loaded;
26+
public event EventHandler FocusedChanged;
2427

2528
public TextBoxHintProxy(TextBox textBox)
2629
{
@@ -30,6 +33,12 @@ public TextBoxHintProxy(TextBox textBox)
3033
_textBox.TextChanged += TextBoxTextChanged;
3134
_textBox.Loaded += TextBoxLoaded;
3235
_textBox.IsVisibleChanged += TextBoxIsVisibleChanged;
36+
_textBox.IsKeyboardFocusedChanged += TextBoxIsKeyboardFocusedChanged;
37+
}
38+
39+
private void TextBoxIsKeyboardFocusedChanged(object sender, DependencyPropertyChangedEventArgs e)
40+
{
41+
FocusedChanged?.Invoke(sender, EventArgs.Empty);
3342
}
3443

3544
private void TextBoxIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
@@ -52,6 +61,7 @@ public void Dispose()
5261
_textBox.TextChanged -= TextBoxTextChanged;
5362
_textBox.Loaded -= TextBoxLoaded;
5463
_textBox.IsVisibleChanged -= TextBoxIsVisibleChanged;
64+
_textBox.IsKeyboardFocusedChanged -= TextBoxIsKeyboardFocusedChanged;
5565
}
5666
}
5767
}

MaterialDesignThemes.Wpf/IHintProxy.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ public interface IHintProxy : IDisposable
2121
/// <returns></returns>
2222
bool IsEmpty();
2323

24+
/// <summary>
25+
/// Targeted control has keyboard focus
26+
/// </summary>
27+
/// <returns></returns>
28+
bool IsFocused();
29+
2430
[Obsolete]
2531
object Content { get; }
2632

@@ -33,5 +39,7 @@ public interface IHintProxy : IDisposable
3339
event EventHandler IsVisibleChanged;
3440

3541
event EventHandler Loaded;
42+
43+
event EventHandler FocusedChanged;
3644
}
3745
}

MaterialDesignThemes.Wpf/SmartHint.cs

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using System.Threading.Tasks;
77
using System.Windows;
88
using System.Windows.Controls;
9-
using System.Windows.Media.Animation;
109
using MaterialDesignThemes.Wpf.Converters;
1110

1211
namespace MaterialDesignThemes.Wpf
@@ -17,15 +16,13 @@ namespace MaterialDesignThemes.Wpf
1716
/// <para/>
1817
/// To set a target control you should set the HintProxy property. Use the <see cref="HintProxyFabricConverter.Instance"/> converter which converts a control into the IHintProxy interface.
1918
/// </summary>
20-
[TemplateVisualState(GroupName = ContentStatesGroupName, Name = ContentEmptyName)]
21-
[TemplateVisualState(GroupName = ContentStatesGroupName, Name = ContentNotEmptyName)]
19+
[TemplateVisualState(GroupName = ContentStatesGroupName, Name = HintRestingPositionName)]
20+
[TemplateVisualState(GroupName = ContentStatesGroupName, Name = HintFloatingPositionName)]
2221
public class SmartHint : Control
2322
{
2423
public const string ContentStatesGroupName = "ContentStates";
25-
public const string ContentEmptyName = "ContentEmpty";
26-
public const string ContentNotEmptyName = "ContentNotEmpty";
27-
28-
private ContentControl _floatingHintPart = null;
24+
public const string HintRestingPositionName = "HintRestingPosition";
25+
public const string HintFloatingPositionName = "HintFloatingPosition";
2926

3027
#region ManagedProperty
3128

@@ -71,6 +68,24 @@ public bool IsContentNullOrEmpty
7168

7269
#endregion
7370

71+
#region IsHintInFloatingPosition
72+
73+
private static readonly DependencyPropertyKey IsHintInFloatingPositionPropertyKey =
74+
DependencyProperty.RegisterReadOnly(
75+
"IsHintInFloatingPosition", typeof(bool), typeof(SmartHint),
76+
new PropertyMetadata(default(bool)));
77+
78+
public static readonly DependencyProperty IsHintInFloatingPositionProperty =
79+
IsHintInFloatingPositionPropertyKey.DependencyProperty;
80+
81+
public bool IsHintInFloatingPosition
82+
{
83+
get { return (bool)GetValue(IsHintInFloatingPositionProperty); }
84+
private set { SetValue(IsHintInFloatingPositionPropertyKey, value); }
85+
}
86+
87+
#endregion
88+
7489
#region UseFloating
7590

7691
public static readonly DependencyProperty UseFloatingProperty = DependencyProperty.Register(
@@ -143,6 +158,7 @@ private static void HintProxyPropertyChangedCallback(DependencyObject dependency
143158
hintProxy.IsVisibleChanged -= smartHint.OnHintProxyIsVisibleChanged;
144159
hintProxy.ContentChanged -= smartHint.OnHintProxyContentChanged;
145160
hintProxy.Loaded -= smartHint.OnHintProxyContentChanged;
161+
hintProxy.FocusedChanged -= smartHint.OnHintProxyFocusedChanged;
146162
hintProxy.Dispose();
147163
}
148164

@@ -152,21 +168,26 @@ private static void HintProxyPropertyChangedCallback(DependencyObject dependency
152168
hintProxy.IsVisibleChanged += smartHint.OnHintProxyIsVisibleChanged;
153169
hintProxy.ContentChanged += smartHint.OnHintProxyContentChanged;
154170
hintProxy.Loaded += smartHint.OnHintProxyContentChanged;
171+
hintProxy.FocusedChanged += smartHint.OnHintProxyFocusedChanged;
155172
smartHint.RefreshState(false);
156173
}
157174

175+
protected virtual void OnHintProxyFocusedChanged(object sender, EventArgs e)
176+
{
177+
if (HintProxy.IsLoaded)
178+
RefreshState(true);
179+
else
180+
HintProxy.Loaded += HintProxySetStateOnLoaded;
181+
}
182+
158183
protected virtual void OnHintProxyContentChanged(object sender, EventArgs e)
159184
{
160185
IsContentNullOrEmpty = HintProxy.IsEmpty();
161186

162187
if (HintProxy.IsLoaded)
163-
{
164188
RefreshState(true);
165-
}
166-
else
167-
{
189+
else
168190
HintProxy.Loaded += HintProxySetStateOnLoaded;
169-
}
170191
}
171192

172193
private void HintProxySetStateOnLoaded(object sender, EventArgs e)
@@ -182,20 +203,26 @@ protected virtual void OnHintProxyIsVisibleChanged(object sender, EventArgs e)
182203

183204
private void RefreshState(bool useTransitions)
184205
{
185-
var proxy = HintProxy;
206+
IHintProxy proxy = HintProxy;
186207

187208
if (proxy == null) return;
188209
if (!proxy.IsVisible) return;
189210

190211
var action = new Action(() =>
191212
{
192-
var isEmpty = proxy.IsEmpty();
213+
string state = string.Empty;
193214

194-
var state = isEmpty
195-
? ContentEmptyName
196-
: ContentNotEmptyName;
197-
198-
VisualStateManager.GoToState(this, state, useTransitions);
215+
bool isEmpty = proxy.IsEmpty();
216+
bool isFocused = proxy.IsFocused();
217+
218+
if (UseFloating)
219+
state = !isEmpty || isFocused ? HintFloatingPositionName : HintRestingPositionName;
220+
else
221+
state = !isEmpty ? HintFloatingPositionName : HintRestingPositionName;
222+
223+
IsHintInFloatingPosition = state == HintFloatingPositionName;
224+
225+
VisualStateManager.GoToState(this, state, useTransitions);
199226
});
200227

201228
if (DesignerProperties.GetIsInDesignMode(this))

MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.ComboBox.xaml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,17 @@
501501
<MultiTrigger>
502502
<MultiTrigger.Conditions>
503503
<Condition SourceName="Hint" Property="IsContentNullOrEmpty" Value="False" />
504-
<Condition Property="IsKeyboardFocused" Value="True" />
504+
<Condition Property="wpf:HintAssist.IsFloating" Value="True" />
505+
<Condition Property="IsKeyboardFocusWithin" Value="True" />
506+
</MultiTrigger.Conditions>
507+
<Setter TargetName="Hint" Property="Foreground" Value="{DynamicResource PrimaryHueMidBrush}" />
508+
<Setter TargetName="Hint" Property="HintOpacity" Value="1" />
509+
</MultiTrigger>
510+
<MultiTrigger>
511+
<MultiTrigger.Conditions>
512+
<Condition Property="wpf:HintAssist.IsFloating" Value="True" />
513+
<Condition SourceName="Hint" Property="IsHintInFloatingPosition" Value="True" />
514+
<Condition Property="IsKeyboardFocusWithin" Value="True" />
505515
</MultiTrigger.Conditions>
506516
<Setter TargetName="Hint" Property="Foreground" Value="{DynamicResource PrimaryHueMidBrush}" />
507517
<Setter TargetName="Hint" Property="HintOpacity" Value="1" />

MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.PasswordBox.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
<ControlTemplate.Triggers>
6060
<MultiTrigger>
6161
<MultiTrigger.Conditions>
62-
<Condition SourceName="Hint" Property="IsContentNullOrEmpty" Value="False" />
62+
<Condition Property="wpf:HintAssist.IsFloating" Value="True" />
6363
<Condition Property="IsKeyboardFocused" Value="True" />
6464
</MultiTrigger.Conditions>
6565
<Setter TargetName="Hint" Property="Foreground" Value="{DynamicResource PrimaryHueMidBrush}" />

MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.SmartHint.xaml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,27 @@
2626
<VisualStateManager.VisualStateGroups>
2727
<VisualStateGroup x:Name="ContentStates">
2828
<VisualStateGroup.Transitions>
29-
<VisualTransition From="*" To="ContentNotEmpty">
29+
<VisualTransition From="*" To="HintFloatingPosition">
3030
<Storyboard>
3131
<DoubleAnimation Storyboard.TargetName="SimpleHintTextBlock" Storyboard.TargetProperty="Opacity"
3232
Duration="0:0:0" To="0" />
3333
</Storyboard>
3434
</VisualTransition>
35-
<VisualTransition From="*" To="ContentEmpty">
35+
<VisualTransition From="*" To="HintRestingPosition">
3636
<Storyboard>
3737
<DoubleAnimation Storyboard.TargetName="SimpleHintTextBlock" Storyboard.TargetProperty="Opacity"
3838
Duration="0:0:0.3"
3939
EasingFunction="{StaticResource AnimationEasingFunction}"/>
4040
</Storyboard>
4141
</VisualTransition>
4242
</VisualStateGroup.Transitions>
43-
<VisualState x:Name="ContentNotEmpty">
43+
<VisualState x:Name="HintFloatingPosition">
4444
<Storyboard>
4545
<DoubleAnimation Storyboard.TargetProperty="Opacity" Storyboard.TargetName="SimpleHintTextBlock"
4646
Duration="0" To="0" />
4747
</Storyboard>
4848
</VisualState>
49-
<VisualState x:Name="ContentEmpty">
49+
<VisualState x:Name="HintRestingPosition">
5050
<Storyboard>
5151
<DoubleAnimation Storyboard.TargetProperty="Opacity" Storyboard.TargetName="SimpleHintTextBlock"
5252
Duration="0" />
@@ -78,7 +78,7 @@
7878
<VisualStateManager.VisualStateGroups>
7979
<VisualStateGroup x:Name="ContentStates">
8080
<VisualStateGroup.Transitions>
81-
<VisualTransition From="*" To="ContentNotEmpty">
81+
<VisualTransition From="*" To="HintFloatingPosition">
8282
<Storyboard>
8383
<DoubleAnimation Storyboard.TargetName="FloatingHintTextBlock" Storyboard.TargetProperty="Opacity"
8484
Duration="0:0:0.3" To="{TemplateBinding HintOpacity}"
@@ -88,7 +88,7 @@
8888
EasingFunction="{StaticResource AnimationEasingFunction}"/>
8989
</Storyboard>
9090
</VisualTransition>
91-
<VisualTransition From="*" To="ContentEmpty">
91+
<VisualTransition From="*" To="HintRestingPosition">
9292
<Storyboard>
9393
<DoubleAnimation Storyboard.TargetName="FloatingHintTextBlock" Storyboard.TargetProperty="Opacity"
9494
Duration="0:0:0.3"
@@ -99,15 +99,15 @@
9999
</Storyboard>
100100
</VisualTransition>
101101
</VisualStateGroup.Transitions>
102-
<VisualState x:Name="ContentNotEmpty">
102+
<VisualState x:Name="HintFloatingPosition">
103103
<Storyboard>
104104
<DoubleAnimation Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FloatingHintTextBlock"
105105
Duration="0" To="{TemplateBinding HintOpacity}" />
106106
<DoubleAnimation Storyboard.TargetName="ScaleHost" Storyboard.TargetProperty="Scale"
107107
Duration="0" To="1"/>
108108
</Storyboard>
109109
</VisualState>
110-
<VisualState x:Name="ContentEmpty">
110+
<VisualState x:Name="HintRestingPosition">
111111
<Storyboard>
112112
<DoubleAnimation Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FloatingHintTextBlock"
113113
Duration="0" />

MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.TextBox.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
<ControlTemplate.Triggers>
8787
<MultiTrigger>
8888
<MultiTrigger.Conditions>
89-
<Condition SourceName="Hint" Property="IsContentNullOrEmpty" Value="False" />
89+
<Condition Property="wpf:HintAssist.IsFloating" Value="True" />
9090
<Condition Property="IsKeyboardFocused" Value="True" />
9191
</MultiTrigger.Conditions>
9292
<Setter TargetName="Hint" Property="Foreground" Value="{DynamicResource PrimaryHueMidBrush}" />

0 commit comments

Comments
 (0)