diff --git a/BytecodeApi.Wpf.Cui/Controls/ProgressBarState.cs b/BytecodeApi.Wpf.Cui/Controls/ProgressBarState.cs index 21dc958..925fe4e 100644 --- a/BytecodeApi.Wpf.Cui/Controls/ProgressBarState.cs +++ b/BytecodeApi.Wpf.Cui/Controls/ProgressBarState.cs @@ -1,8 +1,22 @@ +using BytecodeApi.Wpf.Cui.Controls; + namespace BytecodeApi.Wpf.Cui; +/// +/// Specifies the state of a . +/// public enum ProgressBarState { - Normal, + /// + /// The is green, indicating a normal state. + /// + Normal, + /// + /// The is red, indicating an error or canceled state. + /// Error, + /// + /// The is yellow, indicating a warning or paused state. + /// Paused } \ No newline at end of file diff --git a/BytecodeApi.Wpf.Cui/Controls/SortAdorner.cs b/BytecodeApi.Wpf.Cui/Controls/SortAdorner.cs index 19de288..17b2aa0 100644 --- a/BytecodeApi.Wpf.Cui/Controls/SortAdorner.cs +++ b/BytecodeApi.Wpf.Cui/Controls/SortAdorner.cs @@ -5,26 +5,41 @@ namespace BytecodeApi.Wpf.Cui.Controls; +/// +/// Represents an adorner that displays a sorting glyph. +/// public sealed class SortAdorner : Adorner { - private static readonly Geometry AscendingGeometry = Geometry.Parse("M 0,6 L0,5 L4,1 L8,5 L8,6 L4,2 z"); - private static readonly Geometry DescendingGeometry = Geometry.Parse("M 0,1 L0,2 L4,6 L8,2 L8,1 L4,5 z"); - public ListSortDirection Direction { get; private init; } + private static readonly Geometry AscendingGeometry = Geometry.Parse("M 0,6 L0,5 L4,1 L8,5 L8,6 L4,2 z"); + private static readonly Geometry DescendingGeometry = Geometry.Parse("M 0,1 L0,2 L4,6 L8,2 L8,1 L4,5 z"); + /// + /// Gets the value that specifies the sorting direction. + /// + public ListSortDirection Direction { get; private init; } - public SortAdorner(UIElement element, ListSortDirection direction) : base(element) - { - Direction = direction; - } + /// + /// Initializes a new instance of the class. + /// + /// The to bind the adorner to. + /// A value that specifies the sorting direction. + public SortAdorner(UIElement element, ListSortDirection direction) : base(element) + { + Direction = direction; + } - protected override void OnRender(DrawingContext drawingContext) - { - base.OnRender(drawingContext); + /// + /// Participates in rendering operations that are directed by the layout system. + /// + /// The drawing instructions for a specific element. This context is provided to the layout system. + protected override void OnRender(DrawingContext drawingContext) + { + base.OnRender(drawingContext); - if (AdornedElement.RenderSize.Width > 15) - { - drawingContext.PushTransform(new TranslateTransform(AdornedElement.RenderSize.Width / 2 - 4, 0)); - drawingContext.DrawGeometry(Brushes.Black, null, Direction == ListSortDirection.Ascending ? AscendingGeometry : DescendingGeometry); - drawingContext.Pop(); - } - } + if (AdornedElement.RenderSize.Width > 15) + { + drawingContext.PushTransform(new TranslateTransform(AdornedElement.RenderSize.Width / 2 - 4, 0)); + drawingContext.DrawGeometry(Brushes.Black, null, Direction == ListSortDirection.Ascending ? AscendingGeometry : DescendingGeometry); + drawingContext.Pop(); + } + } } \ No newline at end of file diff --git a/BytecodeApi.Wpf.Cui/Controls/UiApplicationTabControl.cs b/BytecodeApi.Wpf.Cui/Controls/UiApplicationTabControl.cs index c9de132..77f2e62 100644 --- a/BytecodeApi.Wpf.Cui/Controls/UiApplicationTabControl.cs +++ b/BytecodeApi.Wpf.Cui/Controls/UiApplicationTabControl.cs @@ -4,20 +4,23 @@ namespace BytecodeApi.Wpf.Cui.Controls; +/// +/// Represents a styled for use in a , typically identifying to display the main tab control. +/// public class UiApplicationTabControl : TabControl { - static UiApplicationTabControl() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(UiApplicationTabControl), new FrameworkPropertyMetadata(typeof(UiApplicationTabControl))); - } + static UiApplicationTabControl() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(UiApplicationTabControl), new FrameworkPropertyMetadata(typeof(UiApplicationTabControl))); + } - protected override void OnPreviewMouseDown(MouseButtonEventArgs e) - { - base.OnPreviewMouseDown(e); + protected override void OnPreviewMouseDown(MouseButtonEventArgs e) + { + base.OnPreviewMouseDown(e); - if (!IsKeyboardFocusWithin) - { - Focus(); - } - } + if (!IsKeyboardFocusWithin) + { + Focus(); + } + } } \ No newline at end of file diff --git a/BytecodeApi.Wpf.Cui/Controls/UiApplicationWindow.cs b/BytecodeApi.Wpf.Cui/Controls/UiApplicationWindow.cs index 192802e..6b9cdcd 100644 --- a/BytecodeApi.Wpf.Cui/Controls/UiApplicationWindow.cs +++ b/BytecodeApi.Wpf.Cui/Controls/UiApplicationWindow.cs @@ -10,144 +10,183 @@ namespace BytecodeApi.Wpf.Cui.Controls; +/// +/// Represents the main application window styled using a custom window chrome. +/// public class UiApplicationWindow : ObservableWindow { - private const int CaptionHeight = 37; - private const int CaptionHeightWithMenu = 37; - private const int CaptionHeightWithToolBar = 66; - private const int CaptionHeightWithMenuAndToolBar = 66; - public static readonly DependencyProperty IconControlProperty = DependencyPropertyEx.Register(nameof(IconControl)); - public static readonly DependencyProperty MenuProperty = DependencyPropertyEx.Register(nameof(Menu), new(Menu_Changed)); - public static readonly DependencyProperty ToolBarTrayProperty = DependencyPropertyEx.Register(nameof(ToolBarTray), new(ToolBar_Changed)); - public static readonly DependencyProperty StatusBarProperty = DependencyPropertyEx.Register(nameof(StatusBar)); - private static readonly DependencyPropertyKey ShowResizeGripPropertyKey = DependencyPropertyEx.RegisterReadOnly(nameof(ShowResizeGrip), new FrameworkPropertyMetadata(false)); - public static readonly DependencyProperty ShowResizeGripProperty = ShowResizeGripPropertyKey.DependencyProperty; - public object? IconControl - { - get => GetValue(IconControlProperty); - set => SetValue(IconControlProperty, value); - } - public Menu? Menu - { - get => this.GetValue(MenuProperty); - set => SetValue(MenuProperty, value); - } - public ToolBarTray? ToolBarTray - { - get => this.GetValue(ToolBarTrayProperty); - set => SetValue(ToolBarTrayProperty, value); - } - public StatusBar? StatusBar - { - get => this.GetValue(StatusBarProperty); - set => SetValue(StatusBarProperty, value); - } - public bool ShowResizeGrip - { - get => this.GetValue(ShowResizeGripProperty); - private set => SetValue(ShowResizeGripPropertyKey, value); - } - private ResizeGrip? ResizeGrip; - private CriticalSection ResizeModeCriticalSection = new(); + private const int CaptionHeight = 37; + private const int CaptionHeightWithMenu = 37; + private const int CaptionHeightWithToolBar = 66; + private const int CaptionHeightWithMenuAndToolBar = 66; + /// + /// Identifies the dependency property. This field is read-only. + /// + public static readonly DependencyProperty IconControlProperty = DependencyPropertyEx.Register(nameof(IconControl)); + /// + /// Identifies the dependency property. This field is read-only. + /// + public static readonly DependencyProperty MenuProperty = DependencyPropertyEx.Register(nameof(Menu), new(Menu_Changed)); + /// + /// Identifies the dependency property. This field is read-only. + /// + public static readonly DependencyProperty ToolBarTrayProperty = DependencyPropertyEx.Register(nameof(ToolBarTray), new(ToolBar_Changed)); + /// + /// Identifies the dependency property. This field is read-only. + /// + public static readonly DependencyProperty StatusBarProperty = DependencyPropertyEx.Register(nameof(StatusBar)); + private static readonly DependencyPropertyKey ShowResizeGripPropertyKey = DependencyPropertyEx.RegisterReadOnly(nameof(ShowResizeGrip), new FrameworkPropertyMetadata(false)); + /// + /// Identifies the dependency property. This field is read-only. + /// + public static readonly DependencyProperty ShowResizeGripProperty = ShowResizeGripPropertyKey.DependencyProperty; + /// + /// Gets or sets an object that represents the icon control displayed in the window's title bar. + /// + public object? IconControl + { + get => GetValue(IconControlProperty); + set => SetValue(IconControlProperty, value); + } + /// + /// Gets or sets a control that is displayed below the window's title bar. + /// + public Menu? Menu + { + get => this.GetValue(MenuProperty); + set => SetValue(MenuProperty, value); + } + /// + /// Gets or sets the that is displayed below the main menu. + /// + public ToolBarTray? ToolBarTray + { + get => this.GetValue(ToolBarTrayProperty); + set => SetValue(ToolBarTrayProperty, value); + } + /// + /// Gets or sets the that is displayed at the bottom of the window. + /// + public StatusBar? StatusBar + { + get => this.GetValue(StatusBarProperty); + set => SetValue(StatusBarProperty, value); + } + /// + /// Gets a value that indicates whether the resize grip is shown in the bottom-right corner of the window. + /// + public bool ShowResizeGrip + { + get => this.GetValue(ShowResizeGripProperty); + private set => SetValue(ShowResizeGripPropertyKey, value); + } + private ResizeGrip? ResizeGrip; + private CriticalSection ResizeModeCriticalSection = new(); - static UiApplicationWindow() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(UiApplicationWindow), new FrameworkPropertyMetadata(typeof(UiApplicationWindow))); - ResizeModeProperty.OverrideMetadata(typeof(UiApplicationWindow), new FrameworkPropertyMetadata(ResizeMode_Changed)); - BorderBrushProperty.OverrideMetadata(typeof(UiApplicationWindow), new FrameworkPropertyMetadata(BorderBrush_Changed)); - } - public UiApplicationWindow() - { - CommandBindings.Add(new(SystemCommands.CloseWindowCommand, (sender, e) => SystemCommands.CloseWindow(this))); - CommandBindings.Add(new(SystemCommands.MinimizeWindowCommand, (sender, e) => SystemCommands.MinimizeWindow(this))); - CommandBindings.Add(new(SystemCommands.MaximizeWindowCommand, (sender, e) => SystemCommands.MaximizeWindow(this))); - CommandBindings.Add(new(SystemCommands.RestoreWindowCommand, (sender, e) => SystemCommands.RestoreWindow(this))); + static UiApplicationWindow() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(UiApplicationWindow), new FrameworkPropertyMetadata(typeof(UiApplicationWindow))); + ResizeModeProperty.OverrideMetadata(typeof(UiApplicationWindow), new FrameworkPropertyMetadata(ResizeMode_Changed)); + BorderBrushProperty.OverrideMetadata(typeof(UiApplicationWindow), new FrameworkPropertyMetadata(BorderBrush_Changed)); + } + /// + /// Initializes a new instance of the class. + /// + public UiApplicationWindow() + { + CommandBindings.Add(new(SystemCommands.CloseWindowCommand, (sender, e) => SystemCommands.CloseWindow(this))); + CommandBindings.Add(new(SystemCommands.MinimizeWindowCommand, (sender, e) => SystemCommands.MinimizeWindow(this))); + CommandBindings.Add(new(SystemCommands.MaximizeWindowCommand, (sender, e) => SystemCommands.MaximizeWindow(this))); + CommandBindings.Add(new(SystemCommands.RestoreWindowCommand, (sender, e) => SystemCommands.RestoreWindow(this))); - UpdateWindowChrome(); - } + UpdateWindowChrome(); + } - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); + /// + /// Applies the control template to this . + /// + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); - ResizeGrip = GetTemplateChild("PART_ResizeGrip") as ResizeGrip; - } - protected override void OnSourceInitialized(EventArgs e) - { - base.OnSourceInitialized(e); + ResizeGrip = GetTemplateChild("PART_ResizeGrip") as ResizeGrip; + } + protected override void OnSourceInitialized(EventArgs e) + { + base.OnSourceInitialized(e); - UpdateBorder(); + UpdateBorder(); - if (ResizeGrip != null) - { - WindowChrome.SetResizeGripDirection(ResizeGrip, ResizeGripDirection.BottomRight); - } - } - private static void Menu_Changed(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) - { - UiApplicationWindow window = (UiApplicationWindow)dependencyObject; - window.UpdateCaptionHeight(); - } - private static void ToolBar_Changed(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) - { - UiApplicationWindow window = (UiApplicationWindow)dependencyObject; - window.UpdateCaptionHeight(); - } - private static void ResizeMode_Changed(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) - { - UiApplicationWindow window = (UiApplicationWindow)dependencyObject; + if (ResizeGrip != null) + { + WindowChrome.SetResizeGripDirection(ResizeGrip, ResizeGripDirection.BottomRight); + } + } + private static void Menu_Changed(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) + { + UiApplicationWindow window = (UiApplicationWindow)dependencyObject; + window.UpdateCaptionHeight(); + } + private static void ToolBar_Changed(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) + { + UiApplicationWindow window = (UiApplicationWindow)dependencyObject; + window.UpdateCaptionHeight(); + } + private static void ResizeMode_Changed(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) + { + UiApplicationWindow window = (UiApplicationWindow)dependencyObject; - if (!window.ResizeModeCriticalSection.IsRunning) - { - window.ShowResizeGrip = window.ResizeMode == ResizeMode.CanResizeWithGrip; - window.UpdateWindowChrome(); - } - } - private static void BorderBrush_Changed(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) - { - UiApplicationWindow window = (UiApplicationWindow)dependencyObject; - window.UpdateBorder(); - } + if (!window.ResizeModeCriticalSection.IsRunning) + { + window.ShowResizeGrip = window.ResizeMode == ResizeMode.CanResizeWithGrip; + window.UpdateWindowChrome(); + } + } + private static void BorderBrush_Changed(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) + { + UiApplicationWindow window = (UiApplicationWindow)dependencyObject; + window.UpdateBorder(); + } - private void UpdateWindowChrome() - { - if (ShowResizeGrip) - { - // ResizeMode.CanResizeWithGrip cannot be used together with WindowChrome. - ResizeModeCriticalSection.Invoke(() => ResizeMode = ResizeMode.CanResize); - } + private void UpdateWindowChrome() + { + if (ShowResizeGrip) + { + // ResizeMode.CanResizeWithGrip cannot be used together with WindowChrome. + ResizeModeCriticalSection.Invoke(() => ResizeMode = ResizeMode.CanResize); + } - WindowChrome.SetWindowChrome(this, new() - { - CaptionHeight = CaptionHeight - 6, - ResizeBorderThickness = new(6), - UseAeroCaptionButtons = false - }); + WindowChrome.SetWindowChrome(this, new() + { + CaptionHeight = CaptionHeight - 6, + ResizeBorderThickness = new(6), + UseAeroCaptionButtons = false + }); - UpdateCaptionHeight(); - } - private void UpdateCaptionHeight() - { - WindowChrome? windowChrome = WindowChrome.GetWindowChrome(this); + UpdateCaptionHeight(); + } + private void UpdateCaptionHeight() + { + WindowChrome? windowChrome = WindowChrome.GetWindowChrome(this); - if (windowChrome != null) - { - windowChrome.CaptionHeight = (Menu, ToolBarTray) switch - { - (not null, null) => CaptionHeightWithMenu, - (null, not null) => CaptionHeightWithToolBar, - (not null, not null) => CaptionHeightWithMenuAndToolBar, - (null, null) => CaptionHeight - } - windowChrome.ResizeBorderThickness.Top; + if (windowChrome != null) + { + windowChrome.CaptionHeight = (Menu, ToolBarTray) switch + { + (not null, null) => CaptionHeightWithMenu, + (null, not null) => CaptionHeightWithToolBar, + (not null, not null) => CaptionHeightWithMenuAndToolBar, + (null, null) => CaptionHeight + } - windowChrome.ResizeBorderThickness.Top; - WindowChrome.SetWindowChrome(this, windowChrome); - } - } - private void UpdateBorder() - { - if (BorderBrush is SolidColorBrush borderBrush) - { - WindowService.SetBorderBrush(this, borderBrush); - } - } + WindowChrome.SetWindowChrome(this, windowChrome); + } + } + private void UpdateBorder() + { + if (BorderBrush is SolidColorBrush borderBrush) + { + WindowService.SetBorderBrush(this, borderBrush); + } + } } \ No newline at end of file diff --git a/BytecodeApi.Wpf.Cui/Controls/UiBusyIndicator.cs b/BytecodeApi.Wpf.Cui/Controls/UiBusyIndicator.cs index b073f2c..c1a9949 100644 --- a/BytecodeApi.Wpf.Cui/Controls/UiBusyIndicator.cs +++ b/BytecodeApi.Wpf.Cui/Controls/UiBusyIndicator.cs @@ -6,6 +6,9 @@ namespace BytecodeApi.Wpf.Cui.Controls; +/// +/// Represents a circular busy indicator control. +/// public class UiBusyIndicator : Control { private readonly Stopwatch Stopwatch; @@ -16,7 +19,10 @@ public class UiBusyIndicator : Control static UiBusyIndicator() { DefaultStyleKeyProperty.OverrideMetadata(typeof(UiBusyIndicator), new FrameworkPropertyMetadata(typeof(UiBusyIndicator))); - } + } + /// + /// Initializes a new instance of the class. + /// public UiBusyIndicator() { Stopwatch = Stopwatch.StartNew(); @@ -31,7 +37,10 @@ public UiBusyIndicator() Unloaded += UiBusyIndicator_Unloaded; } - public override void OnApplyTemplate() + /// + /// Applies the control template to this . + /// + public override void OnApplyTemplate() { base.OnApplyTemplate(); diff --git a/BytecodeApi.Wpf.Cui/Controls/UiButton.cs b/BytecodeApi.Wpf.Cui/Controls/UiButton.cs index ff88c6b..aade59e 100644 --- a/BytecodeApi.Wpf.Cui/Controls/UiButton.cs +++ b/BytecodeApi.Wpf.Cui/Controls/UiButton.cs @@ -3,6 +3,9 @@ namespace BytecodeApi.Wpf.Cui.Controls; +/// +/// Represents a button control. +/// public class UiButton : Button { static UiButton() diff --git a/BytecodeApi.Wpf.Cui/Controls/UiCheckBox.cs b/BytecodeApi.Wpf.Cui/Controls/UiCheckBox.cs index 2cbc319..e150afc 100644 --- a/BytecodeApi.Wpf.Cui/Controls/UiCheckBox.cs +++ b/BytecodeApi.Wpf.Cui/Controls/UiCheckBox.cs @@ -4,10 +4,19 @@ namespace BytecodeApi.Wpf.Cui.Controls; +/// +/// Represents a checkbox control. +/// public class UiCheckBox : CheckBox { - public static readonly DependencyProperty IndeterminateToCheckedProperty = DependencyPropertyEx.Register(nameof(IndeterminateToChecked)); - public bool IndeterminateToChecked + /// + /// Identifies the dependency property. This field is read-only. + /// + public static readonly DependencyProperty IndeterminateToCheckedProperty = DependencyPropertyEx.Register(nameof(IndeterminateToChecked)); + /// + /// Gets or sets a value that indicates whether a ThreeState should go from null to true when clicked, instead of from null to false. + /// + public bool IndeterminateToChecked { get => this.GetValue(IndeterminateToCheckedProperty); set => SetValue(IndeterminateToCheckedProperty, value); diff --git a/BytecodeApi.Wpf.Cui/Controls/UiComboBox.cs b/BytecodeApi.Wpf.Cui/Controls/UiComboBox.cs index 17fd941..094f784 100644 --- a/BytecodeApi.Wpf.Cui/Controls/UiComboBox.cs +++ b/BytecodeApi.Wpf.Cui/Controls/UiComboBox.cs @@ -3,6 +3,9 @@ namespace BytecodeApi.Wpf.Cui.Controls; +/// +/// Represents a combobox control. +/// public class UiComboBox : ComboBox { static UiComboBox() diff --git a/BytecodeApi.Wpf.Cui/Controls/UiDataGrid.cs b/BytecodeApi.Wpf.Cui/Controls/UiDataGrid.cs index 7e27b42..dc2f2ff 100644 --- a/BytecodeApi.Wpf.Cui/Controls/UiDataGrid.cs +++ b/BytecodeApi.Wpf.Cui/Controls/UiDataGrid.cs @@ -4,17 +4,26 @@ namespace BytecodeApi.Wpf.Cui.Controls; +/// +/// Represents a data grid control. +/// public class UiDataGrid : DataGrid { + /// + /// Identifies the dependency property. This field is read-only. + /// public static readonly DependencyProperty ShowRowNumbersProperty = DependencyPropertyEx.Register(nameof(ShowRowNumbers)); - public bool ShowRowNumbers - { - get => this.GetValue(ShowRowNumbersProperty); - set => SetValue(ShowRowNumbersProperty, value); - } + /// + /// Gets or sets a value that indicates whether row numbers are displayed in the row header. + /// + public bool ShowRowNumbers + { + get => this.GetValue(ShowRowNumbersProperty); + set => SetValue(ShowRowNumbersProperty, value); + } - static UiDataGrid() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(UiDataGrid), new FrameworkPropertyMetadata(typeof(UiDataGrid))); - } + static UiDataGrid() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(UiDataGrid), new FrameworkPropertyMetadata(typeof(UiDataGrid))); + } } \ No newline at end of file diff --git a/BytecodeApi.Wpf.Cui/Controls/UiDatePicker.cs b/BytecodeApi.Wpf.Cui/Controls/UiDatePicker.cs index d1225b4..770dd2a 100644 --- a/BytecodeApi.Wpf.Cui/Controls/UiDatePicker.cs +++ b/BytecodeApi.Wpf.Cui/Controls/UiDatePicker.cs @@ -9,170 +9,188 @@ namespace BytecodeApi.Wpf.Cui.Controls; +/// +/// Represents a date picker control. +/// public class UiDatePicker : DatePicker { - public static readonly DependencyProperty WatermarkProperty = DependencyPropertyEx.Register(nameof(Watermark)); - public static readonly DependencyProperty ShowResetButtonProperty = DependencyPropertyEx.Register(nameof(ShowResetButton)); - public object? Watermark - { - get => GetValue(WatermarkProperty); - set => SetValue(WatermarkProperty, value); - } - public bool ShowResetButton - { - get => this.GetValue(ShowResetButtonProperty); - set => SetValue(ShowResetButtonProperty, value); - } - private readonly CriticalSection FocusCriticalSection = new(); - private TextBox? TextBox; - private Popup? Popup; - private Button? ResetButton; - - static UiDatePicker() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(UiDatePicker), new FrameworkPropertyMetadata(typeof(UiDatePicker))); - } - - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); - - if (TextBox != null) - { - TextBox.PreviewMouseLeftButtonUp -= TextBox_PreviewMouseLeftButtonUp; - TextBox.PreviewKeyDown -= TextBox_PreviewKeyDown; - } - - if (ResetButton != null) - { - ResetButton.Click -= ResetButton_Click; - } - - TextBox? datePickerTextBox = GetTemplateChild("PART_TextBox") as TextBox; - datePickerTextBox?.ApplyTemplate(); - - TextBox = datePickerTextBox?.Template?.FindName("Part_InnerTextBox", datePickerTextBox) as TextBox; - Popup = GetTemplateChild("PART_Popup") as Popup; - ResetButton = GetTemplateChild("PART_ResetButton") as Button; - - if (TextBox != null) - { - TextBox.PreviewMouseLeftButtonUp += TextBox_PreviewMouseLeftButtonUp; - TextBox.PreviewKeyDown += TextBox_PreviewKeyDown; - } - - if (ResetButton != null) - { - ResetButton.Click += ResetButton_Click; - } - } - protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e) - { - if (e.OriginalSource is UiDatePicker or DatePickerTextBox) - { - FocusCriticalSection.Invoke(() => - { - if (TextBox?.Focus() != true) - { - base.OnGotKeyboardFocus(e); - } - }); - } - } - protected override void OnCalendarOpened(RoutedEventArgs e) - { - base.OnCalendarOpened(e); - - if (Popup?.Child is Calendar calendar) - { - HookTodayButton(calendar); - } - } - private void Calendar_Loaded(object sender, RoutedEventArgs e) - { - if (sender is Calendar cal) - { - cal.Loaded -= Calendar_Loaded; - HookTodayButton(cal); - } - } - private void TextBox_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) - { - if (TextBox != null && TextBox.SelectionLength == 0 && Regex.IsMatch(TextBox.Text, @"[0-9]+\.[0-9]+\.[0-9]+")) - { - int start = TextBox.Text[..TextBox.SelectionStart].LastIndexOf('.') + 1; - int end = TextBox.Text.IndexOf('.', TextBox.SelectionStart); - - if (end == -1) - { - end = TextBox.Text.Length; - } - - TextBox.SelectionStart = start; - TextBox.SelectionLength = end - start; - } - } - private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e) - { - if (TextBox != null) - { - int direction = e.Key switch - { - Key.Up or Key.Subtract or Key.OemMinus => -1, - Key.Down or Key.Add or Key.OemPlus => 1, - _ => 0 - }; - - if (direction != 0 && TextBox.Text.ToDateTime("dd.MM.yyyy") != null) - { - int selectionStart = TextBox.SelectionStart; - - if (selectionStart < 3) - { - SelectedDate = SelectedDate?.AddDays(direction); - } - else if (selectionStart < 6) - { - SelectedDate = SelectedDate?.AddMonths(direction); - } - else - { - SelectedDate = SelectedDate?.AddYears(direction); - } - - TextBox.SelectionStart = selectionStart; - e.Handled = true; - } - } - } - private void TodayButton_Click(object sender, RoutedEventArgs e) - { - SelectedDate = DateTime.Today; - IsDropDownOpen = false; - } - private void ResetButton_Click(object sender, RoutedEventArgs e) - { - SelectedDate = null; - } - - private void HookTodayButton(Calendar calendar) - { - calendar.ApplyTemplate(); - - if (calendar.Template.FindName("PART_CalendarItem", calendar) is CalendarItem calendarItem) - { - calendarItem.ApplyTemplate(); - - if (calendarItem.Template.FindName("PART_TodayButton", calendarItem) is Button todayButton) - { - todayButton.Click -= TodayButton_Click; - todayButton.Click += TodayButton_Click; - } - } - else - { - calendar.Loaded -= Calendar_Loaded; - calendar.Loaded += Calendar_Loaded; - } - } + /// + /// Identifies the dependency property. This field is read-only. + /// + public static readonly DependencyProperty WatermarkProperty = DependencyPropertyEx.Register(nameof(Watermark)); + /// + /// Identifies the dependency property. This field is read-only. + /// + public static readonly DependencyProperty ShowResetButtonProperty = DependencyPropertyEx.Register(nameof(ShowResetButton)); + /// + /// Gets or sets an object that represents the watermark displayed when no date is selected. + /// + public object? Watermark + { + get => GetValue(WatermarkProperty); + set => SetValue(WatermarkProperty, value); + } + /// + /// Gets or sets a value that indicates whether a reset button is shown to clear the selected date. + /// + public bool ShowResetButton + { + get => this.GetValue(ShowResetButtonProperty); + set => SetValue(ShowResetButtonProperty, value); + } + private readonly CriticalSection FocusCriticalSection = new(); + private TextBox? TextBox; + private Popup? Popup; + private Button? ResetButton; + + static UiDatePicker() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(UiDatePicker), new FrameworkPropertyMetadata(typeof(UiDatePicker))); + } + + /// + /// Applies the control template to this . + /// + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + if (TextBox != null) + { + TextBox.PreviewMouseLeftButtonUp -= TextBox_PreviewMouseLeftButtonUp; + TextBox.PreviewKeyDown -= TextBox_PreviewKeyDown; + } + + if (ResetButton != null) + { + ResetButton.Click -= ResetButton_Click; + } + + TextBox? datePickerTextBox = GetTemplateChild("PART_TextBox") as TextBox; + datePickerTextBox?.ApplyTemplate(); + + TextBox = datePickerTextBox?.Template?.FindName("Part_InnerTextBox", datePickerTextBox) as TextBox; + Popup = GetTemplateChild("PART_Popup") as Popup; + ResetButton = GetTemplateChild("PART_ResetButton") as Button; + + if (TextBox != null) + { + TextBox.PreviewMouseLeftButtonUp += TextBox_PreviewMouseLeftButtonUp; + TextBox.PreviewKeyDown += TextBox_PreviewKeyDown; + } + + if (ResetButton != null) + { + ResetButton.Click += ResetButton_Click; + } + } + protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e) + { + if (e.OriginalSource is UiDatePicker or DatePickerTextBox) + { + FocusCriticalSection.Invoke(() => + { + if (TextBox?.Focus() != true) + { + base.OnGotKeyboardFocus(e); + } + }); + } + } + protected override void OnCalendarOpened(RoutedEventArgs e) + { + base.OnCalendarOpened(e); + + if (Popup?.Child is Calendar calendar) + { + HookTodayButton(calendar); + } + } + private void Calendar_Loaded(object sender, RoutedEventArgs e) + { + if (sender is Calendar cal) + { + cal.Loaded -= Calendar_Loaded; + HookTodayButton(cal); + } + } + private void TextBox_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + if (TextBox != null && TextBox.SelectionLength == 0 && Regex.IsMatch(TextBox.Text, @"[0-9]+\.[0-9]+\.[0-9]+")) + { + int start = TextBox.Text[..TextBox.SelectionStart].LastIndexOf('.') + 1; + int end = TextBox.Text.IndexOf('.', TextBox.SelectionStart); + + if (end == -1) + { + end = TextBox.Text.Length; + } + + TextBox.SelectionStart = start; + TextBox.SelectionLength = end - start; + } + } + private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e) + { + if (TextBox != null) + { + int direction = e.Key switch + { + Key.Up or Key.Subtract or Key.OemMinus => -1, + Key.Down or Key.Add or Key.OemPlus => 1, + _ => 0 + }; + + if (direction != 0 && TextBox.Text.ToDateTime("dd.MM.yyyy") != null) + { + int selectionStart = TextBox.SelectionStart; + + if (selectionStart < 3) + { + SelectedDate = SelectedDate?.AddDays(direction); + } + else if (selectionStart < 6) + { + SelectedDate = SelectedDate?.AddMonths(direction); + } + else + { + SelectedDate = SelectedDate?.AddYears(direction); + } + + TextBox.SelectionStart = selectionStart; + e.Handled = true; + } + } + } + private void TodayButton_Click(object sender, RoutedEventArgs e) + { + SelectedDate = DateTime.Today; + IsDropDownOpen = false; + } + private void ResetButton_Click(object sender, RoutedEventArgs e) + { + SelectedDate = null; + } + + private void HookTodayButton(Calendar calendar) + { + calendar.ApplyTemplate(); + + if (calendar.Template.FindName("PART_CalendarItem", calendar) is CalendarItem calendarItem) + { + calendarItem.ApplyTemplate(); + + if (calendarItem.Template.FindName("PART_TodayButton", calendarItem) is Button todayButton) + { + todayButton.Click -= TodayButton_Click; + todayButton.Click += TodayButton_Click; + } + } + else + { + calendar.Loaded -= Calendar_Loaded; + calendar.Loaded += Calendar_Loaded; + } + } } \ No newline at end of file diff --git a/BytecodeApi.Wpf.Cui/Controls/UiDockingPanel.cs b/BytecodeApi.Wpf.Cui/Controls/UiDockingPanel.cs index 6dcf4ac..dcc444d 100644 --- a/BytecodeApi.Wpf.Cui/Controls/UiDockingPanel.cs +++ b/BytecodeApi.Wpf.Cui/Controls/UiDockingPanel.cs @@ -4,20 +4,24 @@ namespace BytecodeApi.Wpf.Cui.Controls; +/// +/// Represents a docking panel control with a header. +/// This control only visually represents a panel and does not provide any docking functionality. +/// public class UiDockingPanel : HeaderedContentControl { - static UiDockingPanel() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(UiDockingPanel), new FrameworkPropertyMetadata(typeof(UiDockingPanel))); - } + static UiDockingPanel() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(UiDockingPanel), new FrameworkPropertyMetadata(typeof(UiDockingPanel))); + } - protected override void OnPreviewMouseDown(MouseButtonEventArgs e) - { - base.OnPreviewMouseDown(e); + protected override void OnPreviewMouseDown(MouseButtonEventArgs e) + { + base.OnPreviewMouseDown(e); - if (!IsKeyboardFocusWithin) - { - Focus(); - } - } + if (!IsKeyboardFocusWithin) + { + Focus(); + } + } } \ No newline at end of file diff --git a/BytecodeApi.Wpf.Cui/Controls/UiDockingTabControl.cs b/BytecodeApi.Wpf.Cui/Controls/UiDockingTabControl.cs index ea9937d..ec43a3c 100644 --- a/BytecodeApi.Wpf.Cui/Controls/UiDockingTabControl.cs +++ b/BytecodeApi.Wpf.Cui/Controls/UiDockingTabControl.cs @@ -4,6 +4,10 @@ namespace BytecodeApi.Wpf.Cui.Controls; +/// +/// Represents a styled as a docking panel control with a header. +/// This control only visually represents a panel and does not provide any docking functionality. +/// public class UiDockingTabControl : TabControl { static UiDockingTabControl() diff --git a/BytecodeApi.Wpf.Cui/Controls/UiDropDownButton.cs b/BytecodeApi.Wpf.Cui/Controls/UiDropDownButton.cs index 746a062..903a652 100644 --- a/BytecodeApi.Wpf.Cui/Controls/UiDropDownButton.cs +++ b/BytecodeApi.Wpf.Cui/Controls/UiDropDownButton.cs @@ -6,264 +6,304 @@ namespace BytecodeApi.Wpf.Cui.Controls; +/// +/// This control represents a button that displays either a drop-down menu or popup when clicked. +/// public class UiDropDownButton : Button { - private static readonly DependencyPropertyKey IsDropDownOpenPropertyKey = DependencyPropertyEx.RegisterReadOnly(nameof(IsDropDownOpen), new FrameworkPropertyMetadata(false, IsDropDownOpen_Changed)); - private static readonly DependencyPropertyKey IsDropDownContextMenuPropertyKey = DependencyPropertyEx.RegisterReadOnly(nameof(IsDropDownContextMenu), new FrameworkPropertyMetadata(false)); + private static readonly DependencyPropertyKey IsDropDownOpenPropertyKey = DependencyPropertyEx.RegisterReadOnly(nameof(IsDropDownOpen), new FrameworkPropertyMetadata(false, IsDropDownOpen_Changed)); + private static readonly DependencyPropertyKey IsDropDownContextMenuPropertyKey = DependencyPropertyEx.RegisterReadOnly(nameof(IsDropDownContextMenu), new FrameworkPropertyMetadata(false)); + /// + /// Identifies the dependency property. This field is read-only. + /// public static readonly DependencyProperty IsDropDownOpenProperty = IsDropDownOpenPropertyKey.DependencyProperty; + /// + /// Identifies the dependency property. This field is read-only. + /// public static readonly DependencyProperty DropDownContentProperty = DependencyPropertyEx.Register(nameof(DropDownContent), new(DropDownContent_Changed)); - public static readonly DependencyProperty IsDropDownContextMenuProperty = IsDropDownContextMenuPropertyKey.DependencyProperty; + /// + /// Identifies the dependency property. This field is read-only. + /// + public static readonly DependencyProperty IsDropDownContextMenuProperty = IsDropDownContextMenuPropertyKey.DependencyProperty; + /// + /// Identifies the .CloseOnClick dependency property. This field is read-only. + /// public static readonly DependencyProperty CloseOnClickProperty = DependencyPropertyEx.RegisterAttached("CloseOnClick", new FrameworkPropertyMetadata(CloseOnClick_Changed)); - public bool IsDropDownOpen - { - get => this.GetValue(IsDropDownOpenProperty); - private set => SetValue(IsDropDownOpenPropertyKey, value); - } - public object? DropDownContent - { - get => GetValue(DropDownContentProperty); - set => SetValue(DropDownContentProperty, value); - } - public bool IsDropDownContextMenu - { - get => this.GetValue(IsDropDownContextMenuProperty); - private set => SetValue(IsDropDownContextMenuPropertyKey, value); - } - public static bool GetCloseOnClick(DependencyObject dependencyObject) - { - return dependencyObject.GetValue(CloseOnClickProperty); - } - public static void SetCloseOnClick(DependencyObject dependencyObject, bool value) - { - dependencyObject.SetValue(CloseOnClickProperty, value); - } - private Popup? Popup; - private Window? Window; - private static UiDropDownButton? OpenInstance; + /// + /// Gets a value indicating whether the drop-down is currently open. + /// + public bool IsDropDownOpen + { + get => this.GetValue(IsDropDownOpenProperty); + private set => SetValue(IsDropDownOpenPropertyKey, value); + } + /// + /// Gets or sets the content to be displayed in the drop-down. This can be a , or a , which will be displayed in a . + /// + public object? DropDownContent + { + get => GetValue(DropDownContentProperty); + set => SetValue(DropDownContentProperty, value); + } + /// + /// Gets a value indicating whether the drop-down content is a . + /// + public bool IsDropDownContextMenu + { + get => this.GetValue(IsDropDownContextMenuProperty); + private set => SetValue(IsDropDownContextMenuPropertyKey, value); + } + /// + /// Returns , if the specified will close the currently open when clicked; otherwise, . + /// + /// The to check. + /// + /// , if the specified will close the currently open when clicked; + /// otherwise, . + /// + public static bool GetCloseOnClick(DependencyObject dependencyObject) + { + return dependencyObject.GetValue(CloseOnClickProperty); + } + /// + /// Sets a value indicating whether the specified will close the currently open when clicked. + /// + /// The to apply this property to. + /// , if the specified will close the currently open when clicked; otherwise, . + public static void SetCloseOnClick(DependencyObject dependencyObject, bool value) + { + dependencyObject.SetValue(CloseOnClickProperty, value); + } + private Popup? Popup; + private Window? Window; + private static UiDropDownButton? OpenInstance; - static UiDropDownButton() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(UiDropDownButton), new FrameworkPropertyMetadata(typeof(UiDropDownButton))); - } + static UiDropDownButton() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(UiDropDownButton), new FrameworkPropertyMetadata(typeof(UiDropDownButton))); + } - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); + /// + /// Applies the control template to this . + /// + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); - if (Popup != null) - { - Popup.Closed -= Popup_Closed; - } + if (Popup != null) + { + Popup.Closed -= Popup_Closed; + } - Popup = GetTemplateChild("PART_Popup") as Popup; + Popup = GetTemplateChild("PART_Popup") as Popup; - if (Popup != null) - { - Popup.Closed += Popup_Closed; - } - } - protected override void OnClick() - { - IsDropDownOpen = !IsDropDownOpen; + if (Popup != null) + { + Popup.Closed += Popup_Closed; + } + } + protected override void OnClick() + { + IsDropDownOpen = !IsDropDownOpen; - base.OnClick(); - } - protected override void OnPreviewKeyDown(KeyEventArgs e) - { - base.OnPreviewKeyDown(e); + base.OnClick(); + } + protected override void OnPreviewKeyDown(KeyEventArgs e) + { + base.OnPreviewKeyDown(e); - if (e.Key == Key.Escape) - { - IsDropDownOpen = false; - e.Handled = true; - } - } - protected override void OnContextMenuOpening(ContextMenuEventArgs e) - { - if (IsDropDownContextMenu) - { - e.Handled = true; - return; - } + if (e.Key == Key.Escape) + { + IsDropDownOpen = false; + e.Handled = true; + } + } + protected override void OnContextMenuOpening(ContextMenuEventArgs e) + { + if (IsDropDownContextMenu) + { + e.Handled = true; + return; + } - base.OnContextMenuOpening(e); - } - private void Popup_Closed(object? sender, EventArgs e) - { - if (IsDropDownOpen) - { - IsDropDownOpen = false; - } + base.OnContextMenuOpening(e); + } + private void Popup_Closed(object? sender, EventArgs e) + { + if (IsDropDownOpen) + { + IsDropDownOpen = false; + } - if (OpenInstance == this) - { - OpenInstance = null; - } + if (OpenInstance == this) + { + OpenInstance = null; + } - UnhookOutsideClick(); - } - private void ContextMenu_Closed(object? sender, RoutedEventArgs e) - { - if (IsDropDownOpen) - { - IsDropDownOpen = false; - } + UnhookOutsideClick(); + } + private void ContextMenu_Closed(object? sender, RoutedEventArgs e) + { + if (IsDropDownOpen) + { + IsDropDownOpen = false; + } - if (OpenInstance == this) - { - OpenInstance = null; - } - } - private static void IsDropDownOpen_Changed(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) - { - UiDropDownButton dropDownButton = (UiDropDownButton)dependencyObject; + if (OpenInstance == this) + { + OpenInstance = null; + } + } + private static void IsDropDownOpen_Changed(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) + { + UiDropDownButton dropDownButton = (UiDropDownButton)dependencyObject; - if (dropDownButton.IsDropDownContextMenu) - { - if (dropDownButton.ContextMenu != null) - { - if (dropDownButton.IsDropDownOpen) - { - OpenInstance = dropDownButton; - dropDownButton.ContextMenu.MinWidth = Math.Max(dropDownButton.ContextMenu.MinWidth, dropDownButton.ActualWidth + 10); - dropDownButton.ContextMenu.PlacementTarget = dropDownButton; - dropDownButton.ContextMenu.Placement = PlacementMode.Bottom; - dropDownButton.ContextMenu.IsOpen = true; - } - else - { - if (OpenInstance == dropDownButton) - { - OpenInstance = null; - } + if (dropDownButton.IsDropDownContextMenu) + { + if (dropDownButton.ContextMenu != null) + { + if (dropDownButton.IsDropDownOpen) + { + OpenInstance = dropDownButton; + dropDownButton.ContextMenu.MinWidth = Math.Max(dropDownButton.ContextMenu.MinWidth, dropDownButton.ActualWidth + 10); + dropDownButton.ContextMenu.PlacementTarget = dropDownButton; + dropDownButton.ContextMenu.Placement = PlacementMode.Bottom; + dropDownButton.ContextMenu.IsOpen = true; + } + else + { + if (OpenInstance == dropDownButton) + { + OpenInstance = null; + } - dropDownButton.ContextMenu.IsOpen = false; - } - } - } - else - { - if (dropDownButton.Popup != null) - { - if (dropDownButton.IsDropDownOpen) - { - OpenInstance = dropDownButton; - dropDownButton.Popup.IsOpen = true; - dropDownButton.HookOutsideClick(); - } - else - { - if (OpenInstance == dropDownButton) - { - OpenInstance = null; - } + dropDownButton.ContextMenu.IsOpen = false; + } + } + } + else + { + if (dropDownButton.Popup != null) + { + if (dropDownButton.IsDropDownOpen) + { + OpenInstance = dropDownButton; + dropDownButton.Popup.IsOpen = true; + dropDownButton.HookOutsideClick(); + } + else + { + if (OpenInstance == dropDownButton) + { + OpenInstance = null; + } - dropDownButton.UnhookOutsideClick(); - dropDownButton.Popup.IsOpen = false; - } - } - } - } - private static void DropDownContent_Changed(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) - { - UiDropDownButton dropDownButton = (UiDropDownButton)dependencyObject; + dropDownButton.UnhookOutsideClick(); + dropDownButton.Popup.IsOpen = false; + } + } + } + } + private static void DropDownContent_Changed(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) + { + UiDropDownButton dropDownButton = (UiDropDownButton)dependencyObject; - if (dropDownButton.ContextMenu != null) - { - dropDownButton.ContextMenu.Closed -= dropDownButton.ContextMenu_Closed; - dropDownButton.ContextMenu = null; - } + if (dropDownButton.ContextMenu != null) + { + dropDownButton.ContextMenu.Closed -= dropDownButton.ContextMenu_Closed; + dropDownButton.ContextMenu = null; + } - dropDownButton.IsDropDownContextMenu = e.NewValue is ContextMenu; + dropDownButton.IsDropDownContextMenu = e.NewValue is ContextMenu; - if (dropDownButton.IsDropDownContextMenu) - { - dropDownButton.ContextMenu = (ContextMenu)e.NewValue; - dropDownButton.ContextMenu.Closed += dropDownButton.ContextMenu_Closed; - } + if (dropDownButton.IsDropDownContextMenu) + { + dropDownButton.ContextMenu = (ContextMenu)e.NewValue; + dropDownButton.ContextMenu.Closed += dropDownButton.ContextMenu_Closed; + } - if (dropDownButton.IsDropDownOpen) - { - dropDownButton.IsDropDownOpen = false; - } - } - private static void CloseOnClick_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - if (d is ButtonBase button) - { - if ((bool)e.NewValue) - { - button.Click += CloseOnClick_Click; - } - else - { - button.Click -= CloseOnClick_Click; - } - } - else if (d is UIElement element) - { - if ((bool)e.NewValue) - { - element.MouseLeftButtonUp += CloseOnClick_MouseLeftButtonUp; - } - else - { - element.MouseLeftButtonUp -= CloseOnClick_MouseLeftButtonUp; - } - } - } - private static void CloseOnClick_Click(object? sender, RoutedEventArgs e) - { - if (OpenInstance != null) - { - OpenInstance.IsDropDownOpen = false; - } - } - private static void CloseOnClick_MouseLeftButtonUp(object? sender, MouseButtonEventArgs e) - { - if (OpenInstance != null) - { - OpenInstance.IsDropDownOpen = false; - } - } + if (dropDownButton.IsDropDownOpen) + { + dropDownButton.IsDropDownOpen = false; + } + } + private static void CloseOnClick_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is ButtonBase button) + { + if ((bool)e.NewValue) + { + button.Click += CloseOnClick_Click; + } + else + { + button.Click -= CloseOnClick_Click; + } + } + else if (d is UIElement element) + { + if ((bool)e.NewValue) + { + element.MouseLeftButtonUp += CloseOnClick_MouseLeftButtonUp; + } + else + { + element.MouseLeftButtonUp -= CloseOnClick_MouseLeftButtonUp; + } + } + } + private static void CloseOnClick_Click(object? sender, RoutedEventArgs e) + { + if (OpenInstance != null) + { + OpenInstance.IsDropDownOpen = false; + } + } + private static void CloseOnClick_MouseLeftButtonUp(object? sender, MouseButtonEventArgs e) + { + if (OpenInstance != null) + { + OpenInstance.IsDropDownOpen = false; + } + } - private void HookOutsideClick() - { - Window = Window.GetWindow(this); - if (Window != null) - { - Window.PreviewMouseDown += Window_PreviewMouseDown; - Window.Deactivated += Window_Deactivated; - } - } - private void UnhookOutsideClick() - { - if (Window != null) - { - Window.PreviewMouseDown -= Window_PreviewMouseDown; - Window.Deactivated -= Window_Deactivated; - Window = null; - } - } - private void Window_PreviewMouseDown(object? sender, MouseButtonEventArgs e) - { - if (IsMouseOver) - { - // Click on button. - return; - } - else if (Popup != null && Popup.IsMouseOver) - { - // Click on popup. - return; - } - else - { - IsDropDownOpen = false; - } - } - private void Window_Deactivated(object? sender, EventArgs e) - { - IsDropDownOpen = false; - } + private void HookOutsideClick() + { + Window = Window.GetWindow(this); + if (Window != null) + { + Window.PreviewMouseDown += Window_PreviewMouseDown; + Window.Deactivated += Window_Deactivated; + } + } + private void UnhookOutsideClick() + { + if (Window != null) + { + Window.PreviewMouseDown -= Window_PreviewMouseDown; + Window.Deactivated -= Window_Deactivated; + Window = null; + } + } + private void Window_PreviewMouseDown(object? sender, MouseButtonEventArgs e) + { + if (IsMouseOver) + { + // Click on button. + return; + } + else if (Popup != null && Popup.IsMouseOver) + { + // Click on popup. + return; + } + else + { + IsDropDownOpen = false; + } + } + private void Window_Deactivated(object? sender, EventArgs e) + { + IsDropDownOpen = false; + } } \ No newline at end of file diff --git a/BytecodeApi.Wpf.Cui/Controls/UiExpander.cs b/BytecodeApi.Wpf.Cui/Controls/UiExpander.cs index e6db155..eb72ea2 100644 --- a/BytecodeApi.Wpf.Cui/Controls/UiExpander.cs +++ b/BytecodeApi.Wpf.Cui/Controls/UiExpander.cs @@ -3,10 +3,13 @@ namespace BytecodeApi.Wpf.Cui.Controls; +/// +/// Represents a collapsible container control that can be used to show or hide content. +/// public class UiExpander : Expander { - static UiExpander() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(UiExpander), new FrameworkPropertyMetadata(typeof(UiExpander))); - } + static UiExpander() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(UiExpander), new FrameworkPropertyMetadata(typeof(UiExpander))); + } } \ No newline at end of file diff --git a/BytecodeApi.Wpf.Cui/Controls/UiGridViewColumn.cs b/BytecodeApi.Wpf.Cui/Controls/UiGridViewColumn.cs index 9452532..1c8f56d 100644 --- a/BytecodeApi.Wpf.Cui/Controls/UiGridViewColumn.cs +++ b/BytecodeApi.Wpf.Cui/Controls/UiGridViewColumn.cs @@ -4,39 +4,54 @@ namespace BytecodeApi.Wpf.Cui.Controls; +/// +/// Represents a column in a with extended properties. +/// public class UiGridViewColumn : GridViewColumn { - public static readonly DependencyProperty SortPropertyProperty = DependencyPropertyEx.Register(nameof(SortProperty)); - public static readonly DependencyProperty IsVisibleProperty = DependencyPropertyEx.Register(nameof(IsVisible), new(true, IsVisible_Changed)); - public string? SortProperty - { - get => this.GetValue(SortPropertyProperty); - set => SetValue(SortPropertyProperty, value); - } - public bool IsVisible - { - get => this.GetValue(IsVisibleProperty); - set => SetValue(IsVisibleProperty, value); - } - private double HiddenWidth = double.NaN; + /// + /// Identifies the dependency property. This field is read-only. + /// + public static readonly DependencyProperty SortPropertyProperty = DependencyPropertyEx.Register(nameof(SortProperty)); + /// + /// Identifies the dependency property. This field is read-only. + /// + public static readonly DependencyProperty IsVisibleProperty = DependencyPropertyEx.Register(nameof(IsVisible), new(true, IsVisible_Changed)); + /// + /// Gets or sets a value that corresponds to the property when sorting by this column. + /// + public string? SortProperty + { + get => this.GetValue(SortPropertyProperty); + set => SetValue(SortPropertyProperty, value); + } + /// + /// Gets or sets a value that indicates whether the column is visible. + /// + public bool IsVisible + { + get => this.GetValue(IsVisibleProperty); + set => SetValue(IsVisibleProperty, value); + } + private double HiddenWidth = double.NaN; - private static void IsVisible_Changed(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) - { - if (dependencyObject is UiGridViewColumn column) - { - if (column.IsVisible) - { - column.Width = column.HiddenWidth; - } - else - { - if (column.Width > 0) - { - column.HiddenWidth = column.Width; - } + private static void IsVisible_Changed(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) + { + if (dependencyObject is UiGridViewColumn column) + { + if (column.IsVisible) + { + column.Width = column.HiddenWidth; + } + else + { + if (column.Width > 0) + { + column.HiddenWidth = column.Width; + } - column.Width = 0; - } - } - } + column.Width = 0; + } + } + } } \ No newline at end of file diff --git a/BytecodeApi.Wpf.Cui/Controls/UiPasswordBox.cs b/BytecodeApi.Wpf.Cui/Controls/UiPasswordBox.cs index 1d58793..7185e22 100644 --- a/BytecodeApi.Wpf.Cui/Controls/UiPasswordBox.cs +++ b/BytecodeApi.Wpf.Cui/Controls/UiPasswordBox.cs @@ -52,7 +52,10 @@ static UiPasswordBox() DefaultStyleKeyProperty.OverrideMetadata(typeof(UiPasswordBox), new FrameworkPropertyMetadata(typeof(UiPasswordBox))); } - public override void OnApplyTemplate() + /// + /// Applies the control template to this . + /// + public override void OnApplyTemplate() { base.OnApplyTemplate(); diff --git a/BytecodeApi.Wpf.Cui/Controls/UiPropertyGridGroup.cs b/BytecodeApi.Wpf.Cui/Controls/UiPropertyGridGroup.cs index 7d4acac..46744bf 100644 --- a/BytecodeApi.Wpf.Cui/Controls/UiPropertyGridGroup.cs +++ b/BytecodeApi.Wpf.Cui/Controls/UiPropertyGridGroup.cs @@ -26,7 +26,10 @@ static UiPropertyGridGroup() DefaultStyleKeyProperty.OverrideMetadata(typeof(UiPropertyGridGroup), new FrameworkPropertyMetadata(typeof(UiPropertyGridGroup))); } - public override void OnApplyTemplate() + /// + /// Applies the control template to this . + /// + public override void OnApplyTemplate() { base.OnApplyTemplate(); diff --git a/BytecodeApi.Wpf.Cui/Controls/UiPropertyGridItem.cs b/BytecodeApi.Wpf.Cui/Controls/UiPropertyGridItem.cs index 97c5038..198d32b 100644 --- a/BytecodeApi.Wpf.Cui/Controls/UiPropertyGridItem.cs +++ b/BytecodeApi.Wpf.Cui/Controls/UiPropertyGridItem.cs @@ -29,7 +29,10 @@ static UiPropertyGridItem() DefaultStyleKeyProperty.OverrideMetadata(typeof(UiPropertyGridItem), new FrameworkPropertyMetadata(typeof(UiPropertyGridItem))); } - public override void OnApplyTemplate() + /// + /// Applies the control template to this . + /// + public override void OnApplyTemplate() { base.OnApplyTemplate(); diff --git a/BytecodeApi.Wpf.Cui/Controls/UiSplitButton.cs b/BytecodeApi.Wpf.Cui/Controls/UiSplitButton.cs index 72e50c0..a431a2d 100644 --- a/BytecodeApi.Wpf.Cui/Controls/UiSplitButton.cs +++ b/BytecodeApi.Wpf.Cui/Controls/UiSplitButton.cs @@ -51,7 +51,10 @@ static UiSplitButton() EventManager.RegisterClassHandler(typeof(UiSplitButton), ClickEvent, new RoutedEventHandler(UiSplitButton_Click), true); } - public override void OnApplyTemplate() + /// + /// Applies the control template to this . + /// + public override void OnApplyTemplate() { base.OnApplyTemplate(); diff --git a/BytecodeApi.Wpf.Cui/Controls/UiTextBox.cs b/BytecodeApi.Wpf.Cui/Controls/UiTextBox.cs index 2c16760..28c1229 100644 --- a/BytecodeApi.Wpf.Cui/Controls/UiTextBox.cs +++ b/BytecodeApi.Wpf.Cui/Controls/UiTextBox.cs @@ -41,7 +41,10 @@ static UiTextBox() DefaultStyleKeyProperty.OverrideMetadata(typeof(UiTextBox), new FrameworkPropertyMetadata(typeof(UiTextBox))); } - public override void OnApplyTemplate() + /// + /// Applies the control template to this . + /// + public override void OnApplyTemplate() { base.OnApplyTemplate(); diff --git a/BytecodeApi.Wpf.Cui/SvgSource.cs b/BytecodeApi.Wpf.Cui/SvgSource.cs index 4269052..eb0509a 100644 --- a/BytecodeApi.Wpf.Cui/SvgSource.cs +++ b/BytecodeApi.Wpf.Cui/SvgSource.cs @@ -9,173 +9,253 @@ namespace BytecodeApi.Wpf.Cui; +/// +/// Class to convert SVG resources to WPF image sources. +/// public static class SvgSource { - private static readonly Dictionary ImageSourceCache = []; - private static readonly Dictionary<(string, Color), DrawingImage> ImageSourceColoredCache = []; - private static readonly Dictionary<(string, int), System.Drawing.Bitmap> BitmapCache = []; - private static readonly Dictionary<(string, int, Color), System.Drawing.Bitmap> BitmapColoredCache = []; - private static readonly Dictionary<(string, int), BitmapSource> BitmapSourceCache = []; - private static readonly Dictionary<(string, int, Color), BitmapSource> BitmapSourceColoredCache = []; - - public static DrawingImage? ImageSource(string uri) - { - if (ImageSourceCache.TryGetValue(uri, out DrawingImage? existingImage)) - { - return existingImage; - } - else if (GetSvgResource(uri) is DrawingImage image) - { - if (image.CanFreeze) image.Freeze(); - ImageSourceCache[uri] = image; - return image; - } - else - { - return null; - } - } - public static DrawingImage? ImageSource(string uri, Color color) - { - if (ImageSourceColoredCache.TryGetValue((uri, color), out DrawingImage? existingImage)) - { - return existingImage; - } - else if (GetSvgResource(uri) is DrawingImage image) - { - ChangeColor(image, color); - if (image.CanFreeze) image.Freeze(); - - ImageSourceColoredCache[(uri, color)] = image; - return image; - } - else - { - return null; - } - } - public static System.Drawing.Bitmap? Bitmap(string uri, int size) - { - if (BitmapCache.TryGetValue((uri, size), out System.Drawing.Bitmap? existingImage)) - { - return existingImage; - } - else if (BitmapSource(uri, size) is BitmapSource bitmapSource) - { - System.Drawing.Bitmap bitmap = bitmapSource.ToBitmap(); - BitmapCache[(uri, size)] = bitmap; - return bitmap; - } - else - { - return null; - } - } - public static System.Drawing.Bitmap? Bitmap(string uri, int size, Color color) - { - if (BitmapColoredCache.TryGetValue((uri, size, color), out System.Drawing.Bitmap? existingImage)) - { - return existingImage; - } - else if (BitmapSource(uri, size, color) is BitmapSource bitmapSource) - { - System.Drawing.Bitmap bitmap = bitmapSource.ToBitmap(); - BitmapColoredCache[(uri, size, color)] = bitmap; - return bitmap; - } - else - { - return null; - } - } - public static BitmapSource? BitmapSource(string uri, int size) - { - if (BitmapSourceCache.TryGetValue((uri, size), out BitmapSource? existingImage)) - { - return existingImage; - } - else if (ImageSource(uri) is DrawingImage image) - { - BitmapSource bitmap = ConvertDrawingImageToBitmap(image, size); - BitmapSourceCache[(uri, size)] = bitmap; - return bitmap; - } - else - { - return null; - } - } - public static BitmapSource? BitmapSource(string uri, int size, Color color) - { - if (BitmapSourceColoredCache.TryGetValue((uri, size, color), out BitmapSource? existingImage)) - { - return existingImage; - } - else if (ImageSource(uri, color) is DrawingImage image) - { - BitmapSource bitmap = ConvertDrawingImageToBitmap(image, size); - BitmapSourceColoredCache[(uri, size, color)] = bitmap; - return bitmap; - } - else - { - return null; - } - } - - private static byte[] GetResource(string uri) - { - StreamResourceInfo resourceInfo = Application - .GetResourceStream(new(uri)) - ?? throw new FileNotFoundException($"Resource '{uri}' not found."); - - using MemoryStream memoryStream = new(); - resourceInfo.Stream.CopyTo(memoryStream); - - return memoryStream.ToArray(); - } - private static DrawingImage GetSvgResource(string uri) - { - using FileSvgReader reader = new(new()); - using MemoryStream memoryStream = new(GetResource(uri.StartsWith("pack://", StringComparison.OrdinalIgnoreCase) ? uri : $"{Packs.Application}{uri}")); - - return new(reader.Read(memoryStream)); - } - private static void ChangeColor(DrawingImage image, Color color) - { - SetColor(image.Drawing); - - void SetColor(Drawing drawing) - { - if (drawing is DrawingGroup group) - { - foreach (Drawing child in group.Children) - { - SetColor(child); - } - } - else if (drawing is GeometryDrawing geometry) - { - if (geometry.Pen?.Brush is SolidColorBrush solidColorBrush1) - { - solidColorBrush1.Color = color; - } - if (geometry.Brush is SolidColorBrush solidColorBrush2) - { - solidColorBrush2.Color = color; - } - } - } - } - private static BitmapSource ConvertDrawingImageToBitmap(DrawingImage image, int size) - { - Image wpfImage = new() { Source = image }; - wpfImage.Measure(new(size, size)); - wpfImage.Arrange(new(0, 0, size, size)); - - RenderTargetBitmap renderTarget = new(size, size, 96, 96, PixelFormats.Pbgra32); - renderTarget.Render(wpfImage); - - return renderTarget; - } + private static readonly Dictionary ImageSourceCache = []; + private static readonly Dictionary<(string, Color), DrawingImage> ImageSourceColoredCache = []; + private static readonly Dictionary<(string, int), System.Drawing.Bitmap> BitmapCache = []; + private static readonly Dictionary<(string, int, Color), System.Drawing.Bitmap> BitmapColoredCache = []; + private static readonly Dictionary<(string, int), BitmapSource> BitmapSourceCache = []; + private static readonly Dictionary<(string, int, Color), BitmapSource> BitmapSourceColoredCache = []; + + /// + /// Loads an SVG resource from the specified URI and converts it to a . + /// + /// The URI of the SVG resource. + /// + /// A new if the resource was found; + /// otherwise, . + /// + public static DrawingImage? ImageSource(string uri) + { + Check.ArgumentNull(uri); + Check.ArgumentEx.StringNotEmpty(uri); + + if (ImageSourceCache.TryGetValue(uri, out DrawingImage? existingImage)) + { + return existingImage; + } + else if (GetSvgResource(uri) is DrawingImage image) + { + if (image.CanFreeze) image.Freeze(); + ImageSourceCache[uri] = image; + return image; + } + else + { + return null; + } + } + /// + /// Loads an SVG resource from the specified URI, converts it to a , and changes its color. + /// + /// The URI of the SVG resource. + /// A to apply to all SVG elements. + /// + /// A new if the resource was found; + /// otherwise, . + /// + public static DrawingImage? ImageSource(string uri, Color color) + { + Check.ArgumentNull(uri); + Check.ArgumentEx.StringNotEmpty(uri); + + if (ImageSourceColoredCache.TryGetValue((uri, color), out DrawingImage? existingImage)) + { + return existingImage; + } + else if (GetSvgResource(uri) is DrawingImage image) + { + ChangeColor(image, color); + if (image.CanFreeze) image.Freeze(); + + ImageSourceColoredCache[(uri, color)] = image; + return image; + } + else + { + return null; + } + } + /// + /// Loads an SVG resource from the specified URI and converts it to a of the specified size. + /// + /// The URI of the SVG resource. + /// The width and height, in pixels, of the resulting . + /// + /// A new if the resource was found; + /// otherwise, . + /// + public static System.Drawing.Bitmap? Bitmap(string uri, int size) + { + Check.ArgumentNull(uri); + Check.ArgumentEx.StringNotEmpty(uri); + Check.ArgumentOutOfRangeEx.Greater0(size); + + if (BitmapCache.TryGetValue((uri, size), out System.Drawing.Bitmap? existingImage)) + { + return existingImage; + } + else if (BitmapSource(uri, size) is BitmapSource bitmapSource) + { + System.Drawing.Bitmap bitmap = bitmapSource.ToBitmap(); + BitmapCache[(uri, size)] = bitmap; + return bitmap; + } + else + { + return null; + } + } + /// + /// Loads an SVG resource from the specified URI, converts it to a of the specified size, and changes its color. + /// + /// The URI of the SVG resource. + /// The width and height, in pixels, of the resulting . + /// A to apply to all SVG elements. + /// + /// A new if the resource was found; + /// otherwise, . + /// + public static System.Drawing.Bitmap? Bitmap(string uri, int size, Color color) + { + Check.ArgumentNull(uri); + Check.ArgumentEx.StringNotEmpty(uri); + Check.ArgumentOutOfRangeEx.Greater0(size); + + if (BitmapColoredCache.TryGetValue((uri, size, color), out System.Drawing.Bitmap? existingImage)) + { + return existingImage; + } + else if (BitmapSource(uri, size, color) is BitmapSource bitmapSource) + { + System.Drawing.Bitmap bitmap = bitmapSource.ToBitmap(); + BitmapColoredCache[(uri, size, color)] = bitmap; + return bitmap; + } + else + { + return null; + } + } + /// + /// Loads an SVG resource from the specified URI, converts it to a of the specified size, and returns an equivalent . + /// + /// The URI of the SVG resource. + /// The width and height, in pixels, of the . + /// + /// A new if the resource was found; + /// otherwise, . + /// + public static BitmapSource? BitmapSource(string uri, int size) + { + Check.ArgumentNull(uri); + Check.ArgumentEx.StringNotEmpty(uri); + Check.ArgumentOutOfRangeEx.Greater0(size); + + if (BitmapSourceCache.TryGetValue((uri, size), out BitmapSource? existingImage)) + { + return existingImage; + } + else if (ImageSource(uri) is DrawingImage image) + { + BitmapSource bitmap = ConvertDrawingImageToBitmap(image, size); + BitmapSourceCache[(uri, size)] = bitmap; + return bitmap; + } + else + { + return null; + } + } + /// + /// Loads an SVG resource from the specified URI, converts it to a of the specified size, changes its color, and returns an equivalent . + /// + /// The URI of the SVG resource. + /// The width and height, in pixels, of the . + /// A to apply to all SVG elements. + /// + /// A new if the resource was found; + /// otherwise, . + /// + public static BitmapSource? BitmapSource(string uri, int size, Color color) + { + Check.ArgumentNull(uri); + Check.ArgumentEx.StringNotEmpty(uri); + Check.ArgumentOutOfRangeEx.Greater0(size); + + if (BitmapSourceColoredCache.TryGetValue((uri, size, color), out BitmapSource? existingImage)) + { + return existingImage; + } + else if (ImageSource(uri, color) is DrawingImage image) + { + BitmapSource bitmap = ConvertDrawingImageToBitmap(image, size); + BitmapSourceColoredCache[(uri, size, color)] = bitmap; + return bitmap; + } + else + { + return null; + } + } + + private static byte[] GetResource(string uri) + { + StreamResourceInfo resourceInfo = Application + .GetResourceStream(new(uri)) + ?? throw new FileNotFoundException($"Resource '{uri}' not found."); + + using MemoryStream memoryStream = new(); + resourceInfo.Stream.CopyTo(memoryStream); + + return memoryStream.ToArray(); + } + private static DrawingImage GetSvgResource(string uri) + { + using FileSvgReader reader = new(new()); + using MemoryStream memoryStream = new(GetResource(uri.StartsWith("pack://", StringComparison.OrdinalIgnoreCase) ? uri : $"{Packs.Application}{uri}")); + + return new(reader.Read(memoryStream)); + } + private static void ChangeColor(DrawingImage image, Color color) + { + SetColor(image.Drawing); + + void SetColor(Drawing drawing) + { + if (drawing is DrawingGroup group) + { + foreach (Drawing child in group.Children) + { + SetColor(child); + } + } + else if (drawing is GeometryDrawing geometry) + { + if (geometry.Pen?.Brush is SolidColorBrush solidColorBrush1) + { + solidColorBrush1.Color = color; + } + if (geometry.Brush is SolidColorBrush solidColorBrush2) + { + solidColorBrush2.Color = color; + } + } + } + } + private static BitmapSource ConvertDrawingImageToBitmap(DrawingImage image, int size) + { + Image wpfImage = new() { Source = image }; + wpfImage.Measure(new(size, size)); + wpfImage.Arrange(new(0, 0, size, size)); + + RenderTargetBitmap renderTarget = new(size, size, 96, 96, PixelFormats.Pbgra32); + renderTarget.Render(wpfImage); + + return renderTarget; + } } \ No newline at end of file diff --git a/BytecodeApi.Wpf.Cui/SystemParametersEx.cs b/BytecodeApi.Wpf.Cui/SystemParametersEx.cs index 6b74727..546f89c 100644 --- a/BytecodeApi.Wpf.Cui/SystemParametersEx.cs +++ b/BytecodeApi.Wpf.Cui/SystemParametersEx.cs @@ -4,29 +4,42 @@ namespace BytecodeApi.Wpf.Cui; +/// +/// Helper class that extends with additional functionality. +/// public static class SystemParametersEx { - public static void SetToolTipDelay(int milliseconds) - { - ToolTipService.InitialShowDelayProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(milliseconds)); - } - public static void SetMenuDropAlignment(bool leftAligned) - { - Update(); - SystemParameters.StaticPropertyChanged += delegate { Update(); }; + /// + /// Sets the global initial delay, in milliseconds, before a tooltip is displayed. + /// + /// The delay, in milliseconds, to wait before showing a tooltip. + public static void SetToolTipDelay(int milliseconds) + { + Check.ArgumentOutOfRangeEx.GreaterEqual0(milliseconds); - void Update() - { - try - { - if (SystemParameters.MenuDropAlignment != leftAligned && typeof(SystemParameters).GetField("_menuDropAlignment", BindingFlags.NonPublic | BindingFlags.Static) is FieldInfo field) - { - field.SetValue(null, leftAligned); - } - } - catch - { - } - } - } + ToolTipService.InitialShowDelayProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(milliseconds)); + } + /// + /// Sets the global menu drop alignment. + /// + /// to align menu dropdowns to the left; to align menu dropdowns to the right. + public static void SetMenuDropAlignment(bool leftAligned) + { + Update(); + SystemParameters.StaticPropertyChanged += delegate { Update(); }; + + void Update() + { + try + { + if (SystemParameters.MenuDropAlignment != leftAligned && typeof(SystemParameters).GetField("_menuDropAlignment", BindingFlags.NonPublic | BindingFlags.Static) is FieldInfo field) + { + field.SetValue(null, leftAligned); + } + } + catch + { + } + } + } } \ No newline at end of file