diff --git a/MainDemo.Wpf/DataGrids.xaml b/MainDemo.Wpf/DataGrids.xaml
index d71444cdd4..37ff8b3e32 100644
--- a/MainDemo.Wpf/DataGrids.xaml
+++ b/MainDemo.Wpf/DataGrids.xaml
@@ -11,7 +11,7 @@
d:DesignHeight="300"
d:DesignWidth="600"
d:DataContext="{d:DesignInstance domain:ListsAndGridsViewModel}">
-
+
@@ -19,23 +19,31 @@
-
+
-
-
+
+
+
+
+
+
+ HeadersVisibility="All"
+ SelectionUnit="{Binding ElementName=selectionUnitComboBox, Path=SelectedValue}">
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
recorder.Success();
}
+
+ [Fact]
+ [Description("PR 2828")]
+ public async Task RevealPasswordBox_WithBoundPasswordProperty_RespectsThreeWayBinding()
+ {
+ await using var recorder = new TestRecorder(App);
+
+ var grid = await LoadXaml(@"
+
+
+
+
+
+");
+ var boundPasswordTextBox = await grid.GetElement("BoundPassword"); // Serves as the "VM" in this test
+ var passwordBox = await grid.GetElement("PasswordBox");
+ var clearTextPasswordTextBox = await passwordBox.GetElement("RevealPasswordTextBox");
+ var revealPasswordButton = await passwordBox.GetElement("RevealPasswordButton");
+
+ // Act 1 (Update in VM updates PasswordBox and RevealPasswordTextBox)
+ await boundPasswordTextBox.SendKeyboardInput($"1");
+ string? boundText1 = await boundPasswordTextBox.GetProperty(TextBox.TextProperty);
+ string? password1 = await passwordBox.GetProperty(nameof(PasswordBox.Password));
+ string? clearTextPassword1 = await clearTextPasswordTextBox.GetProperty(TextBox.TextProperty);
+
+ // Act 2 (Update in PasswordBox updates VM and RevealPasswordTextBox)
+ await passwordBox.SendKeyboardInput($"2");
+ string? boundText2 = await boundPasswordTextBox.GetProperty(TextBox.TextProperty);
+ string? password2 = await passwordBox.GetProperty(nameof(PasswordBox.Password));
+ string? clearTextPassword2 = await clearTextPasswordTextBox.GetProperty(TextBox.TextProperty);
+
+ // Act 2 (Update in RevealPasswordTextBox updates PasswordBox and VM)
+ await revealPasswordButton.LeftClick();
+ await Task.Delay(50); // Wait for the "clear text TextBox" to become visible
+ await clearTextPasswordTextBox.SendKeyboardInput($"3");
+ string? boundText3 = await boundPasswordTextBox.GetProperty(TextBox.TextProperty);
+ string? password3 = await passwordBox.GetProperty(nameof(PasswordBox.Password));
+ string? clearTextPassword3 = await clearTextPasswordTextBox.GetProperty(TextBox.TextProperty);
+
+ // Assert
+ Assert.Equal("1", boundText1);
+ Assert.Equal("1", password1);
+ Assert.Equal("1", clearTextPassword1);
+
+ Assert.Equal("21", boundText2);
+ Assert.Equal("21", password2);
+ Assert.Equal("21", clearTextPassword2);
+
+ Assert.Equal("321", boundText3);
+ Assert.Equal("321", password3);
+ Assert.Equal("321", clearTextPassword3);
+
+ recorder.Success();
+ }
}
}
diff --git a/MaterialDesignThemes.UITests/WPF/TextBoxes/TextBoxTests.cs b/MaterialDesignThemes.UITests/WPF/TextBoxes/TextBoxTests.cs
index ff492bd821..8d1063f5f8 100644
--- a/MaterialDesignThemes.UITests/WPF/TextBoxes/TextBoxTests.cs
+++ b/MaterialDesignThemes.UITests/WPF/TextBoxes/TextBoxTests.cs
@@ -1,5 +1,6 @@
using System;
using System.ComponentModel;
+using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
@@ -404,5 +405,91 @@ public async Task VerticalContentAlignment_ProperlyAlignsText()
recorder.Success();
}
+
+ [Fact]
+ [Description("Issue 2596")]
+ public async Task OutlinedTextBox_ValidationErrorMargin_MatchesHelperTextMargin()
+ {
+ await using var recorder = new TestRecorder(App);
+
+ var stackPanel = await LoadXaml(@"
+
+
+
+
+
+
+
+
+
+
+
+", ("local", typeof(NotEmptyValidationRule)));
+
+ var textBox = await stackPanel.GetElement("/TextBox");
+
+ var errorViewer = await textBox.GetElement("DefaultErrorViewer");
+ var helperTextTextBlock = await textBox.GetElement("HelperTextTextBlock");
+
+ Thickness? errorMargin = await errorViewer.GetProperty(FrameworkElement.MarginProperty);
+ Thickness? helperTextMargin = await helperTextTextBlock.GetProperty(FrameworkElement.MarginProperty);
+
+ Assert.True(errorMargin.HasValue);
+ Assert.True(helperTextMargin.HasValue);
+ Assert.True(Math.Abs(errorMargin.Value.Left - helperTextMargin.Value.Left) < double.Epsilon,
+ $"Error text and helper text do not have the same Margin.Left values: Error text Margin.Left ({errorMargin.Value.Left}) == Helper text Margin.Left ({helperTextMargin.Value.Left})");
+
+ recorder.Success();
+ }
+
+ [Fact]
+ [Description("Issue 2596")]
+ public async Task FilledTextBox_ValidationErrorMargin_MatchesHelperTextMargin()
+ {
+ await using var recorder = new TestRecorder(App);
+
+ var stackPanel = await LoadXaml(@"
+
+
+
+
+
+
+
+
+
+
+
+", ("local", typeof(NotEmptyValidationRule)));
+
+ var textBox = await stackPanel.GetElement("/TextBox");
+
+ var errorViewer = await textBox.GetElement("DefaultErrorViewer");
+ var helperTextTextBlock = await textBox.GetElement("HelperTextTextBlock");
+
+ Thickness? errorMargin = await errorViewer.GetProperty(FrameworkElement.MarginProperty);
+ Thickness? helperTextMargin = await helperTextTextBlock.GetProperty(FrameworkElement.MarginProperty);
+
+ Assert.True(errorMargin.HasValue);
+ Assert.True(helperTextMargin.HasValue);
+ Assert.True(Math.Abs(errorMargin.Value.Left - helperTextMargin.Value.Left) < double.Epsilon,
+ $"Error text and helper text do not have the same Margin.Left values: Error text Margin.Left ({errorMargin.Value.Left}) == Helper text Margin.Left ({helperTextMargin.Value.Left})");
+
+ recorder.Success();
+ }
+ }
+
+ public class NotEmptyValidationRule : ValidationRule
+ {
+ public override ValidationResult Validate(object value, CultureInfo cultureInfo)
+ {
+ return string.IsNullOrWhiteSpace((value ?? "").ToString())
+ ? new ValidationResult(false, "Field is required.")
+ : ValidationResult.ValidResult;
+ }
}
}
diff --git a/MaterialDesignThemes.Wpf/Converters/CursorConverter.cs b/MaterialDesignThemes.Wpf/Converters/CursorConverter.cs
new file mode 100644
index 0000000000..3838bf5aeb
--- /dev/null
+++ b/MaterialDesignThemes.Wpf/Converters/CursorConverter.cs
@@ -0,0 +1,17 @@
+using System.Globalization;
+using System.Windows.Data;
+using Cursor = System.Windows.Input.Cursor;
+
+namespace MaterialDesignThemes.Wpf.Converters;
+
+///
+/// Value converter that uses the Cursor from the bound property if set, otherwise it returns the .
+///
+public sealed class CursorConverter : IValueConverter
+{
+ public Cursor FallbackCursor { get; set; } = Cursors.Arrow;
+
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => value as Cursor ?? FallbackCursor;
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
+}
\ No newline at end of file
diff --git a/MaterialDesignThemes.Wpf/Converters/HintProxyFabricConverter.cs b/MaterialDesignThemes.Wpf/Converters/HintProxyFabricConverter.cs
index 8f6d64b518..9dc082db34 100644
--- a/MaterialDesignThemes.Wpf/Converters/HintProxyFabricConverter.cs
+++ b/MaterialDesignThemes.Wpf/Converters/HintProxyFabricConverter.cs
@@ -1,25 +1,20 @@
-using System;
-using System.Globalization;
-using System.Windows.Controls;
+using System.Globalization;
using System.Windows.Data;
-namespace MaterialDesignThemes.Wpf.Converters
+namespace MaterialDesignThemes.Wpf.Converters;
+
+///
+/// Converter for control. Can be extended by method.
+///
+public class HintProxyFabricConverter : IValueConverter
{
- ///
- /// Converter for control. Can be extended by method.
- ///
- public class HintProxyFabricConverter : IValueConverter
- {
- private static readonly Lazy _instance = new Lazy();
+ private static readonly Lazy _instance = new();
- public static HintProxyFabricConverter Instance => _instance.Value;
+ public static HintProxyFabricConverter Instance => _instance.Value;
- public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
- {
- return HintProxyFabric.Get(value as Control);
- }
+ public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
+ => HintProxyFabric.Get(value as Control);
- public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
- => Binding.DoNothing;
- }
+ public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
+ => Binding.DoNothing;
}
diff --git a/MaterialDesignThemes.Wpf/DataGridAssist.cs b/MaterialDesignThemes.Wpf/DataGridAssist.cs
index fa62657bc8..578d3b8df5 100644
--- a/MaterialDesignThemes.Wpf/DataGridAssist.cs
+++ b/MaterialDesignThemes.Wpf/DataGridAssist.cs
@@ -1,289 +1,287 @@
-using System;
-using System.Linq;
-using System.Windows;
using System.Windows.Controls;
-using System.Windows.Controls.Primitives;
-using System.Windows.Input;
using System.Windows.Media;
-namespace MaterialDesignThemes.Wpf
+namespace MaterialDesignThemes.Wpf;
+
+public static class DataGridAssist
{
- public static class DataGridAssist
- {
- private static readonly Thickness DefaultCellPaddingThickness = new Thickness(16, 8, 16, 8);
- private static readonly Thickness DefaultColumnHeaderPadding = new Thickness(16, 10, 16, 10);
- private static readonly CornerRadius DefaultCornerRadius = new CornerRadius(4);
+ private static readonly Thickness DefaultCellPaddingThickness = new Thickness(16, 8, 16, 8);
+ private static readonly Thickness DefaultColumnHeaderPadding = new Thickness(16, 10, 16, 10);
+ private static readonly CornerRadius DefaultCornerRadius = new CornerRadius(4);
- #region AttachedProperty : AutoGeneratedCheckboxStyleProperty
- public static readonly DependencyProperty AutoGeneratedCheckBoxStyleProperty
- = DependencyProperty.RegisterAttached("AutoGeneratedCheckBoxStyle", typeof(Style), typeof(DataGridAssist),
- new PropertyMetadata(default(Style), AutoGeneratedCheckBoxStylePropertyChangedCallback));
+ #region AttachedProperty : AutoGeneratedCheckboxStyleProperty
+ public static readonly DependencyProperty AutoGeneratedCheckBoxStyleProperty
+ = DependencyProperty.RegisterAttached("AutoGeneratedCheckBoxStyle", typeof(Style), typeof(DataGridAssist),
+ new PropertyMetadata(default(Style), AutoGeneratedCheckBoxStylePropertyChangedCallback));
- public static Style GetAutoGeneratedCheckBoxStyle(DataGrid element)
- => (Style)element.GetValue(AutoGeneratedCheckBoxStyleProperty);
- public static void SetAutoGeneratedCheckBoxStyle(DataGrid element, Style value)
- => element.SetValue(AutoGeneratedCheckBoxStyleProperty, value);
+ public static Style GetAutoGeneratedCheckBoxStyle(DataGrid element)
+ => (Style)element.GetValue(AutoGeneratedCheckBoxStyleProperty);
+ public static void SetAutoGeneratedCheckBoxStyle(DataGrid element, Style value)
+ => element.SetValue(AutoGeneratedCheckBoxStyleProperty, value);
- private static void AutoGeneratedCheckBoxStylePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- var dataGrid = (DataGrid)d;
+ private static void AutoGeneratedCheckBoxStylePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var dataGrid = (DataGrid)d;
- dataGrid.AutoGeneratingColumn -= SetGeneratedCheckboxColumnStyle;
- dataGrid.AutoGeneratingColumn += SetGeneratedCheckboxColumnStyle;
- }
+ dataGrid.AutoGeneratingColumn -= SetGeneratedCheckboxColumnStyle;
+ dataGrid.AutoGeneratingColumn += SetGeneratedCheckboxColumnStyle;
+ }
- private static void SetGeneratedCheckboxColumnStyle(object? sender, DataGridAutoGeneratingColumnEventArgs e)
+ private static void SetGeneratedCheckboxColumnStyle(object? sender, DataGridAutoGeneratingColumnEventArgs e)
+ {
+ if (e.Column is DataGridCheckBoxColumn column &&
+ sender is DataGrid dataGrid)
{
- if (e.Column is DataGridCheckBoxColumn column &&
- sender is DataGrid dataGrid)
- {
- column.ElementStyle = GetAutoGeneratedCheckBoxStyle(dataGrid);
- }
+ column.ElementStyle = GetAutoGeneratedCheckBoxStyle(dataGrid);
}
- #endregion
+ }
+ #endregion
- #region AttachedProperty : AutoGeneratedEditingCheckBoxStyleProperty
- public static readonly DependencyProperty AutoGeneratedEditingCheckBoxStyleProperty
- = DependencyProperty.RegisterAttached("AutoGeneratedEditingCheckBoxStyle", typeof(Style), typeof(DataGridAssist),
- new PropertyMetadata(default(Style), AutoGeneratedEditingCheckBoxStylePropertyChangedCallback));
+ #region AttachedProperty : AutoGeneratedEditingCheckBoxStyleProperty
+ public static readonly DependencyProperty AutoGeneratedEditingCheckBoxStyleProperty
+ = DependencyProperty.RegisterAttached("AutoGeneratedEditingCheckBoxStyle", typeof(Style), typeof(DataGridAssist),
+ new PropertyMetadata(default(Style), AutoGeneratedEditingCheckBoxStylePropertyChangedCallback));
- public static Style GetAutoGeneratedEditingCheckBoxStyle(DataGrid element)
- => (Style)element.GetValue(AutoGeneratedEditingCheckBoxStyleProperty);
- public static void SetAutoGeneratedEditingCheckBoxStyle(DataGrid element, Style value)
- => element.SetValue(AutoGeneratedEditingCheckBoxStyleProperty, value);
+ public static Style GetAutoGeneratedEditingCheckBoxStyle(DataGrid element)
+ => (Style)element.GetValue(AutoGeneratedEditingCheckBoxStyleProperty);
+ public static void SetAutoGeneratedEditingCheckBoxStyle(DataGrid element, Style value)
+ => element.SetValue(AutoGeneratedEditingCheckBoxStyleProperty, value);
- private static void AutoGeneratedEditingCheckBoxStylePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- var dataGrid = (DataGrid)d;
+ private static void AutoGeneratedEditingCheckBoxStylePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var dataGrid = (DataGrid)d;
- dataGrid.AutoGeneratingColumn -= SetGeneratedCheckBoxEditingStyle;
- dataGrid.AutoGeneratingColumn += SetGeneratedCheckBoxEditingStyle;
- }
+ dataGrid.AutoGeneratingColumn -= SetGeneratedCheckBoxEditingStyle;
+ dataGrid.AutoGeneratingColumn += SetGeneratedCheckBoxEditingStyle;
+ }
- private static void SetGeneratedCheckBoxEditingStyle(object? sender, DataGridAutoGeneratingColumnEventArgs e)
+ private static void SetGeneratedCheckBoxEditingStyle(object? sender, DataGridAutoGeneratingColumnEventArgs e)
+ {
+ if (e.Column is DataGridCheckBoxColumn column &&
+ sender is DataGrid dataGrid)
{
- if (e.Column is DataGridCheckBoxColumn column &&
- sender is DataGrid dataGrid)
- {
- column.EditingElementStyle = GetAutoGeneratedEditingCheckBoxStyle(dataGrid);
- }
+ column.EditingElementStyle = GetAutoGeneratedEditingCheckBoxStyle(dataGrid);
}
- #endregion
+ }
+ #endregion
- #region AttachedProperty : AutoGeneratedTextStyleProperty
- public static readonly DependencyProperty AutoGeneratedTextStyleProperty
- = DependencyProperty.RegisterAttached("AutoGeneratedTextStyle", typeof(Style), typeof(DataGridAssist),
- new PropertyMetadata(default(Style), AutoGeneratedTextStylePropertyChangedCallback));
+ #region AttachedProperty : AutoGeneratedTextStyleProperty
+ public static readonly DependencyProperty AutoGeneratedTextStyleProperty
+ = DependencyProperty.RegisterAttached("AutoGeneratedTextStyle", typeof(Style), typeof(DataGridAssist),
+ new PropertyMetadata(default(Style), AutoGeneratedTextStylePropertyChangedCallback));
- public static Style GetAutoGeneratedTextStyle(DataGrid element)
- => (Style)element.GetValue(AutoGeneratedTextStyleProperty);
- public static void SetAutoGeneratedTextStyle(DataGrid element, Style value)
- => element.SetValue(AutoGeneratedTextStyleProperty, value);
+ public static Style GetAutoGeneratedTextStyle(DataGrid element)
+ => (Style)element.GetValue(AutoGeneratedTextStyleProperty);
+ public static void SetAutoGeneratedTextStyle(DataGrid element, Style value)
+ => element.SetValue(AutoGeneratedTextStyleProperty, value);
- private static void AutoGeneratedTextStylePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- var dataGrid = (DataGrid)d;
+ private static void AutoGeneratedTextStylePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var dataGrid = (DataGrid)d;
- dataGrid.AutoGeneratingColumn -= SetGeneratedTextColumnStyle;
- dataGrid.AutoGeneratingColumn += SetGeneratedTextColumnStyle;
- }
+ dataGrid.AutoGeneratingColumn -= SetGeneratedTextColumnStyle;
+ dataGrid.AutoGeneratingColumn += SetGeneratedTextColumnStyle;
+ }
- private static void SetGeneratedTextColumnStyle(object? sender, DataGridAutoGeneratingColumnEventArgs e)
+ private static void SetGeneratedTextColumnStyle(object? sender, DataGridAutoGeneratingColumnEventArgs e)
+ {
+ if (e.Column is System.Windows.Controls.DataGridTextColumn column &&
+ sender is DataGrid dataGrid)
{
- if (e.Column is System.Windows.Controls.DataGridTextColumn column &&
- sender is DataGrid dataGrid)
- {
- column.ElementStyle = GetAutoGeneratedTextStyle(dataGrid);
- }
+ column.ElementStyle = GetAutoGeneratedTextStyle(dataGrid);
}
- #endregion
+ }
+ #endregion
- #region AttachedProperty : AutoGeneratedEditingTextStyleProperty
- public static readonly DependencyProperty AutoGeneratedEditingTextStyleProperty
- = DependencyProperty.RegisterAttached("AutoGeneratedEditingTextStyle", typeof(Style), typeof(DataGridAssist),
- new PropertyMetadata(default(Style), AutoGeneratedEditingTextStylePropertyChangedCallback));
+ #region AttachedProperty : AutoGeneratedEditingTextStyleProperty
+ public static readonly DependencyProperty AutoGeneratedEditingTextStyleProperty
+ = DependencyProperty.RegisterAttached("AutoGeneratedEditingTextStyle", typeof(Style), typeof(DataGridAssist),
+ new PropertyMetadata(default(Style), AutoGeneratedEditingTextStylePropertyChangedCallback));
- public static Style GetAutoGeneratedEditingTextStyle(DataGrid element)
- => (Style)element.GetValue(AutoGeneratedEditingTextStyleProperty);
- public static void SetAutoGeneratedEditingTextStyle(DataGrid element, Style value)
- => element.SetValue(AutoGeneratedEditingTextStyleProperty, value);
+ public static Style GetAutoGeneratedEditingTextStyle(DataGrid element)
+ => (Style)element.GetValue(AutoGeneratedEditingTextStyleProperty);
+ public static void SetAutoGeneratedEditingTextStyle(DataGrid element, Style value)
+ => element.SetValue(AutoGeneratedEditingTextStyleProperty, value);
- private static void AutoGeneratedEditingTextStylePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- var dataGrid = (DataGrid)d;
+ private static void AutoGeneratedEditingTextStylePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var dataGrid = (DataGrid)d;
- dataGrid.AutoGeneratingColumn -= SetGeneratedTextColumnEditingStyle;
- dataGrid.AutoGeneratingColumn += SetGeneratedTextColumnEditingStyle;
+ dataGrid.AutoGeneratingColumn -= SetGeneratedTextColumnEditingStyle;
+ dataGrid.AutoGeneratingColumn += SetGeneratedTextColumnEditingStyle;
+ }
+
+ private static void SetGeneratedTextColumnEditingStyle(object? sender, DataGridAutoGeneratingColumnEventArgs e)
+ {
+ if (e.Column is System.Windows.Controls.DataGridTextColumn column &&
+ sender is DataGrid dataGrid)
+ {
+ column.EditingElementStyle = GetAutoGeneratedEditingTextStyle(dataGrid);
}
+ }
+ #endregion
+
+ #region AttachedProperty : CellPaddingProperty
+ public static readonly DependencyProperty CellPaddingProperty
+ = DependencyProperty.RegisterAttached("CellPadding", typeof(Thickness), typeof(DataGridAssist),
+ new FrameworkPropertyMetadata(DefaultCellPaddingThickness, FrameworkPropertyMetadataOptions.Inherits));
+
+ public static Thickness GetCellPadding(DataGrid element)
+ => (Thickness)element.GetValue(CellPaddingProperty);
+ public static void SetCellPadding(DataGrid element, Thickness value)
+ => element.SetValue(CellPaddingProperty, value);
+ #endregion
+
+ #region AttachedProperty : SelectedCellBorderBrushProperty
+ public static readonly DependencyProperty SelectedCellBorderBrushProperty
+ = DependencyProperty.RegisterAttached("SelectedCellBorderBrush", typeof(Brush), typeof(DataGridAssist),
+ new PropertyMetadata(null));
+
+ public static Brush GetSelectedCellBorderBrush(DataGrid element)
+ => (Brush)element.GetValue(SelectedCellBorderBrushProperty);
+ public static void SetSelectedCellBorderBrush(DataGrid element, Brush value)
+ => element.SetValue(SelectedCellBorderBrushProperty, value);
+ #endregion
+
+ #region AttachedProperty : ColumnHeaderPaddingProperty
+ public static readonly DependencyProperty ColumnHeaderPaddingProperty
+ = DependencyProperty.RegisterAttached("ColumnHeaderPadding", typeof(Thickness), typeof(DataGridAssist),
+ new FrameworkPropertyMetadata(DefaultColumnHeaderPadding, FrameworkPropertyMetadataOptions.Inherits));
+
+ public static Thickness GetColumnHeaderPadding(DataGrid element)
+ => (Thickness)element.GetValue(ColumnHeaderPaddingProperty);
+ public static void SetColumnHeaderPadding(DependencyObject element, Thickness value)
+ => element.SetValue(ColumnHeaderPaddingProperty, value);
+ #endregion
+
+ #region AttachedProperty : EnableEditBoxAssistProperty
+ public static readonly DependencyProperty EnableEditBoxAssistProperty
+ = DependencyProperty.RegisterAttached("EnableEditBoxAssist", typeof(bool), typeof(DataGridAssist),
+ new PropertyMetadata(default(bool), EnableEditBoxAssistPropertyChangedCallback));
+
+ public static bool GetEnableEditBoxAssist(DataGrid element)
+ => (bool)element.GetValue(EnableEditBoxAssistProperty);
+ public static void SetEnableEditBoxAssist(DataGrid element, bool value)
+ => element.SetValue(EnableEditBoxAssistProperty, value);
+
+ private static void EnableEditBoxAssistPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var dataGrid = (DataGrid)d;
+ var enableCheckBoxAssist = (bool)e.NewValue;
- private static void SetGeneratedTextColumnEditingStyle(object? sender, DataGridAutoGeneratingColumnEventArgs e)
+ if (enableCheckBoxAssist)
{
- if (e.Column is System.Windows.Controls.DataGridTextColumn column &&
- sender is DataGrid dataGrid)
- {
- column.EditingElementStyle = GetAutoGeneratedEditingTextStyle(dataGrid);
- }
+ // Register for bubbling events from cells, even when the cell handles them (thus the 'true' parameter)
+ dataGrid.AddHandler(UIElement.MouseLeftButtonDownEvent, (RoutedEventHandler)OnMouseLeftButtonDown, true);
+ dataGrid.PreviewKeyDown += EditOnSpacebarPress;
}
- #endregion
-
- #region AttachedProperty : CellPaddingProperty
- public static readonly DependencyProperty CellPaddingProperty
- = DependencyProperty.RegisterAttached("CellPadding", typeof(Thickness), typeof(DataGridAssist),
- new FrameworkPropertyMetadata(DefaultCellPaddingThickness, FrameworkPropertyMetadataOptions.Inherits));
-
- public static Thickness GetCellPadding(DataGrid element)
- => (Thickness)element.GetValue(CellPaddingProperty);
- public static void SetCellPadding(DataGrid element, Thickness value)
- => element.SetValue(CellPaddingProperty, value);
- #endregion
-
- #region AttachedProperty : SelectedCellBorderBrushProperty
- public static readonly DependencyProperty SelectedCellBorderBrushProperty
- = DependencyProperty.RegisterAttached("SelectedCellBorderBrush", typeof(Brush), typeof(DataGridAssist),
- new PropertyMetadata(null));
-
- public static Brush GetSelectedCellBorderBrush(DataGrid element)
- => (Brush)element.GetValue(SelectedCellBorderBrushProperty);
- public static void SetSelectedCellBorderBrush(DataGrid element, Brush value)
- => element.SetValue(SelectedCellBorderBrushProperty, value);
- #endregion
-
- #region AttachedProperty : ColumnHeaderPaddingProperty
- public static readonly DependencyProperty ColumnHeaderPaddingProperty
- = DependencyProperty.RegisterAttached("ColumnHeaderPadding", typeof(Thickness), typeof(DataGridAssist),
- new FrameworkPropertyMetadata(DefaultColumnHeaderPadding, FrameworkPropertyMetadataOptions.Inherits));
-
- public static Thickness GetColumnHeaderPadding(DataGrid element)
- => (Thickness)element.GetValue(ColumnHeaderPaddingProperty);
- public static void SetColumnHeaderPadding(DependencyObject element, Thickness value)
- => element.SetValue(ColumnHeaderPaddingProperty, value);
- #endregion
-
- #region AttachedProperty : EnableEditBoxAssistProperty
- public static readonly DependencyProperty EnableEditBoxAssistProperty
- = DependencyProperty.RegisterAttached("EnableEditBoxAssist", typeof(bool), typeof(DataGridAssist),
- new PropertyMetadata(default(bool), EnableEditBoxAssistPropertyChangedCallback));
-
- public static bool GetEnableEditBoxAssist(DataGrid element)
- => (bool)element.GetValue(EnableEditBoxAssistProperty);
- public static void SetEnableEditBoxAssist(DataGrid element, bool value)
- => element.SetValue(EnableEditBoxAssistProperty, value);
-
- private static void EnableEditBoxAssistPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ else
{
- var dataGrid = (DataGrid)d;
- var enableCheckBoxAssist = (bool)e.NewValue;
-
- if (enableCheckBoxAssist)
- {
- dataGrid.PreviewMouseLeftButtonDown += AllowDirectEditWithoutFocus;
- dataGrid.KeyDown += EditOnSpacebarPress;
- }
- else
- {
- dataGrid.PreviewMouseLeftButtonDown -= AllowDirectEditWithoutFocus;
- dataGrid.KeyDown -= EditOnSpacebarPress;
- }
+ dataGrid.RemoveHandler(UIElement.MouseLeftButtonDownEvent, (RoutedEventHandler)OnMouseLeftButtonDown);
+ dataGrid.PreviewKeyDown -= EditOnSpacebarPress;
}
- #endregion
+ }
- #region AttachedProperty : CornerRadiusProperty
- public static readonly DependencyProperty CornerRadiusProperty
- = DependencyProperty.RegisterAttached("CornerRadius", typeof(CornerRadius), typeof(DataGridAssist),
- new PropertyMetadata(DefaultCornerRadius));
+ // This relay is only needed because the UIElement.AddHandler() has strict requirements for the signature of the passed Delegate
+ private static void OnMouseLeftButtonDown(object sender, RoutedEventArgs e) => AllowDirectEditWithoutFocus(sender, (MouseButtonEventArgs)e);
- public static CornerRadius GetCornerRadius(DataGrid element)
- => (CornerRadius)element.GetValue(CornerRadiusProperty);
- public static void SetCornerRadius(DataGrid element, CornerRadius value)
- => element.SetValue(CornerRadiusProperty, value);
- #endregion
+ #endregion
- private static void EditOnSpacebarPress(object sender, KeyEventArgs e)
- {
- var dataGrid = (DataGrid)sender;
+ #region AttachedProperty : CornerRadiusProperty
+ public static readonly DependencyProperty CornerRadiusProperty
+ = DependencyProperty.RegisterAttached("CornerRadius", typeof(CornerRadius), typeof(DataGridAssist),
+ new PropertyMetadata(DefaultCornerRadius));
- if (e.Key == Key.Space && e.OriginalSource is DataGridCell cell
- && !cell.IsReadOnly && cell.Column is DataGridComboBoxColumn)
+ public static CornerRadius GetCornerRadius(DataGrid element)
+ => (CornerRadius)element.GetValue(CornerRadiusProperty);
+ public static void SetCornerRadius(DataGrid element, CornerRadius value)
+ => element.SetValue(CornerRadiusProperty, value);
+ #endregion
+
+ private static void EditOnSpacebarPress(object sender, KeyEventArgs e)
+ {
+ var dataGrid = (DataGrid)sender;
+ if (e.Key == Key.Space && e.OriginalSource is DataGridCell { IsReadOnly: false } cell)
+ {
+ if (cell.Column is DataGridComboBoxColumn ||
+ cell.Column is System.Windows.Controls.DataGridTextColumn)
{
dataGrid.BeginEdit();
+ e.Handled = true;
}
}
+ }
+
+ ///
+ /// Allows editing of components inside of a data grid cell with a single left click.
+ ///
+ private static void AllowDirectEditWithoutFocus(object sender, MouseButtonEventArgs mouseArgs)
+ {
+ var originalSource = (DependencyObject)mouseArgs.OriginalSource;
+ var dataGridCell = originalSource
+ .GetVisualAncestry()
+ .OfType()
+ .FirstOrDefault();
+
+ // Readonly has to be handled as the pass-through ignores the
+ // cell and interacts directly with the content
+ if (dataGridCell?.IsReadOnly ?? true)
+ {
+ return;
+ }
- ///
- /// Allows editing of components inside of a data grid cell with a single left click.
- ///
- private static void AllowDirectEditWithoutFocus(object sender, MouseButtonEventArgs mouseArgs)
+ if (dataGridCell.Content is UIElement element)
{
- var originalSource = (DependencyObject)mouseArgs.OriginalSource;
- var dataGridCell = originalSource
- .GetVisualAncestry()
- .OfType()
- .FirstOrDefault();
-
- // Readonly has to be handled as the pass-through ignores the
- // cell and interacts directly with the content
- if (dataGridCell?.IsReadOnly ?? true)
+ var dataGrid = (DataGrid)sender;
+ if (dataGridCell.IsEditing)
{
+ // If the cell is already being edited, we don't want to (re)start editing
return;
}
- if (dataGridCell?.Content is UIElement element)
- {
- var dataGrid = (DataGrid)sender;
+ dataGrid.CurrentCell = new DataGridCellInfo(dataGridCell);
+ dataGrid.BeginEdit();
- // Check if the cursor actually hit the element and not just the cell
- var mousePosition = mouseArgs.GetPosition(element);
- var elementHitBox = new Rect(element.RenderSize);
- if (elementHitBox.Contains(mousePosition))
+ switch (dataGridCell.Content)
+ {
+ case TextBoxBase textBox:
{
- // If it is a DataGridTemplateColumn we want the
- // click to be handled naturally by the control
- if (dataGridCell.Column.GetType() == typeof(DataGridTemplateColumn))
- {
- return;
- }
-
- dataGrid.CurrentCell = new DataGridCellInfo(dataGridCell);
- dataGrid.BeginEdit();
- //Begin edit likely changes the visual tree, trigger the mouse down event to cause the DataGrid to adjust selection
+ // Send a 'left-click' routed event to the TextBox to place the I-beam at the position of the mouse cursor
var mouseDownEvent = new MouseButtonEventArgs(mouseArgs.MouseDevice, mouseArgs.Timestamp, mouseArgs.ChangedButton)
{
RoutedEvent = Mouse.MouseDownEvent,
Source = mouseArgs.Source
};
+ textBox.RaiseEvent(mouseDownEvent);
+ break;
+ }
- dataGridCell.RaiseEvent(mouseDownEvent);
-
- switch (dataGridCell?.Content)
+ case ToggleButton toggleButton:
+ {
+ // Check if the cursor actually hit the checkbox and not just the cell
+ var mousePosition = mouseArgs.GetPosition(element);
+ var elementHitBox = new Rect(element.RenderSize);
+ if (elementHitBox.Contains(mousePosition))
{
- // Send a 'left click' routed command to the toggleButton
- case ToggleButton toggleButton:
- {
- var newMouseEvent = new MouseButtonEventArgs(mouseArgs.MouseDevice, 0, MouseButton.Left)
- {
- RoutedEvent = Mouse.MouseDownEvent,
- Source = dataGrid
- };
-
- toggleButton.RaiseEvent(newMouseEvent);
- break;
- }
-
- // Open the dropdown explicitly. Left clicking is not
- // viable, as it would edit the text and not open the
- // dropdown
- case ComboBox comboBox:
- {
- comboBox.IsDropDownOpen = true;
- mouseArgs.Handled = true;
- break;
- }
-
- default:
- {
- break;
- }
+ // Send a 'left click' routed command to the toggleButton to toggle the state
+ var newMouseEvent = new MouseButtonEventArgs(mouseArgs.MouseDevice, mouseArgs.Timestamp, mouseArgs.ChangedButton)
+ {
+ RoutedEvent = Mouse.MouseDownEvent,
+ Source = dataGrid
+ };
+
+ toggleButton.RaiseEvent(newMouseEvent);
}
+ break;
+ }
+
+ // Open the dropdown explicitly. Left clicking is not
+ // viable, as it would edit the text and not open the
+ // dropdown
+ case ComboBox comboBox:
+ {
+ comboBox.IsDropDownOpen = true;
+ break;
}
}
}
diff --git a/MaterialDesignThemes.Wpf/HintProxyFabric.PasswordBox.cs b/MaterialDesignThemes.Wpf/HintProxyFabric.PasswordBox.cs
index b0e2a85e52..8ef0100ebc 100644
--- a/MaterialDesignThemes.Wpf/HintProxyFabric.PasswordBox.cs
+++ b/MaterialDesignThemes.Wpf/HintProxyFabric.PasswordBox.cs
@@ -1,68 +1,55 @@
-using System;
-using System.Windows.Controls;
+namespace MaterialDesignThemes.Wpf;
-namespace MaterialDesignThemes.Wpf
+public static partial class HintProxyFabric
{
- public static partial class HintProxyFabric
+ private sealed class PasswordBoxHintProxy : IHintProxy
{
- private sealed class PasswordBoxHintProxy : IHintProxy
- {
- private readonly PasswordBox _passwordBox;
-
- public bool IsEmpty() => string.IsNullOrEmpty(_passwordBox.Password);
+ private readonly PasswordBox _passwordBox;
- public object Content => _passwordBox.Password;
+ public bool IsEmpty() => string.IsNullOrEmpty(_passwordBox.Password);
- public bool IsLoaded => _passwordBox.IsLoaded;
+ public object Content => _passwordBox.Password;
- public bool IsVisible => _passwordBox.IsVisible;
+ public bool IsLoaded => _passwordBox.IsLoaded;
- public bool IsFocused() => _passwordBox.IsKeyboardFocused;
+ public bool IsVisible => _passwordBox.IsVisible;
- public event EventHandler? ContentChanged;
- public event EventHandler? IsVisibleChanged;
- public event EventHandler? Loaded;
- public event EventHandler? FocusedChanged;
+ public bool IsFocused() => _passwordBox.IsKeyboardFocusWithin;
- public PasswordBoxHintProxy(PasswordBox passwordBox)
- {
- if (passwordBox is null) throw new ArgumentNullException(nameof(passwordBox));
+ public event EventHandler? ContentChanged;
+ public event EventHandler? IsVisibleChanged;
+ public event EventHandler? Loaded;
+ public event EventHandler? FocusedChanged;
- _passwordBox = passwordBox;
- _passwordBox.PasswordChanged += PasswordBoxPasswordChanged;
- _passwordBox.Loaded += PasswordBoxLoaded;
- _passwordBox.IsVisibleChanged += PasswordBoxIsVisibleChanged;
- _passwordBox.IsKeyboardFocusedChanged += PasswordBoxIsKeyboardFocusedChanged;
- }
+ public PasswordBoxHintProxy(PasswordBox passwordBox)
+ {
+ if (passwordBox is null) throw new ArgumentNullException(nameof(passwordBox));
- private void PasswordBoxIsKeyboardFocusedChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e)
- {
- FocusedChanged?.Invoke(this, EventArgs.Empty);
- }
+ _passwordBox = passwordBox;
+ _passwordBox.PasswordChanged += PasswordBoxPasswordChanged;
+ _passwordBox.Loaded += PasswordBoxLoaded;
+ _passwordBox.IsVisibleChanged += PasswordBoxIsVisibleChanged;
+ _passwordBox.IsKeyboardFocusWithinChanged += PasswordBoxIsKeyboardFocusedChanged;
+ }
- private void PasswordBoxIsVisibleChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e)
- {
- IsVisibleChanged?.Invoke(this, EventArgs.Empty);
- }
+ private void PasswordBoxIsKeyboardFocusedChanged(object sender, DependencyPropertyChangedEventArgs e)
+ => FocusedChanged?.Invoke(this, EventArgs.Empty);
- private void PasswordBoxLoaded(object sender, System.Windows.RoutedEventArgs e)
- {
- Loaded?.Invoke(this, EventArgs.Empty);
- }
+ private void PasswordBoxIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
+ => IsVisibleChanged?.Invoke(this, EventArgs.Empty);
- private void PasswordBoxPasswordChanged(object sender, System.Windows.RoutedEventArgs e)
- {
- ContentChanged?.Invoke(this, EventArgs.Empty);
- }
+ private void PasswordBoxLoaded(object sender, RoutedEventArgs e)
+ => Loaded?.Invoke(this, EventArgs.Empty);
- public void Dispose()
- {
- _passwordBox.PasswordChanged -= PasswordBoxPasswordChanged;
- _passwordBox.Loaded -= PasswordBoxLoaded;
- _passwordBox.IsVisibleChanged -= PasswordBoxIsVisibleChanged;
- _passwordBox.IsKeyboardFocusedChanged -= PasswordBoxIsKeyboardFocusedChanged;
- }
+ private void PasswordBoxPasswordChanged(object sender, RoutedEventArgs e)
+ => ContentChanged?.Invoke(this, EventArgs.Empty);
+ public void Dispose()
+ {
+ _passwordBox.PasswordChanged -= PasswordBoxPasswordChanged;
+ _passwordBox.Loaded -= PasswordBoxLoaded;
+ _passwordBox.IsVisibleChanged -= PasswordBoxIsVisibleChanged;
+ _passwordBox.IsKeyboardFocusWithinChanged -= PasswordBoxIsKeyboardFocusedChanged;
}
}
}
\ No newline at end of file
diff --git a/MaterialDesignThemes.Wpf/HintProxyFabric.TextBox.cs b/MaterialDesignThemes.Wpf/HintProxyFabric.TextBox.cs
index 455fc23aa3..9e9eeb5a92 100644
--- a/MaterialDesignThemes.Wpf/HintProxyFabric.TextBox.cs
+++ b/MaterialDesignThemes.Wpf/HintProxyFabric.TextBox.cs
@@ -1,56 +1,51 @@
-using System;
-using System.Windows;
-using System.Windows.Controls;
+namespace MaterialDesignThemes.Wpf;
-namespace MaterialDesignThemes.Wpf
+public static partial class HintProxyFabric
{
- public static partial class HintProxyFabric
+ private sealed class TextBoxHintProxy : IHintProxy
{
- private sealed class TextBoxHintProxy : IHintProxy
- {
- private readonly TextBox _textBox;
+ private readonly TextBox _textBox;
- public bool IsLoaded => _textBox.IsLoaded;
+ public bool IsLoaded => _textBox.IsLoaded;
- public bool IsVisible => _textBox.IsVisible;
+ public bool IsVisible => _textBox.IsVisible;
- public bool IsEmpty() => string.IsNullOrEmpty(_textBox.Text);
+ public bool IsEmpty() => string.IsNullOrEmpty(_textBox.Text);
- public bool IsFocused() => _textBox.IsKeyboardFocused;
+ public bool IsFocused() => _textBox.IsKeyboardFocusWithin;
- public event EventHandler? ContentChanged;
- public event EventHandler? IsVisibleChanged;
- public event EventHandler? Loaded;
- public event EventHandler? FocusedChanged;
+ public event EventHandler? ContentChanged;
+ public event EventHandler? IsVisibleChanged;
+ public event EventHandler? Loaded;
+ public event EventHandler? FocusedChanged;
- public TextBoxHintProxy(TextBox textBox)
- {
- _textBox = textBox ?? throw new ArgumentNullException(nameof(textBox));
- _textBox.TextChanged += TextBoxTextChanged;
- _textBox.Loaded += TextBoxLoaded;
- _textBox.IsVisibleChanged += TextBoxIsVisibleChanged;
- _textBox.IsKeyboardFocusedChanged += TextBoxIsKeyboardFocusedChanged;
- }
+ public TextBoxHintProxy(TextBox textBox)
+ {
+ _textBox = textBox ?? throw new ArgumentNullException(nameof(textBox));
+ _textBox.TextChanged += TextBoxTextChanged;
+ _textBox.Loaded += TextBoxLoaded;
+ _textBox.IsVisibleChanged += TextBoxIsVisibleChanged;
+ _textBox.IsKeyboardFocusWithinChanged += TextBoxIsKeyboardFocusedChanged;
+ }
- private void TextBoxIsKeyboardFocusedChanged(object sender, DependencyPropertyChangedEventArgs e)
- => FocusedChanged?.Invoke(sender, EventArgs.Empty);
+ private void TextBoxIsKeyboardFocusedChanged(object sender, DependencyPropertyChangedEventArgs e)
+ => FocusedChanged?.Invoke(sender, EventArgs.Empty);
- private void TextBoxIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
- => IsVisibleChanged?.Invoke(sender, EventArgs.Empty);
+ private void TextBoxIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
+ => IsVisibleChanged?.Invoke(sender, EventArgs.Empty);
- private void TextBoxLoaded(object sender, RoutedEventArgs e)
- => Loaded?.Invoke(sender, EventArgs.Empty);
+ private void TextBoxLoaded(object sender, RoutedEventArgs e)
+ => Loaded?.Invoke(sender, EventArgs.Empty);
- private void TextBoxTextChanged(object sender, TextChangedEventArgs e)
- => ContentChanged?.Invoke(sender, EventArgs.Empty);
+ private void TextBoxTextChanged(object sender, TextChangedEventArgs e)
+ => ContentChanged?.Invoke(sender, EventArgs.Empty);
- public void Dispose()
- {
- _textBox.TextChanged -= TextBoxTextChanged;
- _textBox.Loaded -= TextBoxLoaded;
- _textBox.IsVisibleChanged -= TextBoxIsVisibleChanged;
- _textBox.IsKeyboardFocusedChanged -= TextBoxIsKeyboardFocusedChanged;
- }
+ public void Dispose()
+ {
+ _textBox.TextChanged -= TextBoxTextChanged;
+ _textBox.Loaded -= TextBoxLoaded;
+ _textBox.IsVisibleChanged -= TextBoxIsVisibleChanged;
+ _textBox.IsKeyboardFocusWithinChanged -= TextBoxIsKeyboardFocusedChanged;
}
}
}
\ No newline at end of file
diff --git a/MaterialDesignThemes.Wpf/HintProxyFabric.cs b/MaterialDesignThemes.Wpf/HintProxyFabric.cs
index aaba18ad77..8b045c463f 100644
--- a/MaterialDesignThemes.Wpf/HintProxyFabric.cs
+++ b/MaterialDesignThemes.Wpf/HintProxyFabric.cs
@@ -1,45 +1,39 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Windows.Controls;
+namespace MaterialDesignThemes.Wpf;
-namespace MaterialDesignThemes.Wpf
+public static partial class HintProxyFabric
{
- public static partial class HintProxyFabric
+ private sealed class HintProxyBuilder
{
- private sealed class HintProxyBuilder
- {
- private readonly Func _canBuild;
- private readonly Func _build;
-
- public HintProxyBuilder(Func canBuild, Func build)
- {
- _canBuild = canBuild ?? throw new ArgumentNullException(nameof(canBuild));
- _build = build ?? throw new ArgumentNullException(nameof(build));
- }
+ private readonly Func _canBuild;
+ private readonly Func _build;
- public bool CanBuild(Control? control) => _canBuild(control);
- public IHintProxy? Build(Control control) => _build(control);
+ public HintProxyBuilder(Func canBuild, Func build)
+ {
+ _canBuild = canBuild ?? throw new ArgumentNullException(nameof(canBuild));
+ _build = build ?? throw new ArgumentNullException(nameof(build));
}
- private static readonly List Builders = new List();
+ public bool CanBuild(Control? control) => _canBuild(control);
+ public IHintProxy? Build(Control control) => _build(control);
+ }
- static HintProxyFabric()
- {
- Builders.Add(new HintProxyBuilder(c => c is ComboBox, c => new ComboBoxHintProxy((ComboBox)c)));
- Builders.Add(new HintProxyBuilder(c => c is TextBox, c => new TextBoxHintProxy((TextBox)c)));
- Builders.Add(new HintProxyBuilder(c => c is RichTextBox, c => new RichTextBoxHintProxy((RichTextBox)c)));
- Builders.Add(new HintProxyBuilder(c => c is PasswordBox, c => new PasswordBoxHintProxy((PasswordBox)c)));
- }
+ private static readonly List Builders = new();
- public static void RegisterBuilder(Func canBuild, Func build)
- => Builders.Add(new HintProxyBuilder(canBuild, build));
+ static HintProxyFabric()
+ {
+ Builders.Add(new HintProxyBuilder(c => c is ComboBox, c => new ComboBoxHintProxy((ComboBox)c)));
+ Builders.Add(new HintProxyBuilder(c => c is TextBox, c => new TextBoxHintProxy((TextBox)c)));
+ Builders.Add(new HintProxyBuilder(c => c is RichTextBox, c => new RichTextBoxHintProxy((RichTextBox)c)));
+ Builders.Add(new HintProxyBuilder(c => c is PasswordBox, c => new PasswordBoxHintProxy((PasswordBox)c)));
+ }
- public static IHintProxy? Get(Control? control)
- {
- if (control is null) return null;
- var builder = Builders.FirstOrDefault(v => v.CanBuild(control));
- return builder?.Build(control);
- }
+ public static void RegisterBuilder(Func canBuild, Func build)
+ => Builders.Add(new HintProxyBuilder(canBuild, build));
+
+ public static IHintProxy? Get(Control? control)
+ {
+ if (control is null) return null;
+ var builder = Builders.FirstOrDefault(v => v.CanBuild(control));
+ return builder?.Build(control);
}
}
diff --git a/MaterialDesignThemes.Wpf/IHintProxy.cs b/MaterialDesignThemes.Wpf/IHintProxy.cs
index 23a9404ae6..cf528df981 100644
--- a/MaterialDesignThemes.Wpf/IHintProxy.cs
+++ b/MaterialDesignThemes.Wpf/IHintProxy.cs
@@ -1,38 +1,34 @@
-using System;
-using System.Windows.Controls;
-
-namespace MaterialDesignThemes.Wpf
+namespace MaterialDesignThemes.Wpf;
+
+///
+/// This interface is the adapter from UiControl (like , and others) to
+///
+/// You should implement this interface in order to use SmartHint for your own control.
+///
+public interface IHintProxy : IDisposable
{
///
- /// This interface is the adapter from UiControl (like , and others) to
- ///
- /// You should implement this interface in order to use SmartHint for your own control.
+ /// Checks to see if the targeted control can be deemed as logically
+ /// empty, even if not null, affecting the current hint display.
///
- public interface IHintProxy : IDisposable
- {
- ///
- /// Checks to see if the targeted control can be deemed as logically
- /// empty, even if not null, affecting the current hint display.
- ///
- ///
- bool IsEmpty();
+ ///
+ bool IsEmpty();
- ///
- /// Targeted control has keyboard focus
- ///
- ///
- bool IsFocused();
+ ///
+ /// Targeted control has keyboard focus
+ ///
+ ///
+ bool IsFocused();
- bool IsLoaded { get; }
+ bool IsLoaded { get; }
- bool IsVisible { get; }
+ bool IsVisible { get; }
- event EventHandler? ContentChanged;
+ event EventHandler? ContentChanged;
- event EventHandler? IsVisibleChanged;
+ event EventHandler? IsVisibleChanged;
- event EventHandler? Loaded;
+ event EventHandler? Loaded;
- event EventHandler? FocusedChanged;
- }
+ event EventHandler? FocusedChanged;
}
diff --git a/MaterialDesignThemes.Wpf/PackIconKind.cs b/MaterialDesignThemes.Wpf/PackIconKind.cs
index de29ee8adf..bae8f655f2 100644
--- a/MaterialDesignThemes.Wpf/PackIconKind.cs
+++ b/MaterialDesignThemes.Wpf/PackIconKind.cs
@@ -10314,7 +10314,9 @@ public enum PackIconKind
RomanNumeral8,
RomanNumeral9,
RoomService,
+ CallBell=RoomService,
RoomServiceOutline,
+ CallBellOutline=RoomServiceOutline,
Rotate360,
Rotate3d,
Rotate3dVariant,
diff --git a/MaterialDesignThemes.Wpf/PasswordBoxAssist.cs b/MaterialDesignThemes.Wpf/PasswordBoxAssist.cs
new file mode 100644
index 0000000000..9a6a104cd9
--- /dev/null
+++ b/MaterialDesignThemes.Wpf/PasswordBoxAssist.cs
@@ -0,0 +1,68 @@
+using System.Windows.Data;
+
+namespace MaterialDesignThemes.Wpf;
+
+public static class PasswordBoxAssist
+{
+ public static readonly DependencyProperty PasswordMaskedIconProperty = DependencyProperty.RegisterAttached(
+ "PasswordMaskedIcon", typeof(PackIconKind), typeof(PasswordBoxAssist), new FrameworkPropertyMetadata(PackIconKind.EyeOff, FrameworkPropertyMetadataOptions.Inherits));
+ public static void SetPasswordMaskedIcon(DependencyObject element, PackIconKind value) => element.SetValue(PasswordMaskedIconProperty, value);
+ public static PackIconKind GetPasswordMaskedIcon(DependencyObject element) => (PackIconKind) element.GetValue(PasswordMaskedIconProperty);
+
+ public static readonly DependencyProperty PasswordRevealedIconProperty = DependencyProperty.RegisterAttached(
+ "PasswordRevealedIcon", typeof(PackIconKind), typeof(PasswordBoxAssist), new FrameworkPropertyMetadata(PackIconKind.Eye, FrameworkPropertyMetadataOptions.Inherits));
+ public static void SetPasswordRevealedIcon(DependencyObject element, PackIconKind value) => element.SetValue(PasswordRevealedIconProperty, value);
+ public static PackIconKind GetPasswordRevealedIcon(DependencyObject element) => (PackIconKind) element.GetValue(PasswordRevealedIconProperty);
+
+ public static readonly DependencyProperty IsPasswordRevealedProperty = DependencyProperty.RegisterAttached(
+ "IsPasswordRevealed", typeof(bool), typeof(PasswordBoxAssist), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits));
+ public static void SetIsPasswordRevealed(DependencyObject element, bool value) => element.SetValue(IsPasswordRevealedProperty, value);
+ public static bool GetIsPasswordRevealed(DependencyObject element) => (bool) element.GetValue(IsPasswordRevealedProperty);
+
+ public static readonly DependencyProperty PasswordProperty = DependencyProperty.RegisterAttached(
+ "Password", typeof(string), typeof(PasswordBoxAssist), new FrameworkPropertyMetadata(null, HandlePasswordChanged) { BindsTwoWayByDefault = true, DefaultUpdateSourceTrigger = UpdateSourceTrigger.LostFocus });
+ public static void SetPassword(DependencyObject element, string value) => element.SetValue(PasswordProperty, value);
+ public static string GetPassword(DependencyObject element) => (string) element.GetValue(PasswordProperty);
+
+ // Internal attached DP used to initially wire up the connection between the masked PasswordBox content and the clear text TextBox content
+ internal static readonly DependencyProperty InitialPasswordProperty = DependencyProperty.RegisterAttached(
+ "InitialPassword", typeof(string), typeof(PasswordBoxAssist), new PropertyMetadata(default(string)));
+ internal static void SetInitialPassword(DependencyObject element, string value) => element.SetValue(InitialPasswordProperty, value);
+ internal static string GetInitialPassword(DependencyObject element) => (string)element.GetValue(InitialPasswordProperty);
+
+ private static readonly DependencyProperty IsPasswordInitializedProperty = DependencyProperty.RegisterAttached(
+ "IsPasswordInitialized", typeof(bool), typeof(PasswordBoxAssist), new PropertyMetadata(false));
+
+ private static readonly DependencyProperty SettingPasswordProperty = DependencyProperty.RegisterAttached(
+ "SettingPassword", typeof(bool), typeof(PasswordBoxAssist), new PropertyMetadata(false));
+
+ private static void HandlePasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is not PasswordBox passwordBox)
+ return;
+
+ if ((bool)passwordBox.GetValue(SettingPasswordProperty))
+ return;
+
+ if (!(bool)passwordBox.GetValue(IsPasswordInitializedProperty))
+ {
+ passwordBox.SetValue(IsPasswordInitializedProperty, true);
+ WeakEventManager.AddHandler(passwordBox, nameof(PasswordBox.PasswordChanged), HandlePasswordChanged);
+ }
+ passwordBox.Password = e.NewValue as string;
+ }
+
+ private static void HandlePasswordChanged(object? sender, RoutedEventArgs e)
+ {
+ if (sender is not PasswordBox passwordBox)
+ return;
+
+ passwordBox.SetValue(SettingPasswordProperty, true);
+ string currentPassword = GetPassword(passwordBox);
+ if (currentPassword != passwordBox.Password)
+ {
+ SetPassword(passwordBox, passwordBox.Password);
+ }
+ passwordBox.SetValue(SettingPasswordProperty, false);
+ }
+}
\ No newline at end of file
diff --git a/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.DialogHost.xaml b/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.DialogHost.xaml
index 333e3a3c2a..08cc1319a4 100644
--- a/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.DialogHost.xaml
+++ b/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.DialogHost.xaml
@@ -341,7 +341,7 @@
Duration="0">
-
diff --git a/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.PasswordBox.xaml b/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.PasswordBox.xaml
index 87cb270598..9bd7965052 100644
--- a/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.PasswordBox.xaml
+++ b/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.PasswordBox.xaml
@@ -1,4 +1,4 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.TextBox.xaml b/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.TextBox.xaml
index 92be75618f..6cb5b56b35 100644
--- a/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.TextBox.xaml
+++ b/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.TextBox.xaml
@@ -16,6 +16,8 @@
+
+
-
@@ -74,7 +75,7 @@
-
+
+
@@ -413,6 +415,7 @@
+
diff --git a/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.ValidationErrorTemplate.xaml b/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.ValidationErrorTemplate.xaml
index f2f2ef5899..7d151cdc4e 100644
--- a/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.ValidationErrorTemplate.xaml
+++ b/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.ValidationErrorTemplate.xaml
@@ -97,9 +97,13 @@
-
+
+
+
+
+
\ No newline at end of file