From d8ecbd8efea8a1566e71d7e4f72f8ff40bb76162 Mon Sep 17 00:00:00 2001 From: CHINBOY Date: Sat, 19 Jul 2025 17:04:30 +0800 Subject: [PATCH] Refactor DataGridOperationButtons --- .../AtomUIDataGridThemesProvider.axaml | 1 + .../Column/DataGridColumnHeader.Sorting.cs | 2 +- .../Column/DataGridOperationButtons.cs | 123 ++++++++++++++++++ .../Column/DataGridOperationColumn.cs | 9 +- .../Column/Filters/DataGridFilterIndicator.cs | 2 +- .../DataGrid.Privates.cs | 21 ++- .../LanguageProviderPool.g.cs | 4 +- .../LanguageResourceConst.g.cs | 4 +- .../Localization/en_US.cs | 4 +- .../Localization/zh_CN.cs | 4 +- .../Row/DataGridRow.Privates.cs | 13 ++ .../Row/DataGridRow.cs | 1 + .../Themes/DataGridOperationButtons.axaml | 45 ++++++- .../Themes/DataGridThemeConstants.cs | 18 ++- .../Buttons/Themes/HyperLinkButtonTheme.axaml | 2 +- .../Flyouts/FlyoutStateHelper.cs | 12 +- .../LanguageResourceConst.g.cs | 3 + src/AtomUI.Controls/Localization/en_US.cs | 3 + src/AtomUI.Controls/Localization/zh_CN.cs | 3 + .../TextBlock/HyperLinkTextBlock.cs | 2 + .../TokenResourceConst.g.cs | 8 ++ .../TokenDefinitions/DesignToken.Alias.cs | 40 ++++++ .../TokenDefinitions/DesignToken.cs | 25 ++-- 23 files changed, 302 insertions(+), 47 deletions(-) diff --git a/src/AtomUI.Controls.DataGrid/AtomUIDataGridThemesProvider.axaml b/src/AtomUI.Controls.DataGrid/AtomUIDataGridThemesProvider.axaml index 4b843c9a7..034202cfe 100644 --- a/src/AtomUI.Controls.DataGrid/AtomUIDataGridThemesProvider.axaml +++ b/src/AtomUI.Controls.DataGrid/AtomUIDataGridThemesProvider.axaml @@ -17,6 +17,7 @@ + diff --git a/src/AtomUI.Controls.DataGrid/Column/DataGridColumnHeader.Sorting.cs b/src/AtomUI.Controls.DataGrid/Column/DataGridColumnHeader.Sorting.cs index a8e458306..504a24c54 100644 --- a/src/AtomUI.Controls.DataGrid/Column/DataGridColumnHeader.Sorting.cs +++ b/src/AtomUI.Controls.DataGrid/Column/DataGridColumnHeader.Sorting.cs @@ -6,7 +6,7 @@ using System.ComponentModel; using System.Diagnostics; using AtomUI.Controls.Data; -using AtomUI.Controls.DataGridLang; +using AtomUI.Controls.DataGridLocalization; using AtomUI.Controls.Utils; using AtomUI.Theme.Data; using Avalonia; diff --git a/src/AtomUI.Controls.DataGrid/Column/DataGridOperationButtons.cs b/src/AtomUI.Controls.DataGrid/Column/DataGridOperationButtons.cs index f5e971efe..37291b065 100644 --- a/src/AtomUI.Controls.DataGrid/Column/DataGridOperationButtons.cs +++ b/src/AtomUI.Controls.DataGrid/Column/DataGridOperationButtons.cs @@ -1,16 +1,27 @@ +using System.Diagnostics; +using AtomUI.Controls.Data; +using AtomUI.Data; using Avalonia; +using Avalonia.Controls; using Avalonia.Controls.Primitives; +using Avalonia.Data; +using Avalonia.Interactivity; namespace AtomUI.Controls; internal class DataGridOperationButtons : TemplatedControl { + #region 公共接口 + public static readonly StyledProperty IsMotionEnabledProperty = MotionAwareControlProperty.IsMotionEnabledProperty.AddOwner(); public static readonly StyledProperty IsEditEnabledProperty = AvaloniaProperty.Register(nameof(IsEditEnabled)); + public static readonly StyledProperty IsDeleteEnabledProperty = + AvaloniaProperty.Register(nameof(IsDeleteEnabled)); + public bool IsMotionEnabled { get => GetValue(IsMotionEnabledProperty); @@ -23,4 +34,116 @@ internal class DataGridOperationButtons : TemplatedControl set => SetValue(IsEditEnabledProperty, value); } + public bool IsDeleteEnabled + { + get => GetValue(IsDeleteEnabledProperty); + set => SetValue(IsDeleteEnabledProperty, value); + } + #endregion + + internal static readonly DirectProperty IsEditingProperty = + AvaloniaProperty.RegisterDirect( + nameof(IsEditing), + o => o.IsEditing, + (o, v) => o.IsEditing = v); + + internal bool IsEditing + { + get => _isEditing; + set => SetAndRaise(IsEditingProperty, ref _isEditing, value); + } + + private bool _isEditing; + + private HyperLinkTextBlock? _editAction; + private PopupConfirm? _deleteAction; + private HyperLinkTextBlock? _saveAction; + private PopupConfirm? _cancelAction; + private IDisposable? _disposable; + + internal DataGrid? OwningGrid { get; set; } + internal DataGridRow? OwningRow { get; set; } + + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) + { + base.OnApplyTemplate(e); + _editAction = e.NameScope.Find(DataGridOperationButtonsThemeConstants.EditActionPart); + _deleteAction = e.NameScope.Find(DataGridOperationButtonsThemeConstants.DeleteActionPart); + _saveAction = e.NameScope.Find(DataGridOperationButtonsThemeConstants.SaveActionPart); + _cancelAction = e.NameScope.Find(DataGridOperationButtonsThemeConstants.CancelActionPart); + + if (_editAction != null) + { + _editAction.Click += HandleEditingRow; + } + + if (_deleteAction != null) + { + _deleteAction.Confirmed += HandleDeleteRow; + } + + if (_cancelAction != null) + { + _cancelAction.Confirmed += HandleCancelEditingRow; + } + + if (_saveAction != null) + { + _saveAction.Click += HandleSaveRow; + } + } + + private void HandleDeleteRow(object? sender, RoutedEventArgs e) + { + if (OwningGrid != null) + { + var dataCollectionView = OwningGrid.DataConnection.CollectionView; + Debug.Assert(dataCollectionView != null); + var index = OwningRow?.Index; + if (index.HasValue) + { + dataCollectionView.RemoveAt(index.Value); + } + } + } + + private void HandleEditingRow(object? sender, RoutedEventArgs e) + { + if (OwningRow != null && OwningGrid != null) + { + SetValue(IsEditingProperty, true, BindingPriority.Template); + OwningGrid?.BeginRowEdit(OwningRow); + } + } + + private void HandleSaveRow(object? sender, RoutedEventArgs e) + { + if (OwningRow != null && OwningGrid != null) + { + SetValue(IsEditingProperty, false, BindingPriority.Template); + OwningGrid?.EndRowEdit(DataGridEditAction.Commit, true, true); + } + } + + + private void HandleCancelEditingRow(object? sender, RoutedEventArgs e) + { + if (OwningRow != null && OwningGrid != null) + { + SetValue(IsEditingProperty, false, BindingPriority.Template); + OwningGrid?.EndRowEdit(DataGridEditAction.Cancel, true, true); + } + } + + internal void NotifyLoadingRow(DataGridRow row) + { + OwningRow = row; + _disposable = BindUtils.RelayBind(row, DataGridRow.IsEditingModeProperty, this, IsEditingProperty); + } + + internal void NotifyUnLoadingRow(DataGridRow row) + { + _disposable?.Dispose(); + OwningRow = null; + } } \ No newline at end of file diff --git a/src/AtomUI.Controls.DataGrid/Column/DataGridOperationColumn.cs b/src/AtomUI.Controls.DataGrid/Column/DataGridOperationColumn.cs index 9201c5c86..9a892d6c1 100644 --- a/src/AtomUI.Controls.DataGrid/Column/DataGridOperationColumn.cs +++ b/src/AtomUI.Controls.DataGrid/Column/DataGridOperationColumn.cs @@ -24,6 +24,7 @@ public class DataGridOperationColumn : DataGridColumn { Debug.Assert(OwningGrid != null); var operationButtons = new DataGridOperationButtons(); + operationButtons.OwningGrid = OwningGrid; operationButtons[!DataGridOperationButtons.IsMotionEnabledProperty] = OwningGrid[!DataGrid.IsMotionEnabledProperty]; return operationButtons; } @@ -72,9 +73,9 @@ public class DataGridOperationColumn : DataGridColumn { if (OwningGrid != null) { - if (GetCellContent(e.Row) is DataGridRowExpander expander) + if (GetCellContent(e.Row) is DataGridOperationButtons operationButtons) { - expander.NotifyLoadingRow(e.Row); + operationButtons.NotifyLoadingRow(e.Row); } } } @@ -83,9 +84,9 @@ public class DataGridOperationColumn : DataGridColumn { if (OwningGrid != null) { - if (GetCellContent(e.Row) is DataGridRowExpander expander) + if (GetCellContent(e.Row) is DataGridOperationButtons operationButtons) { - expander.NotifyUnLoadingRow(e.Row); + operationButtons.NotifyUnLoadingRow(e.Row); } } } diff --git a/src/AtomUI.Controls.DataGrid/Column/Filters/DataGridFilterIndicator.cs b/src/AtomUI.Controls.DataGrid/Column/Filters/DataGridFilterIndicator.cs index abcc7ac6d..de39bcb81 100644 --- a/src/AtomUI.Controls.DataGrid/Column/Filters/DataGridFilterIndicator.cs +++ b/src/AtomUI.Controls.DataGrid/Column/Filters/DataGridFilterIndicator.cs @@ -1,7 +1,7 @@ using System.Collections.Specialized; using System.Diagnostics; using AtomUI.Controls.Data; -using AtomUI.Controls.DataGridLang; +using AtomUI.Controls.DataGridLocalization; using AtomUI.Data; using AtomUI.IconPkg.AntDesign; using AtomUI.Theme.Data; diff --git a/src/AtomUI.Controls.DataGrid/DataGrid.Privates.cs b/src/AtomUI.Controls.DataGrid/DataGrid.Privates.cs index 067ffab9d..9c87da18f 100644 --- a/src/AtomUI.Controls.DataGrid/DataGrid.Privates.cs +++ b/src/AtomUI.Controls.DataGrid/DataGrid.Privates.cs @@ -1310,7 +1310,7 @@ public partial class DataGrid if (newItemsSource is IDataGridCollectionView) { setDefaultSelection = true; - newCollectionView = (IDataGridCollectionView)newItemsSource; + newCollectionView = (IDataGridCollectionView)newItemsSource; } else { @@ -1412,8 +1412,8 @@ public partial class DataGrid } else { - column.HeaderCell.IsFirstVisible = false; - column.HeaderCell.IsLastVisible = false; + column.HeaderCell.IsFirstVisible = false; + column.HeaderCell.IsLastVisible = false; column.HeaderCell.IsMiddleVisible = true; } @@ -1494,9 +1494,9 @@ public partial class DataGrid dataGridCell: newCell); if (row.OwningGrid != null) { - newCell.OwningColumn = column; - newCell.IsVisible = column.IsVisible; - newCell[!SizeTypeProperty] = this[!SizeTypeProperty]; + newCell.OwningColumn = column; + newCell.IsVisible = column.IsVisible; + newCell[!SizeTypeProperty] = this[!SizeTypeProperty]; } row.Cells.Insert(column.Index, newCell); @@ -1577,7 +1577,7 @@ public partial class DataGrid } //TODO Validation - private bool BeginRowEdit(DataGridRow dataGridRow) + internal bool BeginRowEdit(DataGridRow dataGridRow) { Debug.Assert(EditingRow == null); Debug.Assert(dataGridRow != null); @@ -2505,7 +2505,7 @@ public partial class DataGrid } //TODO Validation - private bool EndRowEdit(DataGridEditAction editAction, bool exitEditingMode, bool raiseEvents) + internal bool EndRowEdit(DataGridEditAction editAction, bool exitEditingMode, bool raiseEvents) { if (EditingRow == null || DataConnection.CommittingEdit) { @@ -2867,7 +2867,6 @@ public partial class DataGrid Debug.Assert(dataGridCell != null); Control? element = null; - DataGridBoundColumn? dataGridBoundColumn = dataGridColumn as DataGridBoundColumn; Debug.Assert(dataGridRow.DataContext != null); if (isCellEdited) { @@ -2878,7 +2877,7 @@ public partial class DataGrid dataGridCell.Content = element; if (element.IsInitialized) { - PreparingCellForEditPrivate(element as Control); + PreparingCellForEditPrivate(element); } else { @@ -4589,7 +4588,7 @@ public partial class DataGrid else { if (Footer == null && (GridLinesVisibility == DataGridGridLinesVisibility.All || - GridLinesVisibility == DataGridGridLinesVisibility.Horizontal)) + GridLinesVisibility == DataGridGridLinesVisibility.Horizontal)) { SetValue(FrameBorderThicknessProperty, new Thickness(BorderThickness.Left, BorderThickness.Top, BorderThickness.Right, 0)); } diff --git a/src/AtomUI.Controls.DataGrid/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.LanguageGenerator/LanguageProviderPool.g.cs b/src/AtomUI.Controls.DataGrid/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.LanguageGenerator/LanguageProviderPool.g.cs index 3791dd332..2de687db6 100644 --- a/src/AtomUI.Controls.DataGrid/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.LanguageGenerator/LanguageProviderPool.g.cs +++ b/src/AtomUI.Controls.DataGrid/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.LanguageGenerator/LanguageProviderPool.g.cs @@ -8,8 +8,8 @@ namespace AtomUI.Theme internal static IList GetLanguageProviders() { List languageProviders = new List(); - languageProviders.Add(new AtomUI.Controls.DataGridLang.en_US()); - languageProviders.Add(new AtomUI.Controls.DataGridLang.zh_CN()); + languageProviders.Add(new AtomUI.Controls.DataGridLocalization.en_US()); + languageProviders.Add(new AtomUI.Controls.DataGridLocalization.zh_CN()); return languageProviders; } } diff --git a/src/AtomUI.Controls.DataGrid/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.LanguageGenerator/LanguageResourceConst.g.cs b/src/AtomUI.Controls.DataGrid/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.LanguageGenerator/LanguageResourceConst.g.cs index 378244e4a..698850117 100644 --- a/src/AtomUI.Controls.DataGrid/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.LanguageGenerator/LanguageResourceConst.g.cs +++ b/src/AtomUI.Controls.DataGrid/GeneratedFiles/AtomUI.Generator/AtomUI.Generator.LanguageGenerator/LanguageResourceConst.g.cs @@ -1,11 +1,13 @@ using AtomUI.Theme; -namespace AtomUI.Controls.DataGridLang +namespace AtomUI.Controls.DataGridLocalization { public static class DataGridLangResourceKey { public static readonly LanguageResourceKey AscendTooltip = new LanguageResourceKey("DataGrid.AscendTooltip", "AtomUI.Lang"); + public static readonly LanguageResourceKey CancelConfirmText = new LanguageResourceKey("DataGrid.CancelConfirmText", "AtomUI.Lang"); public static readonly LanguageResourceKey CancelTooltip = new LanguageResourceKey("DataGrid.CancelTooltip", "AtomUI.Lang"); + public static readonly LanguageResourceKey DeleteConfirmText = new LanguageResourceKey("DataGrid.DeleteConfirmText", "AtomUI.Lang"); public static readonly LanguageResourceKey DescendTooltip = new LanguageResourceKey("DataGrid.DescendTooltip", "AtomUI.Lang"); public static readonly LanguageResourceKey SelectAllFilterItems = new LanguageResourceKey("DataGrid.SelectAllFilterItems", "AtomUI.Lang"); } diff --git a/src/AtomUI.Controls.DataGrid/Localization/en_US.cs b/src/AtomUI.Controls.DataGrid/Localization/en_US.cs index 27156fc2a..40f2e7610 100644 --- a/src/AtomUI.Controls.DataGrid/Localization/en_US.cs +++ b/src/AtomUI.Controls.DataGrid/Localization/en_US.cs @@ -1,7 +1,7 @@ using AtomUI.Theme; using AtomUI.Utils; -namespace AtomUI.Controls.DataGridLang; +namespace AtomUI.Controls.DataGridLocalization; [LanguageProvider(LanguageCode.en_US, DataGridToken.ID)] internal class en_US : AbstractLanguageProvider @@ -10,4 +10,6 @@ internal class en_US : AbstractLanguageProvider public const string AscendTooltip = "Click to sort ascending"; public const string DescendTooltip = "Click to sort descending"; public const string CancelTooltip = "Click to cancel sorting"; + public const string DeleteConfirmText = "Sure to delete?"; + public const string CancelConfirmText = "Sure to cancel?"; } \ No newline at end of file diff --git a/src/AtomUI.Controls.DataGrid/Localization/zh_CN.cs b/src/AtomUI.Controls.DataGrid/Localization/zh_CN.cs index 21aec1975..b7982233b 100644 --- a/src/AtomUI.Controls.DataGrid/Localization/zh_CN.cs +++ b/src/AtomUI.Controls.DataGrid/Localization/zh_CN.cs @@ -1,7 +1,7 @@ using AtomUI.Theme; using AtomUI.Utils; -namespace AtomUI.Controls.DataGridLang; +namespace AtomUI.Controls.DataGridLocalization; [LanguageProvider(LanguageCode.zh_CN, DataGridToken.ID)] internal class zh_CN : AbstractLanguageProvider @@ -10,4 +10,6 @@ internal class zh_CN : AbstractLanguageProvider public const string AscendTooltip = "点击升序"; public const string DescendTooltip = "点击降序"; public const string CancelTooltip = "取消排序"; + public const string DeleteConfirmText = "确认删除?"; + public const string CancelConfirmText = "确认取消?"; } \ No newline at end of file diff --git a/src/AtomUI.Controls.DataGrid/Row/DataGridRow.Privates.cs b/src/AtomUI.Controls.DataGrid/Row/DataGridRow.Privates.cs index da152042c..16ac143e7 100644 --- a/src/AtomUI.Controls.DataGrid/Row/DataGridRow.Privates.cs +++ b/src/AtomUI.Controls.DataGrid/Row/DataGridRow.Privates.cs @@ -36,6 +36,11 @@ public partial class DataGridRow internal static readonly StyledProperty IsDraggingProperty = AvaloniaProperty.Register(nameof(IsDragging)); + internal static readonly DirectProperty IsEditingModeProperty = + AvaloniaProperty.RegisterDirect( + nameof(IsEditingMode), + o => o.IsEditingMode); + internal bool IsMotionEnabled { get => GetValue(IsMotionEnabledProperty); @@ -54,6 +59,13 @@ public partial class DataGridRow set => SetValue(IsDraggingProperty, value); } + internal bool IsEditingMode + { + get => _isEditingMode; + set => SetAndRaise(IsEditingModeProperty, ref _isEditingMode, value); + } + private bool _isEditingMode = false; + internal int Slot { get; set; } internal DataGridCellCollection Cells { get; private set; } @@ -483,6 +495,7 @@ public partial class DataGridRow IsSelected = isSelected; PseudoClasses.Set(StdPseudoClass.Editing, IsEditing); PseudoClasses.Set(StdPseudoClass.Invalid, !IsValid); + IsEditingMode = IsEditing; ApplyHeaderStatus(); } } diff --git a/src/AtomUI.Controls.DataGrid/Row/DataGridRow.cs b/src/AtomUI.Controls.DataGrid/Row/DataGridRow.cs index 9ead504c5..1c96a9649 100644 --- a/src/AtomUI.Controls.DataGrid/Row/DataGridRow.cs +++ b/src/AtomUI.Controls.DataGrid/Row/DataGridRow.cs @@ -77,6 +77,7 @@ public partial class DataGridRow : TemplatedControl } private bool _isSelected; + public bool IsSelected { get => _isSelected; diff --git a/src/AtomUI.Controls.DataGrid/Themes/DataGridOperationButtons.axaml b/src/AtomUI.Controls.DataGrid/Themes/DataGridOperationButtons.axaml index 76aac1da0..a97c9d9af 100644 --- a/src/AtomUI.Controls.DataGrid/Themes/DataGridOperationButtons.axaml +++ b/src/AtomUI.Controls.DataGrid/Themes/DataGridOperationButtons.axaml @@ -1,12 +1,51 @@ - + xmlns:atom="https://atomui.net" + xmlns:dataGridLocalization="clr-namespace:AtomUI.Controls.DataGridLocalization" + xmlns:localization="clr-namespace:AtomUI.Controls.Localization;assembly=AtomUI.Controls"> + - + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AtomUI.Controls.DataGrid/Themes/DataGridThemeConstants.cs b/src/AtomUI.Controls.DataGrid/Themes/DataGridThemeConstants.cs index 0a65e8710..e527be24d 100644 --- a/src/AtomUI.Controls.DataGrid/Themes/DataGridThemeConstants.cs +++ b/src/AtomUI.Controls.DataGrid/Themes/DataGridThemeConstants.cs @@ -32,12 +32,6 @@ internal static class DataGridColumnHeaderThemeConstants public const string FocusVisualSecondaryPart = "PART_FocusVisualSecondary"; } -internal static class DataGridFilterIndicatorThemeConstants -{ - public const string FramePart = "PART_Frame"; - public const string IconPresenterPart = "PART_IconPresenter"; -} - internal static class DataGridHeaderViewItemThemeConstants { public const string ContentPresenterPart = "PART_ContentPresenter"; @@ -106,10 +100,6 @@ internal static class DataGridThemeConstants public const string DraggingOverIndicatorPart = "PART_DraggingOverIndicator"; } -internal static class DataGridTopLeftColumnHeaderThemeConstants -{ -} - internal static class DataGridFilterFlyoutPresenterThemeConstants { public const string ButtonLayoutPart = "PART_ButtonLayout"; @@ -128,4 +118,12 @@ internal static class DataGridRowExpanderThemeConstants internal static class DataGridRowReorderHandleConstants { public const string IndicatorIconButtonPart = "PART_IndicatorIconButton"; +} + +internal static class DataGridOperationButtonsThemeConstants +{ + public const string EditActionPart = "PART_EditAction"; + public const string DeleteActionPart = "PART_DeleteAction"; + public const string CancelActionPart = "PAR_CancelAction"; + public const string SaveActionPart = "PAR_SaveAction"; } \ No newline at end of file diff --git a/src/AtomUI.Controls/Buttons/Themes/HyperLinkButtonTheme.axaml b/src/AtomUI.Controls/Buttons/Themes/HyperLinkButtonTheme.axaml index 096e98d64..f20f0c04e 100644 --- a/src/AtomUI.Controls/Buttons/Themes/HyperLinkButtonTheme.axaml +++ b/src/AtomUI.Controls/Buttons/Themes/HyperLinkButtonTheme.axaml @@ -226,7 +226,7 @@