From 6c9e986c8609a07d75000e54e0ba3a5b2bc18a63 Mon Sep 17 00:00:00 2001 From: Nicolai Henriksen Date: Thu, 9 Jan 2025 13:04:30 +0100 Subject: [PATCH 1/5] Demo app workaround/hack for initial miscalculation of hint placement --- src/MainDemo.Wpf/SmartHint.xaml.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/MainDemo.Wpf/SmartHint.xaml.cs b/src/MainDemo.Wpf/SmartHint.xaml.cs index bc0ead89be..89e38e9643 100644 --- a/src/MainDemo.Wpf/SmartHint.xaml.cs +++ b/src/MainDemo.Wpf/SmartHint.xaml.cs @@ -17,10 +17,24 @@ public partial class SmartHint : UserControl internal static void SetRichTextBoxText(DependencyObject element, object value) => element.SetValue(RichTextBoxTextProperty, value); internal static object GetRichTextBoxText(DependencyObject element) => element.GetValue(RichTextBoxTextProperty); + private SmartHintViewModel ViewModel { get; } + public SmartHint() { - DataContext = new SmartHintViewModel(); + DataContext = ViewModel = new SmartHintViewModel(); InitializeComponent(); + + Loaded += SmartHint_Loaded; + } + + private void SmartHint_Loaded(object sender, RoutedEventArgs e) + { + // HACK! For some strange reason, the calculation of the left margin for the hint is initially wrong if these values are set as default in the view model directly. + // Setting them here is a bit hacky, but it makes the demo page work, and I don't think this would be an issue in a real world application so I can live the hack. + // To see the issue in action: Simply comment out the 2 lines below, open the "Smart Hint" page and toggle the "IsReadOnly" checkbox in the "TextBox styles" section; + // that will place the hint on top of the prefix text for unknown reasons. + ViewModel.PrefixText = "Pre"; + ViewModel.SuffixText = "Suf"; } private void HasErrors_OnToggled(object sender, RoutedEventArgs e) From 9de4ffc981eefd586117b1a042871a7a921198ec Mon Sep 17 00:00:00 2001 From: Nicolai Henriksen Date: Thu, 9 Jan 2025 13:51:18 +0100 Subject: [PATCH 2/5] 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 --- src/MaterialDesignThemes.Wpf/SmartHint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MaterialDesignThemes.Wpf/SmartHint.cs b/src/MaterialDesignThemes.Wpf/SmartHint.cs index c69eba8aac..41c8245531 100644 --- a/src/MaterialDesignThemes.Wpf/SmartHint.cs +++ b/src/MaterialDesignThemes.Wpf/SmartHint.cs @@ -258,7 +258,7 @@ private void RefreshState(bool useTransitions) string state = string.Empty; bool isEmpty = proxy.IsEmpty(); - bool isFocused = proxy.IsFocused(); + bool isFocused = HintHost?.IsKeyboardFocusWithin ?? proxy.IsFocused(); if (UseFloating) state = !isEmpty || isFocused ? HintFloatingPositionName : HintRestingPositionName; From 8de7db72d483d35519ed6eec6ad5f414a0ecf706 Mon Sep 17 00:00:00 2001 From: Nicolai Henriksen Date: Thu, 9 Jan 2025 15:48:14 +0100 Subject: [PATCH 3/5] 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". --- .../FloatingHintInitialHorizontalOffsetConverter.cs | 13 ++++++++++--- .../Themes/MaterialDesignTheme.AutoSuggestBox.xaml | 1 + .../Themes/MaterialDesignTheme.ComboBox.xaml | 1 + .../Themes/MaterialDesignTheme.PasswordBox.xaml | 2 ++ .../Themes/MaterialDesignTheme.TextBox.xaml | 1 + 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/MaterialDesignThemes.Wpf/Converters/FloatingHintInitialHorizontalOffsetConverter.cs b/src/MaterialDesignThemes.Wpf/Converters/FloatingHintInitialHorizontalOffsetConverter.cs index bb1d5a4c88..c9bf535f65 100644 --- a/src/MaterialDesignThemes.Wpf/Converters/FloatingHintInitialHorizontalOffsetConverter.cs +++ b/src/MaterialDesignThemes.Wpf/Converters/FloatingHintInitialHorizontalOffsetConverter.cs @@ -19,7 +19,8 @@ public class FloatingHintInitialHorizontalOffsetConverter : IMultiValueConverter PrefixSuffixVisibility suffixVisibility, PrefixSuffixHintBehavior prefixHintBehavior, PrefixSuffixHintBehavior suffixHintBehavior, - HorizontalAlignment horizontalContentAlignment + HorizontalAlignment horizontalContentAlignment, + bool isEditable, ]) { return 0; @@ -37,8 +38,11 @@ double GetLeftOffset() return prefixVisibility switch { PrefixSuffixVisibility.WhenFocusedOrNonEmpty - when prefixHintBehavior == PrefixSuffixHintBehavior.AlignWithText => + when prefixHintBehavior == PrefixSuffixHintBehavior.AlignWithText && isEditable => prefixWidth + prefixMargin.Right, + PrefixSuffixVisibility.WhenFocusedOrNonEmpty + when prefixHintBehavior == PrefixSuffixHintBehavior.AlignWithPrefixSuffix && !isEditable => + -(prefixWidth + prefixMargin.Right), PrefixSuffixVisibility.Always when prefixHintBehavior == PrefixSuffixHintBehavior.AlignWithPrefixSuffix => -(prefixWidth + prefixMargin.Right), @@ -51,8 +55,11 @@ double GetRightOffset() return suffixVisibility switch { PrefixSuffixVisibility.WhenFocusedOrNonEmpty - when suffixHintBehavior == PrefixSuffixHintBehavior.AlignWithText => + when suffixHintBehavior == PrefixSuffixHintBehavior.AlignWithText && isEditable => -(suffixWidth + suffixMargin.Left), + PrefixSuffixVisibility.WhenFocusedOrNonEmpty + when suffixHintBehavior == PrefixSuffixHintBehavior.AlignWithPrefixSuffix && !isEditable => + suffixWidth + suffixMargin.Left, PrefixSuffixVisibility.Always when suffixHintBehavior == PrefixSuffixHintBehavior.AlignWithPrefixSuffix => suffixWidth + suffixMargin.Left, diff --git a/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.AutoSuggestBox.xaml b/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.AutoSuggestBox.xaml index a8f8f1123f..30713bca3f 100644 --- a/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.AutoSuggestBox.xaml +++ b/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.AutoSuggestBox.xaml @@ -174,6 +174,7 @@ + diff --git a/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.ComboBox.xaml b/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.ComboBox.xaml index 7e0a333041..7b8c0f0fbf 100644 --- a/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.ComboBox.xaml +++ b/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.ComboBox.xaml @@ -416,6 +416,7 @@ + diff --git a/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.PasswordBox.xaml b/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.PasswordBox.xaml index ff3b415b4f..d6745207d8 100644 --- a/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.PasswordBox.xaml +++ b/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.PasswordBox.xaml @@ -216,6 +216,7 @@ + @@ -836,6 +837,7 @@ + diff --git a/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.TextBox.xaml b/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.TextBox.xaml index a20c25196a..55133abc9e 100644 --- a/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.TextBox.xaml +++ b/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.TextBox.xaml @@ -212,6 +212,7 @@ + From 31e3840bfb81f7588101e60cb6d4830ec5bd2cda Mon Sep 17 00:00:00 2001 From: Kevin Bost Date: Thu, 9 Jan 2025 22:00:55 -0800 Subject: [PATCH 4/5] Fixing so the hack is no longer needed --- src/MainDemo.Wpf/SmartHint.xaml.cs | 16 +-------- .../Themes/MaterialDesignTheme.TextBox.xaml | 36 +++++++++---------- 2 files changed, 19 insertions(+), 33 deletions(-) diff --git a/src/MainDemo.Wpf/SmartHint.xaml.cs b/src/MainDemo.Wpf/SmartHint.xaml.cs index 89e38e9643..bc0ead89be 100644 --- a/src/MainDemo.Wpf/SmartHint.xaml.cs +++ b/src/MainDemo.Wpf/SmartHint.xaml.cs @@ -17,24 +17,10 @@ public partial class SmartHint : UserControl internal static void SetRichTextBoxText(DependencyObject element, object value) => element.SetValue(RichTextBoxTextProperty, value); internal static object GetRichTextBoxText(DependencyObject element) => element.GetValue(RichTextBoxTextProperty); - private SmartHintViewModel ViewModel { get; } - public SmartHint() { - DataContext = ViewModel = new SmartHintViewModel(); + DataContext = new SmartHintViewModel(); InitializeComponent(); - - Loaded += SmartHint_Loaded; - } - - private void SmartHint_Loaded(object sender, RoutedEventArgs e) - { - // HACK! For some strange reason, the calculation of the left margin for the hint is initially wrong if these values are set as default in the view model directly. - // Setting them here is a bit hacky, but it makes the demo page work, and I don't think this would be an issue in a real world application so I can live the hack. - // To see the issue in action: Simply comment out the 2 lines below, open the "Smart Hint" page and toggle the "IsReadOnly" checkbox in the "TextBox styles" section; - // that will place the hint on top of the prefix text for unknown reasons. - ViewModel.PrefixText = "Pre"; - ViewModel.SuffixText = "Suf"; } private void HasErrors_OnToggled(object sender, RoutedEventArgs e) diff --git a/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.TextBox.xaml b/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.TextBox.xaml index 55133abc9e..52372c0272 100644 --- a/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.TextBox.xaml +++ b/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.TextBox.xaml @@ -151,24 +151,6 @@ Opacity="{TemplateBinding wpf:HintAssist.HintOpacity}" Visibility="{TemplateBinding wpf:TextFieldAssist.HasLeadingIcon, Converter={x:Static converters:BooleanToVisibilityConverter.CollapsedInstance}}" /> - - - - - - - - - - - - + + + + + + + + + + + + Date: Thu, 9 Jan 2025 22:19:30 -0800 Subject: [PATCH 5/5] Fix AutoSuggestBox as well --- .../MaterialDesignTheme.AutoSuggestBox.xaml | 105 +++++++++--------- 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.AutoSuggestBox.xaml b/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.AutoSuggestBox.xaml index 30713bca3f..ece9dd79f4 100644 --- a/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.AutoSuggestBox.xaml +++ b/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.AutoSuggestBox.xaml @@ -71,29 +71,29 @@ + VerticalAlignment="Stretch" + Background="{DynamicResource MaterialDesign.Brush.TextBox.HoverBackground}" + CornerRadius="{TemplateBinding wpf:TextFieldAssist.TextFieldCornerRadius}" + RenderTransformOrigin="0.5,0.5" + Visibility="{TemplateBinding wpf:TextFieldAssist.RippleOnFocusEnabled, Converter={x:Static converters:BooleanToVisibilityConverter.CollapsedInstance}}"> + Padding="{TemplateBinding Padding}" + wpf:BottomDashedLineAdorner.Brush="{TemplateBinding BorderBrush}" + wpf:BottomDashedLineAdorner.Thickness="{Binding RelativeSource={RelativeSource Self}, Path=BorderThickness}" + Background="{TemplateBinding Background}" + BorderBrush="{TemplateBinding BorderBrush}" + BorderThickness="{TemplateBinding BorderThickness}" + CornerRadius="{TemplateBinding wpf:TextFieldAssist.TextFieldCornerRadius}" + SnapsToDevicePixels="True"> + MinHeight="16" + VerticalAlignment="{TemplateBinding VerticalContentAlignment}"> @@ -104,32 +104,14 @@ - - - - - - - - - - - - + Grid.Column="0" + Width="{TemplateBinding wpf:TextFieldAssist.LeadingIconSize}" + Height="{TemplateBinding wpf:TextFieldAssist.LeadingIconSize}" + Margin="0,0,6,0" + VerticalAlignment="{TemplateBinding wpf:TextFieldAssist.IconVerticalAlignment}" + Kind="{TemplateBinding wpf:TextFieldAssist.LeadingIcon}" + Opacity="{TemplateBinding wpf:HintAssist.HintOpacity}" + Visibility="{TemplateBinding wpf:TextFieldAssist.HasLeadingIcon, Converter={x:Static converters:BooleanToVisibilityConverter.CollapsedInstance}}" /> + Background="{TemplateBinding wpf:HintAssist.Background}" + CornerRadius="2"> + + + + + + + + + + + + + Grid.Column="3" + Margin="2,0,0,0" + VerticalAlignment="Center" + FontSize="{TemplateBinding FontSize}" + Opacity="{TemplateBinding wpf:HintAssist.HintOpacity}" + Text="{TemplateBinding wpf:TextFieldAssist.SuffixText}"> @@ -289,11 +289,10 @@ CornerRadius="{TemplateBinding wpf:TextFieldAssist.UnderlineCornerRadius}" Visibility="{TemplateBinding wpf:TextFieldAssist.DecorationVisibility}" /> - + + Padding="{TemplateBinding Padding, Converter={StaticResource HelperTextMarginConverter}}" + Width="{Binding ActualWidth, ElementName=OuterBorder}">