Skip to content

Commit 070e8bb

Browse files
[SmartHint] Hint placement for "readonly" controls (#3764)
* Demo app workaround/hack for initial miscalculation of hint placement * Ensure ComboBox smart hint behaves according to MD spec According to the "Behavior" section of the "Menus" page in the link below, the hint should float even when there is no selection, but the popup is open. https://m2.material.io/components/menus#exposed-dropdown-menu * Fix hint positioning issue when "readonly" element The issue was present for all controls once they are in "readonly" state. Special handling of the case where the element is readonly, and the hint should follow the prefix/suffix needed to be added because of the "business rule" that prefix/suffix is always visible when the element is "readonly". * Fixing so the hack is no longer needed * Fix AutoSuggestBox as well --------- Co-authored-by: Kevin Bost <[email protected]>
1 parent 9e71c5c commit 070e8bb

File tree

6 files changed

+86
-75
lines changed

6 files changed

+86
-75
lines changed

src/MaterialDesignThemes.Wpf/Converters/FloatingHintInitialHorizontalOffsetConverter.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ public class FloatingHintInitialHorizontalOffsetConverter : IMultiValueConverter
1919
PrefixSuffixVisibility suffixVisibility,
2020
PrefixSuffixHintBehavior prefixHintBehavior,
2121
PrefixSuffixHintBehavior suffixHintBehavior,
22-
HorizontalAlignment horizontalContentAlignment
22+
HorizontalAlignment horizontalContentAlignment,
23+
bool isEditable,
2324
])
2425
{
2526
return 0;
@@ -37,8 +38,11 @@ double GetLeftOffset()
3738
return prefixVisibility switch
3839
{
3940
PrefixSuffixVisibility.WhenFocusedOrNonEmpty
40-
when prefixHintBehavior == PrefixSuffixHintBehavior.AlignWithText =>
41+
when prefixHintBehavior == PrefixSuffixHintBehavior.AlignWithText && isEditable =>
4142
prefixWidth + prefixMargin.Right,
43+
PrefixSuffixVisibility.WhenFocusedOrNonEmpty
44+
when prefixHintBehavior == PrefixSuffixHintBehavior.AlignWithPrefixSuffix && !isEditable =>
45+
-(prefixWidth + prefixMargin.Right),
4246
PrefixSuffixVisibility.Always
4347
when prefixHintBehavior == PrefixSuffixHintBehavior.AlignWithPrefixSuffix =>
4448
-(prefixWidth + prefixMargin.Right),
@@ -51,8 +55,11 @@ double GetRightOffset()
5155
return suffixVisibility switch
5256
{
5357
PrefixSuffixVisibility.WhenFocusedOrNonEmpty
54-
when suffixHintBehavior == PrefixSuffixHintBehavior.AlignWithText =>
58+
when suffixHintBehavior == PrefixSuffixHintBehavior.AlignWithText && isEditable =>
5559
-(suffixWidth + suffixMargin.Left),
60+
PrefixSuffixVisibility.WhenFocusedOrNonEmpty
61+
when suffixHintBehavior == PrefixSuffixHintBehavior.AlignWithPrefixSuffix && !isEditable =>
62+
suffixWidth + suffixMargin.Left,
5663
PrefixSuffixVisibility.Always
5764
when suffixHintBehavior == PrefixSuffixHintBehavior.AlignWithPrefixSuffix =>
5865
suffixWidth + suffixMargin.Left,

src/MaterialDesignThemes.Wpf/SmartHint.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ private void RefreshState(bool useTransitions)
258258
string state = string.Empty;
259259

260260
bool isEmpty = proxy.IsEmpty();
261-
bool isFocused = proxy.IsFocused();
261+
bool isFocused = HintHost?.IsKeyboardFocusWithin ?? proxy.IsFocused();
262262

263263
if (UseFloating)
264264
state = !isEmpty || isFocused ? HintFloatingPositionName : HintRestingPositionName;

src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.AutoSuggestBox.xaml

Lines changed: 53 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -71,29 +71,29 @@
7171
</VisualStateGroup>
7272
</VisualStateManager.VisualStateGroups>
7373
<Border HorizontalAlignment="Stretch"
74-
VerticalAlignment="Stretch"
75-
Background="{DynamicResource MaterialDesign.Brush.TextBox.HoverBackground}"
76-
CornerRadius="{TemplateBinding wpf:TextFieldAssist.TextFieldCornerRadius}"
77-
RenderTransformOrigin="0.5,0.5"
78-
Visibility="{TemplateBinding wpf:TextFieldAssist.RippleOnFocusEnabled, Converter={x:Static converters:BooleanToVisibilityConverter.CollapsedInstance}}">
74+
VerticalAlignment="Stretch"
75+
Background="{DynamicResource MaterialDesign.Brush.TextBox.HoverBackground}"
76+
CornerRadius="{TemplateBinding wpf:TextFieldAssist.TextFieldCornerRadius}"
77+
RenderTransformOrigin="0.5,0.5"
78+
Visibility="{TemplateBinding wpf:TextFieldAssist.RippleOnFocusEnabled, Converter={x:Static converters:BooleanToVisibilityConverter.CollapsedInstance}}">
7979
<Border.RenderTransform>
8080
<ScaleTransform x:Name="RippleOnFocusScaleTransform" ScaleX="0" ScaleY="0" />
8181
</Border.RenderTransform>
8282
</Border>
8383
<AdornerDecorator>
8484
<Border x:Name="OuterBorder"
85-
Padding="{TemplateBinding Padding}"
86-
wpf:BottomDashedLineAdorner.Brush="{TemplateBinding BorderBrush}"
87-
wpf:BottomDashedLineAdorner.Thickness="{Binding RelativeSource={RelativeSource Self}, Path=BorderThickness}"
88-
Background="{TemplateBinding Background}"
89-
BorderBrush="{TemplateBinding BorderBrush}"
90-
BorderThickness="{TemplateBinding BorderThickness}"
91-
CornerRadius="{TemplateBinding wpf:TextFieldAssist.TextFieldCornerRadius}"
92-
SnapsToDevicePixels="True">
85+
Padding="{TemplateBinding Padding}"
86+
wpf:BottomDashedLineAdorner.Brush="{TemplateBinding BorderBrush}"
87+
wpf:BottomDashedLineAdorner.Thickness="{Binding RelativeSource={RelativeSource Self}, Path=BorderThickness}"
88+
Background="{TemplateBinding Background}"
89+
BorderBrush="{TemplateBinding BorderBrush}"
90+
BorderThickness="{TemplateBinding BorderThickness}"
91+
CornerRadius="{TemplateBinding wpf:TextFieldAssist.TextFieldCornerRadius}"
92+
SnapsToDevicePixels="True">
9393

9494
<Grid x:Name="ContentGrid"
95-
MinHeight="16"
96-
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
95+
MinHeight="16"
96+
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
9797
<Grid.ColumnDefinitions>
9898
<ColumnDefinition Width="Auto" />
9999
<ColumnDefinition Width="Auto" />
@@ -104,32 +104,14 @@
104104
</Grid.ColumnDefinitions>
105105

106106
<wpf:PackIcon x:Name="LeadingPackIcon"
107-
Grid.Column="0"
108-
Width="{TemplateBinding wpf:TextFieldAssist.LeadingIconSize}"
109-
Height="{TemplateBinding wpf:TextFieldAssist.LeadingIconSize}"
110-
Margin="0,0,6,0"
111-
VerticalAlignment="{TemplateBinding wpf:TextFieldAssist.IconVerticalAlignment}"
112-
Kind="{TemplateBinding wpf:TextFieldAssist.LeadingIcon}"
113-
Opacity="{TemplateBinding wpf:HintAssist.HintOpacity}"
114-
Visibility="{TemplateBinding wpf:TextFieldAssist.HasLeadingIcon, Converter={x:Static converters:BooleanToVisibilityConverter.CollapsedInstance}}" />
115-
116-
<TextBlock x:Name="PrefixTextBlock"
117-
Grid.Column="1"
118-
Margin="0,0,2,0"
119-
VerticalAlignment="Center"
120-
FontSize="{TemplateBinding FontSize}"
121-
Opacity="{TemplateBinding wpf:HintAssist.HintOpacity}"
122-
Text="{TemplateBinding wpf:TextFieldAssist.PrefixText}">
123-
<TextBlock.Visibility>
124-
<MultiBinding Converter="{StaticResource PrefixSuffixTextVisibilityConverter}">
125-
<Binding ElementName="Hint" Path="IsHintInFloatingPosition" />
126-
<Binding Path="(wpf:TextFieldAssist.PrefixText)" RelativeSource="{RelativeSource TemplatedParent}" />
127-
<Binding Path="(wpf:TextFieldAssist.PrefixTextVisibility)" RelativeSource="{RelativeSource TemplatedParent}" />
128-
<Binding Path="IsKeyboardFocusWithin" RelativeSource="{RelativeSource TemplatedParent}" />
129-
<Binding Path="IsReadOnly" RelativeSource="{RelativeSource TemplatedParent}" Converter="{x:Static converters:InvertBooleanConverter.Instance}" />
130-
</MultiBinding>
131-
</TextBlock.Visibility>
132-
</TextBlock>
107+
Grid.Column="0"
108+
Width="{TemplateBinding wpf:TextFieldAssist.LeadingIconSize}"
109+
Height="{TemplateBinding wpf:TextFieldAssist.LeadingIconSize}"
110+
Margin="0,0,6,0"
111+
VerticalAlignment="{TemplateBinding wpf:TextFieldAssist.IconVerticalAlignment}"
112+
Kind="{TemplateBinding wpf:TextFieldAssist.LeadingIcon}"
113+
Opacity="{TemplateBinding wpf:HintAssist.HintOpacity}"
114+
Visibility="{TemplateBinding wpf:TextFieldAssist.HasLeadingIcon, Converter={x:Static converters:BooleanToVisibilityConverter.CollapsedInstance}}" />
133115

134116
<ScrollViewer x:Name="PART_ContentHost"
135117
Grid.Column="2"
@@ -174,6 +156,7 @@
174156
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="(wpf:TextFieldAssist.PrefixTextHintBehavior)" />
175157
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="(wpf:TextFieldAssist.SuffixTextHintBehavior)" />
176158
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="HorizontalContentAlignment" />
159+
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="IsReadOnly" Converter="{x:Static converters:InvertBooleanConverter.Instance}" />
177160
</MultiBinding>
178161
</wpf:SmartHint.InitialHorizontalOffset>
179162
<wpf:SmartHint.Margin>
@@ -191,20 +174,38 @@
191174
</wpf:SmartHint.Margin>
192175
<wpf:SmartHint.Hint>
193176
<Border x:Name="HintBackgroundBorder"
194-
Background="{TemplateBinding wpf:HintAssist.Background}"
195-
CornerRadius="2">
177+
Background="{TemplateBinding wpf:HintAssist.Background}"
178+
CornerRadius="2">
196179
<ContentPresenter x:Name="HintWrapper" Content="{TemplateBinding wpf:HintAssist.Hint}" />
197180
</Border>
198181
</wpf:SmartHint.Hint>
199182
</wpf:SmartHint>
200183

184+
<TextBlock x:Name="PrefixTextBlock"
185+
Grid.Column="1"
186+
Margin="0,0,2,0"
187+
VerticalAlignment="Center"
188+
FontSize="{TemplateBinding FontSize}"
189+
Opacity="{TemplateBinding wpf:HintAssist.HintOpacity}"
190+
Text="{TemplateBinding wpf:TextFieldAssist.PrefixText}">
191+
<TextBlock.Visibility>
192+
<MultiBinding Converter="{StaticResource PrefixSuffixTextVisibilityConverter}">
193+
<Binding ElementName="Hint" Path="IsHintInFloatingPosition" />
194+
<Binding Path="(wpf:TextFieldAssist.PrefixText)" RelativeSource="{RelativeSource TemplatedParent}" />
195+
<Binding Path="(wpf:TextFieldAssist.PrefixTextVisibility)" RelativeSource="{RelativeSource TemplatedParent}" />
196+
<Binding Path="IsKeyboardFocusWithin" RelativeSource="{RelativeSource TemplatedParent}" />
197+
<Binding Path="IsReadOnly" RelativeSource="{RelativeSource TemplatedParent}" Converter="{x:Static converters:InvertBooleanConverter.Instance}" />
198+
</MultiBinding>
199+
</TextBlock.Visibility>
200+
</TextBlock>
201+
201202
<TextBlock x:Name="SuffixTextBlock"
202-
Grid.Column="3"
203-
Margin="2,0,0,0"
204-
VerticalAlignment="Center"
205-
FontSize="{TemplateBinding FontSize}"
206-
Opacity="{TemplateBinding wpf:HintAssist.HintOpacity}"
207-
Text="{TemplateBinding wpf:TextFieldAssist.SuffixText}">
203+
Grid.Column="3"
204+
Margin="2,0,0,0"
205+
VerticalAlignment="Center"
206+
FontSize="{TemplateBinding FontSize}"
207+
Opacity="{TemplateBinding wpf:HintAssist.HintOpacity}"
208+
Text="{TemplateBinding wpf:TextFieldAssist.SuffixText}">
208209
<TextBlock.Visibility>
209210
<MultiBinding Converter="{StaticResource PrefixSuffixTextVisibilityConverter}">
210211
<Binding ElementName="Hint" Path="IsHintInFloatingPosition" />
@@ -288,11 +289,10 @@
288289
CornerRadius="{TemplateBinding wpf:TextFieldAssist.UnderlineCornerRadius}"
289290
Visibility="{TemplateBinding wpf:TextFieldAssist.DecorationVisibility}" />
290291

291-
<Canvas VerticalAlignment="Bottom"
292-
IsHitTestVisible="False">
292+
<Canvas VerticalAlignment="Bottom" IsHitTestVisible="False">
293293
<Border Canvas.Top="2"
294-
Padding="{TemplateBinding Padding, Converter={StaticResource HelperTextMarginConverter}}"
295-
Width="{Binding ActualWidth, ElementName=OuterBorder}">
294+
Padding="{TemplateBinding Padding, Converter={StaticResource HelperTextMarginConverter}}"
295+
Width="{Binding ActualWidth, ElementName=OuterBorder}">
296296
<Grid x:Name="FooterGrid">
297297
<Grid.ColumnDefinitions>
298298
<ColumnDefinition />

src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.ComboBox.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,7 @@
416416
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="(wpf:TextFieldAssist.PrefixTextHintBehavior)" />
417417
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="(wpf:TextFieldAssist.SuffixTextHintBehavior)" />
418418
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="HorizontalContentAlignment" />
419+
<Binding Path="IsEditable" RelativeSource="{RelativeSource TemplatedParent}" />
419420
</MultiBinding>
420421
</wpf:SmartHint.InitialHorizontalOffset>
421422
<wpf:SmartHint.Margin>

src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.PasswordBox.xaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@
216216
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="(wpf:TextFieldAssist.PrefixTextHintBehavior)" />
217217
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="(wpf:TextFieldAssist.SuffixTextHintBehavior)" />
218218
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="HorizontalContentAlignment" />
219+
<Binding Source="{StaticResource TrueValue}" />
219220
</MultiBinding>
220221
</wpf:SmartHint.InitialHorizontalOffset>
221222
<wpf:SmartHint.Margin>
@@ -836,6 +837,7 @@
836837
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="(wpf:TextFieldAssist.PrefixTextHintBehavior)" />
837838
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="(wpf:TextFieldAssist.SuffixTextHintBehavior)" />
838839
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="HorizontalContentAlignment" />
840+
<Binding Source="{StaticResource TrueValue}" />
839841
</MultiBinding>
840842
</wpf:SmartHint.InitialHorizontalOffset>
841843
<wpf:SmartHint.Margin>

src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.TextBox.xaml

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -151,24 +151,6 @@
151151
Opacity="{TemplateBinding wpf:HintAssist.HintOpacity}"
152152
Visibility="{TemplateBinding wpf:TextFieldAssist.HasLeadingIcon, Converter={x:Static converters:BooleanToVisibilityConverter.CollapsedInstance}}" />
153153

154-
<TextBlock x:Name="PrefixTextBlock"
155-
Grid.Column="1"
156-
Margin="0,0,2,0"
157-
VerticalAlignment="Center"
158-
FontSize="{TemplateBinding FontSize}"
159-
Opacity="{TemplateBinding wpf:HintAssist.HintOpacity}"
160-
Text="{TemplateBinding wpf:TextFieldAssist.PrefixText}">
161-
<TextBlock.Visibility>
162-
<MultiBinding Converter="{StaticResource PrefixSuffixTextVisibilityConverter}">
163-
<Binding ElementName="Hint" Path="IsHintInFloatingPosition" />
164-
<Binding Path="(wpf:TextFieldAssist.PrefixText)" RelativeSource="{RelativeSource TemplatedParent}" />
165-
<Binding Path="(wpf:TextFieldAssist.PrefixTextVisibility)" RelativeSource="{RelativeSource TemplatedParent}" />
166-
<Binding Path="IsKeyboardFocusWithin" RelativeSource="{RelativeSource TemplatedParent}" />
167-
<Binding Path="IsReadOnly" RelativeSource="{RelativeSource TemplatedParent}" Converter="{x:Static converters:InvertBooleanConverter.Instance}" />
168-
</MultiBinding>
169-
</TextBlock.Visibility>
170-
</TextBlock>
171-
172154
<ScrollViewer x:Name="PART_ContentHost"
173155
Grid.Column="2"
174156
HorizontalAlignment="Stretch"
@@ -212,6 +194,7 @@
212194
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="(wpf:TextFieldAssist.PrefixTextHintBehavior)" />
213195
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="(wpf:TextFieldAssist.SuffixTextHintBehavior)" />
214196
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="HorizontalContentAlignment" />
197+
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="IsReadOnly" Converter="{x:Static converters:InvertBooleanConverter.Instance}" />
215198
</MultiBinding>
216199
</wpf:SmartHint.InitialHorizontalOffset>
217200
<wpf:SmartHint.Margin>
@@ -236,6 +219,24 @@
236219
</wpf:SmartHint.Hint>
237220
</wpf:SmartHint>
238221

222+
<TextBlock x:Name="PrefixTextBlock"
223+
Grid.Column="1"
224+
Margin="0,0,2,0"
225+
VerticalAlignment="Center"
226+
FontSize="{TemplateBinding FontSize}"
227+
Opacity="{TemplateBinding wpf:HintAssist.HintOpacity}"
228+
Text="{TemplateBinding wpf:TextFieldAssist.PrefixText}">
229+
<TextBlock.Visibility>
230+
<MultiBinding Converter="{StaticResource PrefixSuffixTextVisibilityConverter}">
231+
<Binding ElementName="Hint" Path="IsHintInFloatingPosition" />
232+
<Binding Path="(wpf:TextFieldAssist.PrefixText)" RelativeSource="{RelativeSource TemplatedParent}" />
233+
<Binding Path="(wpf:TextFieldAssist.PrefixTextVisibility)" RelativeSource="{RelativeSource TemplatedParent}" />
234+
<Binding Path="IsKeyboardFocusWithin" RelativeSource="{RelativeSource TemplatedParent}" />
235+
<Binding Path="IsReadOnly" RelativeSource="{RelativeSource TemplatedParent}" Converter="{x:Static converters:InvertBooleanConverter.Instance}" />
236+
</MultiBinding>
237+
</TextBlock.Visibility>
238+
</TextBlock>
239+
239240
<TextBlock x:Name="SuffixTextBlock"
240241
Grid.Column="3"
241242
Margin="2,0,0,0"

0 commit comments

Comments
 (0)