diff --git a/Main.Test/App.xaml b/Main.Test/App.xaml
index 25275cd..e9613f0 100644
--- a/Main.Test/App.xaml
+++ b/Main.Test/App.xaml
@@ -11,7 +11,7 @@
-
+
diff --git a/Main.Test/DataGridEx.cs b/Main.Test/DataGridEx.cs
deleted file mode 100644
index 437effa..0000000
--- a/Main.Test/DataGridEx.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows.Controls;
-
-namespace Main.Test;
-
-public class DataGridEx : DataGrid
-{
-
-}
diff --git a/Main.Test/DataGridHelper.cs b/Main.Test/DataGridHelper.cs
index 88d55d2..ff1c76a 100644
--- a/Main.Test/DataGridHelper.cs
+++ b/Main.Test/DataGridHelper.cs
@@ -63,12 +63,15 @@ public class DataGridHelper
public static DependencyProperty ShowRowNumberProperty = DependencyProperty.RegisterAttached("ShowRowNumber",
- typeof(bool), typeof(DataGridAttach),
+ typeof(bool), typeof(DataGridHelper),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits, OnShowRowNumberChanged));
public static bool GetShowRowNumber(DependencyObject target) => (bool)target.GetValue(ShowRowNumberProperty);
- public static void SetShowRowNumber(DependencyObject target, bool value) => target.SetValue(ShowRowNumberProperty, value);
+ public static void SetShowRowNumber(DependencyObject target, bool value)
+ {
+ target.SetValue(ShowRowNumberProperty, value);
+ }
private static void OnShowRowNumberChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
{
@@ -118,7 +121,10 @@ public class DataGridHelper
}
}
- private static void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e) => e.Row.Header = (e.Row.GetIndex() + 1).ToString();
+ private static void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
+ {
+ e.Row.Header = (e.Row.GetIndex() + 1).ToString();
+ }
@@ -126,7 +132,6 @@ public class DataGridHelper
public static readonly DependencyProperty ShowBorderProperty =
DependencyProperty.RegisterAttached("ShowBorder", typeof(bool),
typeof(DataGridHelper), new PropertyMetadata(false, OnShowBorderChanged));
-
public static void SetShowBorder(DependencyObject element, bool value)
=> element.SetValue(ShowBorderProperty, value);
@@ -166,24 +171,3 @@ public class BorderAdorner : Adorner
new Point(header.ActualWidth - 0.5, header.ActualHeight));
}
}
-// 先创建自定义类(如果还没创建)
-public class CustomDataGridColumnHeader : DataGridColumnHeader
-{
- protected override void OnRender(DrawingContext drawingContext)
- {
- base.OnRender(drawingContext);
-
- // 在这里绘制边框,永远不消失
- var pen = new Pen(new SolidColorBrush(Colors.LightGray), 1);
-
- // 绘制右侧竖线
- drawingContext.DrawLine(pen,
- new Point(ActualWidth - 0.5, 0),
- new Point(ActualWidth - 0.5, ActualHeight));
-
- // 绘制底部横线(如果需要)
- // drawingContext.DrawLine(pen,
- // new Point(0, ActualHeight - 0.5),
- // new Point(ActualWidth, ActualHeight - 0.5));
- }
-}
\ No newline at end of file
diff --git a/Main.Test/Dictionary1.xaml b/Main.Test/Dictionary1.xaml
index 42078cb..1ca4940 100644
--- a/Main.Test/Dictionary1.xaml
+++ b/Main.Test/Dictionary1.xaml
@@ -3,16 +3,10 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ext="clr-namespace:Main.Test"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
-
-
-
-
+
+
+
-
-
+ SelectedRowForeground="White"
+ SelectionMode="Extended"
+ ShowCheckBox="True"
+ ShowRowNumber="True">
+
-
-
+
+
diff --git a/Main.Test/StyledDataGrid.cs b/Main.Test/StyledDataGrid.cs
new file mode 100644
index 0000000..61efc87
--- /dev/null
+++ b/Main.Test/StyledDataGrid.cs
@@ -0,0 +1,130 @@
+using System.Collections.Specialized;
+using System.Globalization;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Threading;
+
+namespace Main.Test;
+
+/// 带默认样式、行号和行选择勾选框的 DataGrid。
+public class StyledDataGrid : DataGrid
+{
+ public static readonly RoutedUICommand ToggleSelectAllCommand = new("全选或取消全选", nameof(ToggleSelectAllCommand), typeof(StyledDataGrid));
+ private static readonly DependencyPropertyKey AreAllRowsSelectedPropertyKey = DependencyProperty.RegisterReadOnly(
+ nameof(AreAllRowsSelected), typeof(bool?), typeof(StyledDataGrid), new PropertyMetadata(false));
+ public static readonly DependencyProperty AreAllRowsSelectedProperty = AreAllRowsSelectedPropertyKey.DependencyProperty;
+ /// 全部选中为 true,部分选中为 null,未选中为 false。
+ public bool? AreAllRowsSelected => (bool?)GetValue(AreAllRowsSelectedProperty);
+ public static readonly DependencyProperty SelectedRowBackgroundProperty = DependencyProperty.Register(
+ nameof(SelectedRowBackground), typeof(Brush), typeof(StyledDataGrid),
+ new PropertyMetadata(new SolidColorBrush(Color.FromRgb(75, 178, 255))));
+ public static readonly DependencyProperty SelectedRowForegroundProperty = DependencyProperty.Register(
+ nameof(SelectedRowForeground), typeof(Brush), typeof(StyledDataGrid), new PropertyMetadata(Brushes.White));
+ public static readonly DependencyProperty ShowCheckBoxProperty = DependencyProperty.Register(
+ nameof(ShowCheckBox), typeof(bool), typeof(StyledDataGrid), new PropertyMetadata(false, HeaderOptionsChanged));
+ public static readonly DependencyProperty ShowRowNumberProperty = DependencyProperty.Register(
+ nameof(ShowRowNumber), typeof(bool), typeof(StyledDataGrid), new PropertyMetadata(false, HeaderOptionsChanged));
+
+ public Brush SelectedRowBackground { get => (Brush)GetValue(SelectedRowBackgroundProperty); set => SetValue(SelectedRowBackgroundProperty, value); }
+ public Brush SelectedRowForeground { get => (Brush)GetValue(SelectedRowForegroundProperty); set => SetValue(SelectedRowForegroundProperty, value); }
+ /// 勾选状态与行 IsSelected 同步,可通过 SelectedItems 获取。
+ public bool ShowCheckBox { get => (bool)GetValue(ShowCheckBoxProperty); set => SetValue(ShowCheckBoxProperty, value); }
+ public bool ShowRowNumber { get => (bool)GetValue(ShowRowNumberProperty); set => SetValue(ShowRowNumberProperty, value); }
+
+ static StyledDataGrid()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(StyledDataGrid), new FrameworkPropertyMetadata(typeof(StyledDataGrid)));
+ }
+
+ public StyledDataGrid()
+ {
+ CommandBindings.Add(new CommandBinding(ToggleSelectAllCommand, (_, e) =>
+ {
+ if (AreAllRowsSelected == true) UnselectAll();
+ else SelectAll();
+ e.Handled = true;
+ }, (_, e) =>
+ {
+ e.CanExecute = SelectionMode == DataGridSelectionMode.Extended &&
+ SelectionUnit != DataGridSelectionUnit.Cell && SelectableItemCount > 0;
+ e.Handled = true;
+ }));
+ LoadingRow += (_, e) => UpdateRowNumber(e.Row);
+ ItemContainerGenerator.ItemsChanged += (_, _) => QueueHeaderUpdate();
+ Loaded += (_, _) => QueueHeaderUpdate();
+ }
+
+ private static void HeaderOptionsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ => ((StyledDataGrid)d).QueueHeaderUpdate();
+
+ protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
+ {
+ base.OnItemsChanged(e);
+ QueueHeaderUpdate();
+ UpdateSelectAllState();
+ }
+
+ private int SelectableItemCount => Items.Count - (Items.Contains(System.Windows.Data.CollectionView.NewItemPlaceholder) ? 1 : 0);
+
+ protected override void OnSelectionChanged(SelectionChangedEventArgs e)
+ {
+ base.OnSelectionChanged(e);
+ UpdateSelectAllState();
+ }
+
+ private void UpdateSelectAllState()
+ {
+ SetValue(AreAllRowsSelectedPropertyKey, SelectedItems.Count == 0 ? false :
+ SelectedItems.Count == SelectableItemCount ? true : (bool?)null);
+ CommandManager.InvalidateRequerySuggested();
+ }
+
+ protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
+ {
+ base.OnPropertyChanged(e);
+ if (e.Property == FontSizeProperty || e.Property == FontFamilyProperty ||
+ e.Property == FontStyleProperty || e.Property == FontWeightProperty || e.Property == FontStretchProperty)
+ QueueHeaderUpdate();
+ }
+
+ private bool headerUpdatePending;
+ private void QueueHeaderUpdate()
+ {
+ if (headerUpdatePending) return;
+ headerUpdatePending = true;
+ Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() =>
+ {
+ headerUpdatePending = false;
+ // 使用最宽数字估算所有行号,避免虚拟化滚动时行头宽度跳变。
+ var digits = Math.Max(1, Items.Count.ToString(CultureInfo.InvariantCulture).Length);
+ var numberWidth = 0d;
+ if (ShowRowNumber)
+ for (var digit = '0'; digit <= '9'; digit++)
+ {
+ var text = new FormattedText(new string(digit, digits), CultureInfo.CurrentCulture,
+ FlowDirection, new Typeface(FontFamily, FontStyle, FontWeight, FontStretch),
+ FontSize, Foreground ?? Brushes.Black, VisualTreeHelper.GetDpi(this).PixelsPerDip);
+ numberWidth = Math.Max(numberWidth, Math.Ceiling(text.WidthIncludingTrailingWhitespace) + 16);
+ }
+ SetCurrentValue(RowHeaderWidthProperty, numberWidth + (ShowCheckBox ? 32 : 0) +
+ (ShowRowNumber && ShowCheckBox ? 1 : 0) + (ShowRowNumber || ShowCheckBox ? 1 : 0));
+ foreach (var row in GetRealizedRows(this)) UpdateRowNumber(row);
+ }));
+ }
+
+ private void UpdateRowNumber(DataGridRow row)
+ => row.SetCurrentValue(DataGridRow.HeaderProperty, ShowRowNumber ? (row.GetIndex() + 1).ToString(CultureInfo.CurrentCulture) : null);
+
+ private IEnumerable GetRealizedRows(DependencyObject parent)
+ {
+ for (var i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
+ {
+ var child = VisualTreeHelper.GetChild(parent, i);
+ if (child is DataGridRow row && ItemsControl.ItemsControlFromItemContainer(row) == this) yield return row;
+ else if (child is not DataGrid)
+ foreach (var descendant in GetRealizedRows(child)) yield return descendant;
+ }
+ }
+}
diff --git a/Main.Test/Themes/Generic.xaml b/Main.Test/Themes/Generic.xaml
new file mode 100644
index 0000000..6ab3487
--- /dev/null
+++ b/Main.Test/Themes/Generic.xaml
@@ -0,0 +1,249 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Main.Test/ViewModels/MainViewModel.cs b/Main.Test/ViewModels/MainViewModel.cs
index 820ad91..bb8446a 100644
--- a/Main.Test/ViewModels/MainViewModel.cs
+++ b/Main.Test/ViewModels/MainViewModel.cs
@@ -32,7 +32,7 @@ internal class MainViewModel
var singleItem = itemFaker.Generate();
// 生成100个对象
- Data = itemFaker.Generate(100);
+ Data = itemFaker.Generate(1000);
//Data.Clear();
}
}