Skip to content

Commit c36307b

Browse files
authored
Fix ComboBox-ClearButton and some other ClearButton issues (#2193)
* Reworked Clear-Button in fields for small font sizes (#2187) * Fix ComboBox-ClearButton not clickable (#2187) * Fix ComboBox-ClearButton position for small font sizes (#2187) * ClearButton Hidden if HasClearButton but content is empty (#2187) * remove unused FontToLineHeightConverter (#2187) * remove unused constants (#2187) * PickerTextBoxInnerButtonSpacing -> TextBoxInnerButtonSpacing (#2187)
1 parent 46ce5cd commit c36307b

12 files changed

+455
-447
lines changed

MaterialDesignThemes.Wpf/Constants.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,10 @@ namespace MaterialDesignThemes.Wpf
55
public static class Constants
66
{
77
public static readonly Thickness TextBoxDefaultPadding = new Thickness(0, 4, 0, 4);
8-
public static readonly Thickness TextBoxFloatingHintPadding = new Thickness(0, 12, 0, 0);
98
public static readonly Thickness DefaultTextBoxViewMargin = new Thickness(1, 0, 1, 0);
109
public static readonly Thickness DefaultTextBoxViewMarginEmbedded = new Thickness(0);
1110
public const double TextBoxNotEnabledOpacity = 0.56;
12-
public const double PickerTextBoxInnerButtonSpacing = 4;
13-
public static readonly Thickness InnerButtonMargin = new Thickness(PickerTextBoxInnerButtonSpacing, 0, 0, 0);
11+
public const double TextBoxInnerButtonSpacing = 2;
12+
public const double ComboBoxArrowSize = 8;
1413
}
1514
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System;
2+
using System.Globalization;
3+
using System.Windows;
4+
using System.Windows.Data;
5+
6+
namespace MaterialDesignThemes.Wpf.Converters
7+
{
8+
internal class ComboBoxClearButtonMarginConverter : IMultiValueConverter
9+
{
10+
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
11+
{
12+
var padding = (Thickness)values[0];
13+
var borderThickness = (Thickness)values[1];
14+
return new Thickness(
15+
borderThickness.Left,
16+
borderThickness.Top + padding.Top,
17+
borderThickness.Right + padding.Right + Constants.ComboBoxArrowSize + Constants.TextBoxInnerButtonSpacing,
18+
borderThickness.Bottom + padding.Bottom);
19+
}
20+
21+
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotImplementedException();
22+
}
23+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System;
2+
using System.Globalization;
3+
using System.Windows;
4+
using System.Windows.Controls;
5+
using System.Windows.Data;
6+
7+
namespace MaterialDesignThemes.Wpf.Converters
8+
{
9+
internal class DoubleToThicknessConverter : IValueConverter
10+
{
11+
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
12+
=> (Dock)parameter switch
13+
{
14+
Dock.Left => new Thickness((double)value, 0, 0, 0),
15+
Dock.Top => new Thickness(0, (double)value, 0, 0),
16+
Dock.Right => new Thickness(0, 0, (double)value, 0),
17+
Dock.Bottom => new Thickness(0, 0, 0, (double)value),
18+
_ => Binding.DoNothing
19+
};
20+
21+
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
22+
}
23+
}

MaterialDesignThemes.Wpf/Converters/FloatingHintOffsetCalculationConverter.cs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,26 @@
66

77
namespace MaterialDesignThemes.Wpf.Converters
88
{
9-
public class FloatingHintOffsetCalculationConverter : IMultiValueConverter
9+
internal class FloatingHintOffsetCalculationConverter : IMultiValueConverter
1010
{
1111
public object Convert(object[] values, Type targetType, object? parameter, CultureInfo culture)
1212
{
13-
double height = 0;
14-
if (values[0] is FontFamily fontFamily
15-
&& values[1] is double fontSize
16-
&& values[2] is double floatingScale)
17-
height = fontFamily.LineSpacing * fontSize * floatingScale;
13+
var hintHeight = ((FontFamily)values[0]).LineSpacing
14+
* (double)values[1]; // fontSize
15+
var floatingHintHeight = hintHeight
16+
* (double)values[2]; // floatingScale
1817

19-
if (values.Length > 3 && values[3] is Thickness padding)
20-
height = height / 2 + padding.Top;
18+
var offset = (values.Length > 3 ? values[3] : null) switch
19+
{
20+
Thickness padding => floatingHintHeight / 2 + padding.Top,
21+
double parentHeight => (parentHeight - hintHeight + floatingHintHeight) / 2,
22+
_ => floatingHintHeight
23+
};
2124

2225
if (targetType == typeof(Point)) // offset
23-
return new Point(0, -height);
26+
return new Point(0, -offset);
2427
if (targetType == typeof(Thickness)) // margin
25-
return new Thickness(0, height, 0, 0);
28+
return new Thickness(0, offset, 0, 0);
2629
throw new NotSupportedException(targetType.FullName);
2730
}
2831

MaterialDesignThemes.Wpf/Converters/FontToLineHeightConverter.cs

Lines changed: 0 additions & 22 deletions
This file was deleted.

MaterialDesignThemes.Wpf/Converters/PickerInnerPaddingConverter.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Diagnostics;
23
using System.Globalization;
34
using System.Windows;
45
using System.Windows.Data;
@@ -14,7 +15,7 @@ public class PickerInnerPaddingConverter : IValueConverter, IMultiValueConverter
1415
/// </summary>
1516
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
1617
=> value is Thickness padding
17-
? new Thickness(Constants.PickerTextBoxInnerButtonSpacing, padding.Top, padding.Right, padding.Bottom)
18+
? new Thickness(Constants.TextBoxInnerButtonSpacing, padding.Top, padding.Right, padding.Bottom)
1819
: Binding.DoNothing;
1920

2021
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotSupportedException();
@@ -34,7 +35,7 @@ public object Convert(object[] values, Type targetType, object parameter, Cultur
3435
return new Thickness(
3536
padding.Left,
3637
padding.Top,
37-
padding.Right + rightAddend + Constants.PickerTextBoxInnerButtonSpacing,
38+
padding.Right + rightAddend + Constants.TextBoxInnerButtonSpacing,
3839
padding.Bottom);
3940

4041
// calculate padding for picker-button (considering floating hint offset)

MaterialDesignThemes.Wpf/Converters/TextFieldClearButtonVisibilityConverter.cs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,19 @@
55

66
namespace MaterialDesignThemes.Wpf.Converters
77
{
8-
public class TextFieldClearButtonVisibilityConverter : IMultiValueConverter
8+
internal class TextFieldClearButtonVisibilityConverter : IMultiValueConverter
99
{
1010
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
1111
{
12-
bool bAllTrue = true;
13-
foreach (var v in values)
14-
{
15-
if (v is bool b && !b)
16-
bAllTrue = false;
17-
}
18-
return bAllTrue ? Visibility.Visible : Visibility.Collapsed;
12+
if (!(bool)values[0]) // TextFieldAssist.HasClearButton
13+
return Visibility.Collapsed;
14+
15+
return (bool)values[1] // Hint.IsContentNullOrEmpty
16+
? Visibility.Hidden
17+
: Visibility.Visible;
1918
}
2019

2120
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
22-
{
23-
throw new NotImplementedException();
24-
}
21+
=> throw new NotImplementedException();
2522
}
2623
}

MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.ComboBox.xaml

Lines changed: 77 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@
1515
<converters:MathConverter x:Key="DivisionMathConverter" Operation="Divide" />
1616
<converters:BrushRoundConverter x:Key="BrushRoundConverter" />
1717
<converters:BooleanToVisibilityConverter x:Key="InverseBoolToVisConverter" TrueValue="Collapsed" FalseValue="Visible"/>
18-
<converters:TextFieldClearButtonVisibilityConverter x:Key="ClearTextConverter" />
18+
<converters:TextFieldClearButtonVisibilityConverter x:Key="ClearButtonVisibilityConverter" />
1919
<converters:NotConverter x:Key="NotConverter" />
2020
<converters:FallbackBrushConverter x:Key="FallbackBrushConverter" />
2121
<converters:RemoveAlphaBrushConverter x:Key="RemoveAlphaBrushConverter" />
2222
<converters:FloatingHintOffsetCalculationConverter x:Key="FloatingHintOffsetCalculationConverter" />
23-
<converters:FontToLineHeightConverter x:Key="FontToLineHeightConverter" />
23+
<converters:ComboBoxClearButtonMarginConverter x:Key="ComboBoxClearButtonMarginConverter" />
24+
<converters:DoubleToThicknessConverter x:Key="DoubleToThicknessConverter" />
2425

2526
<system:Double x:Key="PopupContentPresenterExtend">4</system:Double>
2627
<system:Double x:Key="PopupTopBottomMargin">8</system:Double>
@@ -328,6 +329,7 @@
328329

329330
<Style x:Key="MaterialDesignComboBoxToggleButton" TargetType="{x:Type ToggleButton}">
330331
<Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}, Path=(TextElement.Foreground)}" />
332+
<Setter Property="Background" Value="Transparent" />
331333
<Setter Property="OverridesDefaultStyle" Value="True" />
332334
<Setter Property="IsTabStop" Value="False" />
333335
<Setter Property="Focusable" Value="False" />
@@ -348,7 +350,8 @@
348350
BorderBrush="Transparent"
349351
BorderThickness="0">
350352
<Path x:Name="arrow"
351-
Width="8" Height="8"
353+
Width="{x:Static wpf:Constants.ComboBoxArrowSize}"
354+
Height="{x:Static wpf:Constants.ComboBoxArrowSize}"
352355
Margin="0"
353356
Stretch="Uniform"
354357
HorizontalAlignment="Right"
@@ -401,15 +404,6 @@
401404

402405
<ControlTemplate x:Key="MaterialDesignFloatingHintComboBoxTemplate" TargetType="{x:Type ComboBox}">
403406
<Grid>
404-
<ToggleButton
405-
x:Name="toggleButton"
406-
Grid.Column="0"
407-
Panel.ZIndex="1"
408-
Background="Transparent"
409-
BorderBrush="{TemplateBinding BorderBrush}"
410-
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
411-
Style="{StaticResource MaterialDesignComboBoxToggleButton}"
412-
Padding="{TemplateBinding Padding}" />
413407
<AdornerDecorator>
414408
<Border
415409
x:Name="templateRoot"
@@ -482,24 +476,13 @@
482476
Hint="{TemplateBinding wpf:HintAssist.Hint}"
483477
Margin="{TemplateBinding wpf:TextFieldAssist.TextBoxViewMargin}" />
484478

485-
<StackPanel
486-
Orientation="Horizontal"
487-
Grid.Column="2">
488-
<TextBlock
489-
FontSize="{TemplateBinding FontSize}"
490-
Opacity="{TemplateBinding wpf:HintAssist.HintOpacity}"
491-
Text="{TemplateBinding wpf:TextFieldAssist.SuffixText}"
492-
IsHitTestVisible="False" />
493-
<Button x:Name="PART_ClearButton" Height="Auto" Padding="2 0 0 0" Style="{DynamicResource MaterialDesignToolButton}" Focusable="False">
494-
<Button.Visibility>
495-
<MultiBinding Converter="{StaticResource ClearTextConverter}">
496-
<Binding ElementName="Hint" Path="IsContentNullOrEmpty" Converter="{StaticResource NotConverter}" />
497-
<Binding Path="(wpf:TextFieldAssist.HasClearButton)" RelativeSource="{RelativeSource TemplatedParent}" />
498-
</MultiBinding>
499-
</Button.Visibility>
500-
<wpf:PackIcon Margin="0" Kind="CloseCircle" />
501-
</Button>
502-
</StackPanel>
479+
<TextBlock
480+
Grid.Column="2"
481+
FontSize="{TemplateBinding FontSize}"
482+
Opacity="{TemplateBinding wpf:HintAssist.HintOpacity}"
483+
Text="{TemplateBinding wpf:TextFieldAssist.SuffixText}"
484+
IsHitTestVisible="False"
485+
Margin="{Binding ActualWidth, ElementName=PART_ClearButton, Converter={StaticResource DoubleToThicknessConverter}, ConverterParameter={x:Static Dock.Right}}" />
503486
</Grid>
504487
</Border>
505488
</Grid>
@@ -559,6 +542,34 @@
559542
</ScrollViewer>
560543
</ContentControl>
561544
</wpf:ComboBoxPopup>
545+
<ToggleButton
546+
x:Name="toggleButton"
547+
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
548+
Style="{StaticResource MaterialDesignComboBoxToggleButton}"
549+
BorderBrush="{TemplateBinding BorderBrush}"
550+
Padding="{TemplateBinding Padding}" />
551+
<Button
552+
x:Name="PART_ClearButton"
553+
Style="{DynamicResource MaterialDesignToolButton}"
554+
Height="Auto"
555+
VerticalAlignment="Center"
556+
HorizontalAlignment="Right"
557+
Padding="0"
558+
Focusable="False">
559+
<Button.Margin>
560+
<MultiBinding Converter="{StaticResource ComboBoxClearButtonMarginConverter}">
561+
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Padding" />
562+
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="BorderThickness" />
563+
</MultiBinding>
564+
</Button.Margin>
565+
<Button.Visibility>
566+
<MultiBinding Converter="{StaticResource ClearButtonVisibilityConverter}">
567+
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="(wpf:TextFieldAssist.HasClearButton)" />
568+
<Binding ElementName="Hint" Path="IsContentNullOrEmpty" />
569+
</MultiBinding>
570+
</Button.Visibility>
571+
<wpf:PackIcon Margin="0" Kind="CloseCircle" />
572+
</Button>
562573
</Grid>
563574

564575
<ControlTemplate.Triggers>
@@ -756,14 +767,6 @@
756767

757768
<ControlTemplate x:Key="MaterialDesignFilledComboBoxTemplate" TargetType="{x:Type ComboBox}">
758769
<Grid>
759-
<ToggleButton
760-
x:Name="toggleButton"
761-
Panel.ZIndex="1"
762-
Background="Transparent"
763-
BorderBrush="{TemplateBinding BorderBrush}"
764-
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
765-
Style="{StaticResource MaterialDesignComboBoxToggleButton}"
766-
Padding="{TemplateBinding Padding}" />
767770
<AdornerDecorator>
768771
<Border
769772
x:Name="templateRoot"
@@ -834,23 +837,14 @@
834837
Hint="{TemplateBinding wpf:HintAssist.Hint}"
835838
Margin="{TemplateBinding wpf:TextFieldAssist.TextBoxViewMargin}" />
836839

837-
<StackPanel Orientation="Horizontal" Grid.Column="2">
838-
<TextBlock
839-
x:Name="SuffixTextBlock"
840-
FontSize="{TemplateBinding FontSize}"
841-
Opacity="{TemplateBinding wpf:HintAssist.HintOpacity}"
842-
Text="{TemplateBinding wpf:TextFieldAssist.SuffixText}"
843-
IsHitTestVisible="False" />
844-
<Button x:Name="PART_ClearButton" Height="Auto" Padding="2 0 0 0" Style="{DynamicResource MaterialDesignToolButton}" Focusable="False">
845-
<Button.Visibility>
846-
<MultiBinding Converter="{StaticResource ClearTextConverter}">
847-
<Binding ElementName="Hint" Path="IsContentNullOrEmpty" Converter="{StaticResource NotConverter}" />
848-
<Binding Path="(wpf:TextFieldAssist.HasClearButton)" RelativeSource="{RelativeSource TemplatedParent}" />
849-
</MultiBinding>
850-
</Button.Visibility>
851-
<wpf:PackIcon Margin="0" Kind="CloseCircle" />
852-
</Button>
853-
</StackPanel>
840+
<TextBlock
841+
Grid.Column="2"
842+
x:Name="SuffixTextBlock"
843+
FontSize="{TemplateBinding FontSize}"
844+
Opacity="{TemplateBinding wpf:HintAssist.HintOpacity}"
845+
Text="{TemplateBinding wpf:TextFieldAssist.SuffixText}"
846+
IsHitTestVisible="False"
847+
Margin="{Binding ActualWidth, ElementName=PART_ClearButton, Converter={StaticResource DoubleToThicknessConverter}, ConverterParameter={x:Static Dock.Right}}" />
854848
</Grid>
855849
</Border>
856850
</Grid>
@@ -908,6 +902,34 @@
908902
</ScrollViewer>
909903
</ContentControl>
910904
</wpf:ComboBoxPopup>
905+
<ToggleButton
906+
x:Name="toggleButton"
907+
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
908+
Style="{StaticResource MaterialDesignComboBoxToggleButton}"
909+
BorderBrush="{TemplateBinding BorderBrush}"
910+
Padding="{TemplateBinding Padding}" />
911+
<Button
912+
x:Name="PART_ClearButton"
913+
Style="{DynamicResource MaterialDesignToolButton}"
914+
Height="Auto"
915+
VerticalAlignment="Center"
916+
HorizontalAlignment="Right"
917+
Padding="0"
918+
Focusable="False">
919+
<Button.Margin>
920+
<MultiBinding Converter="{StaticResource ComboBoxClearButtonMarginConverter}">
921+
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Padding" />
922+
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="BorderThickness" />
923+
</MultiBinding>
924+
</Button.Margin>
925+
<Button.Visibility>
926+
<MultiBinding Converter="{StaticResource ClearButtonVisibilityConverter}">
927+
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="(wpf:TextFieldAssist.HasClearButton)" />
928+
<Binding ElementName="Hint" Path="IsContentNullOrEmpty" />
929+
</MultiBinding>
930+
</Button.Visibility>
931+
<wpf:PackIcon Margin="0" Kind="CloseCircle" />
932+
</Button>
911933
</Grid>
912934
<ControlTemplate.Triggers>
913935
<Trigger Property="IsEnabled" Value="False">

0 commit comments

Comments
 (0)