Browse Source

Merge pull request #7292 from AvaloniaUI/upgrade-datagrid

Upgrade DataGrid
Max Katz 3 năm trước cách đây
mục cha
commit
6b4cf247d7

+ 17 - 2
samples/ControlCatalog/Pages/DataGridPage.xaml

@@ -13,9 +13,22 @@
   </UserControl.Resources>
   </UserControl.Resources>
   <UserControl.Styles>
   <UserControl.Styles>
     <Style Selector="DataGridCell.gdp">
     <Style Selector="DataGridCell.gdp">
-      <Setter Property="FontWeight" Value="Bold" />
       <Setter Property="Background" Value="{Binding Path=GDP, Mode=OneWay, Converter={StaticResource GDPConverter}}" />
       <Setter Property="Background" Value="{Binding Path=GDP, Mode=OneWay, Converter={StaticResource GDPConverter}}" />
     </Style>
     </Style>
+    <Style Selector="DataGridColumnHeader:nth-last-child(1)">
+      <Setter Property="FontWeight" Value="Bold" />
+    </Style>
+    <Style Selector="DataGridCell:nth-last-child(1)">
+      <Setter Property="FontWeight" Value="Bold" />
+    </Style>
+    <Style Selector="DataGrid#dataGridGrouping DataGridRow:nth-child(5n+3)">
+      <Setter Property="Foreground" Value="Red" />
+      <Setter Property="FontWeight" Value="Bold" />
+    </Style>
+    <Style Selector="DataGrid#dataGridGrouping DataGridRow:nth-last-child(5n+1)">
+      <Setter Property="Foreground" Value="Blue" />
+      <Setter Property="FontWeight" Value="Bold" />
+    </Style>
   </UserControl.Styles>
   </UserControl.Styles>
   <Grid RowDefinitions="Auto,Auto,*">
   <Grid RowDefinitions="Auto,Auto,*">
     <StackPanel Orientation="Vertical" Spacing="4" Grid.Row="0">
     <StackPanel Orientation="Vertical" Spacing="4" Grid.Row="0">
@@ -31,7 +44,9 @@
         <DockPanel>
         <DockPanel>
           <CheckBox x:Name="ShowGDP"  IsChecked="True"  Content="Toggle GDP Column Visibility"
           <CheckBox x:Name="ShowGDP"  IsChecked="True"  Content="Toggle GDP Column Visibility"
                     DockPanel.Dock="Top"/>
                     DockPanel.Dock="Top"/>
-          <DataGrid Name="dataGrid1" Margin="12" CanUserResizeColumns="True" CanUserReorderColumns="True" CanUserSortColumns="True" HeadersVisibility="All">
+          <DataGrid Name="dataGrid1" Margin="12" CanUserResizeColumns="True" CanUserReorderColumns="True" CanUserSortColumns="True" HeadersVisibility="All"
+                    RowBackground="#1000"
+                    AlternatingRowBackground="#1fff">
             <DataGrid.Columns>
             <DataGrid.Columns>
               <!-- Using HeaderTemplate -->
               <!-- Using HeaderTemplate -->
               <DataGridTextColumn Header="Country" HeaderTemplate="{StaticResource Demo.DataTemplates.CountryHeader}" Binding="{Binding Name}" Width="6*" />
               <DataGridTextColumn Header="Country" HeaderTemplate="{StaticResource Demo.DataTemplates.CountryHeader}" Binding="{Binding Name}" Width="6*" />

+ 3 - 1
src/Avalonia.Base/LogicalTree/ChildIndexChangedEventArgs.cs

@@ -8,7 +8,9 @@ namespace Avalonia.LogicalTree
     /// </summary>
     /// </summary>
     public class ChildIndexChangedEventArgs : EventArgs
     public class ChildIndexChangedEventArgs : EventArgs
     {
     {
-        public ChildIndexChangedEventArgs()
+        public static new ChildIndexChangedEventArgs Empty { get; } = new ChildIndexChangedEventArgs();
+
+        private ChildIndexChangedEventArgs()
         {
         {
         }
         }
 
 

+ 0 - 10
src/Avalonia.Controls.DataGrid/DataGrid.cs

@@ -669,8 +669,6 @@ namespace Avalonia.Controls
             ItemsProperty.Changed.AddClassHandler<DataGrid>((x, e) => x.OnItemsPropertyChanged(e));
             ItemsProperty.Changed.AddClassHandler<DataGrid>((x, e) => x.OnItemsPropertyChanged(e));
             CanUserResizeColumnsProperty.Changed.AddClassHandler<DataGrid>((x, e) => x.OnCanUserResizeColumnsChanged(e));
             CanUserResizeColumnsProperty.Changed.AddClassHandler<DataGrid>((x, e) => x.OnCanUserResizeColumnsChanged(e));
             ColumnWidthProperty.Changed.AddClassHandler<DataGrid>((x, e) => x.OnColumnWidthChanged(e));
             ColumnWidthProperty.Changed.AddClassHandler<DataGrid>((x, e) => x.OnColumnWidthChanged(e));
-            RowBackgroundProperty.Changed.AddClassHandler<DataGrid>((x, e) => x.OnRowBackgroundChanged(e));
-            AlternatingRowBackgroundProperty.Changed.AddClassHandler<DataGrid>((x, e) => x.OnRowBackgroundChanged(e));
             FrozenColumnCountProperty.Changed.AddClassHandler<DataGrid>((x, e) => x.OnFrozenColumnCountChanged(e));
             FrozenColumnCountProperty.Changed.AddClassHandler<DataGrid>((x, e) => x.OnFrozenColumnCountChanged(e));
             GridLinesVisibilityProperty.Changed.AddClassHandler<DataGrid>((x, e) => x.OnGridLinesVisibilityChanged(e));
             GridLinesVisibilityProperty.Changed.AddClassHandler<DataGrid>((x, e) => x.OnGridLinesVisibilityChanged(e));
             HeadersVisibilityProperty.Changed.AddClassHandler<DataGrid>((x, e) => x.OnHeadersVisibilityChanged(e));
             HeadersVisibilityProperty.Changed.AddClassHandler<DataGrid>((x, e) => x.OnHeadersVisibilityChanged(e));
@@ -1144,14 +1142,6 @@ namespace Avalonia.Controls
             InvalidateCellsArrange();
             InvalidateCellsArrange();
         }
         }
 
 
-        private void OnRowBackgroundChanged(AvaloniaPropertyChangedEventArgs e)
-        {
-            foreach (DataGridRow row in GetAllRows())
-            {
-                row.EnsureBackground();
-            }
-        }
-
         private void OnColumnWidthChanged(AvaloniaPropertyChangedEventArgs e)
         private void OnColumnWidthChanged(AvaloniaPropertyChangedEventArgs e)
         {
         {
             var value = (DataGridLength)e.NewValue;
             var value = (DataGridLength)e.NewValue;

+ 1 - 1
src/Avalonia.Controls.DataGrid/DataGridColumn.cs

@@ -199,7 +199,7 @@ namespace Avalonia.Controls
             if (change.Property == IsVisibleProperty)
             if (change.Property == IsVisibleProperty)
             {
             {
                 OwningGrid?.OnColumnVisibleStateChanging(this);
                 OwningGrid?.OnColumnVisibleStateChanging(this);
-                var isVisible = (change as AvaloniaPropertyChangedEventArgs<bool>).NewValue.Value;
+                var isVisible = change.NewValue.GetValueOrDefault<bool>();
 
 
                 if (_headerCell != null)
                 if (_headerCell != null)
                 {
                 {

+ 19 - 17
src/Avalonia.Controls.DataGrid/DataGridColumnCollection.cs

@@ -12,7 +12,8 @@ namespace Avalonia.Controls
 {
 {
     internal class DataGridColumnCollection : ObservableCollection<DataGridColumn>
     internal class DataGridColumnCollection : ObservableCollection<DataGridColumn>
     {
     {
-        private DataGrid _owningGrid;
+        private readonly Dictionary<int, int> _columnsMap = new Dictionary<int, int>();
+        private readonly DataGrid _owningGrid;
 
 
         public DataGridColumnCollection(DataGrid owningGrid)
         public DataGridColumnCollection(DataGrid owningGrid)
         {
         {
@@ -124,18 +125,8 @@ namespace Avalonia.Controls
 
 
         internal int VisibleColumnCount
         internal int VisibleColumnCount
         {
         {
-            get
-            {
-                int visibleColumnCount = 0;
-                for (int columnIndex = 0; columnIndex < ItemsInternal.Count; columnIndex++)
-                {
-                    if (ItemsInternal[columnIndex].IsVisible)
-                    {
-                        visibleColumnCount++;
-                    }
-                }
-                return visibleColumnCount;
-            }
+            get;
+            private set;
         }
         }
 
 
         internal double VisibleEdgedColumnsWidth
         internal double VisibleEdgedColumnsWidth
@@ -287,20 +278,31 @@ namespace Avalonia.Controls
         {
         {
             VisibleStarColumnCount = 0;
             VisibleStarColumnCount = 0;
             VisibleEdgedColumnsWidth = 0;
             VisibleEdgedColumnsWidth = 0;
+            VisibleColumnCount = 0;
+            _columnsMap.Clear();
+
             for (int columnIndex = 0; columnIndex < ItemsInternal.Count; columnIndex++)
             for (int columnIndex = 0; columnIndex < ItemsInternal.Count; columnIndex++)
             {
             {
-                if (ItemsInternal[columnIndex].IsVisible)
+                var item = ItemsInternal[columnIndex];
+                _columnsMap[columnIndex] = item.DisplayIndex;
+                if (item.IsVisible)
                 {
                 {
-                    ItemsInternal[columnIndex].EnsureWidth();
-                    if (ItemsInternal[columnIndex].Width.IsStar)
+                    VisibleColumnCount++;
+                    item.EnsureWidth();
+                    if (item.Width.IsStar)
                     {
                     {
                         VisibleStarColumnCount++;
                         VisibleStarColumnCount++;
                     }
                     }
-                    VisibleEdgedColumnsWidth += ItemsInternal[columnIndex].ActualWidth;
+                    VisibleEdgedColumnsWidth += item.ActualWidth;
                 }
                 }
             }
             }
         }
         }
 
 
+        internal int GetColumnDisplayIndex(int columnIndex)
+        {
+            return _columnsMap.TryGetValue(columnIndex, out var displayIndex) ? displayIndex : -1;
+        }
+
         internal DataGridColumn GetColumnAtDisplayIndex(int displayIndex)
         internal DataGridColumn GetColumnAtDisplayIndex(int displayIndex)
         {
         {
             if (displayIndex < 0 || displayIndex >= ItemsInternal.Count || displayIndex >= DisplayIndexMap.Count)
             if (displayIndex < 0 || displayIndex >= ItemsInternal.Count || displayIndex >= DisplayIndexMap.Count)

+ 4 - 5
src/Avalonia.Controls.DataGrid/DataGridColumns.cs

@@ -444,12 +444,11 @@ namespace Avalonia.Controls
 
 
             // We need to explicitly collapse the cells of the invisible column because layout only goes through
             // We need to explicitly collapse the cells of the invisible column because layout only goes through
             // visible ones
             // visible ones
-            if (!updatedColumn.IsVisible)
+            ColumnHeaders?.InvalidateChildIndex();
+            foreach (var row in GetAllRows())
             {
             {
-                foreach (DataGridRow row in GetAllRows())
-                {
-                    row.Cells[updatedColumn.Index].IsVisible = false;
-                }
+                row.Cells[updatedColumn.Index].IsVisible = updatedColumn.IsVisible;
+                row.InvalidateCellsIndex();
             }
             }
         }
         }
 
 

+ 19 - 17
src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs

@@ -77,7 +77,7 @@ namespace Avalonia.Controls
             private set;
             private set;
         }
         }
 
 
-        public int Count => GetCount(true);
+        public int Count => TryGetCount(true, false, out var count) ? count : 0;
 
 
         public bool DataIsPrimitive
         public bool DataIsPrimitive
         {
         {
@@ -193,22 +193,25 @@ namespace Avalonia.Controls
             }
             }
         }
         }
 
 
-        internal bool Any()
-        {
-            return GetCount(false) > 0;
-        }
-
         /// <param name="allowSlow">When "allowSlow" is false, method will not use Linq.Count() method and will return 0 or 1 instead.</param>
         /// <param name="allowSlow">When "allowSlow" is false, method will not use Linq.Count() method and will return 0 or 1 instead.</param>
-        private int GetCount(bool allowSlow)
+        /// <param name="getAny">If "getAny" is true, method can use Linq.Any() method to speedup.</param>
+        internal bool TryGetCount(bool allowSlow, bool getAny, out int count)
         {
         {
-            return DataSource switch
+            bool result;
+            (result, count) = DataSource switch
             {
             {
-                ICollection collection => collection.Count,
-                DataGridCollectionView cv => cv.Count,
-                IEnumerable enumerable when allowSlow => enumerable.Cast<object>().Count(),
-                IEnumerable enumerable when !allowSlow => enumerable.Cast<object>().Any() ? 1 : 0,
-                _ => 0
+                ICollection collection => (true, collection.Count),
+                DataGridCollectionView cv => (true, cv.Count),
+                IEnumerable enumerable when allowSlow && !getAny => (true, enumerable.Cast<object>().Count()),
+                IEnumerable enumerable when getAny => (true, enumerable.Cast<object>().Any() ? 1 : 0),
+                _ => (false, 0)
             };
             };
+            return result;
+        }
+
+        internal bool Any()
+        {
+            return TryGetCount(false, true, out var count) && count > 0;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -383,7 +386,7 @@ namespace Avalonia.Controls
                     List<string> propertyNames = TypeHelper.SplitPropertyPath(propertyName);
                     List<string> propertyNames = TypeHelper.SplitPropertyPath(propertyName);
                     for (int i = 0; i < propertyNames.Count; i++)
                     for (int i = 0; i < propertyNames.Count; i++)
                     {
                     {
-                        propertyInfo = propertyType.GetPropertyOrIndexer(propertyNames[i], out object[] index);
+                        propertyInfo = propertyType.GetPropertyOrIndexer(propertyNames[i], out _);
                         if (propertyInfo == null || propertyType.GetIsReadOnly() || propertyInfo.GetIsReadOnly())
                         if (propertyInfo == null || propertyType.GetIsReadOnly() || propertyInfo.GetIsReadOnly())
                         {
                         {
                             // Either the data type is read-only, the property doesn't exist, or it does exist but is read-only
                             // Either the data type is read-only, the property doesn't exist, or it does exist but is read-only
@@ -391,11 +394,10 @@ namespace Avalonia.Controls
                         }
                         }
 
 
                         // Check if EditableAttribute is defined on the property and if it indicates uneditable
                         // Check if EditableAttribute is defined on the property and if it indicates uneditable
-                        object[] attributes = propertyInfo.GetCustomAttributes(typeof(EditableAttribute), true);
+                        var attributes = propertyInfo.GetCustomAttributes(typeof(EditableAttribute), true);
                         if (attributes != null && attributes.Length > 0)
                         if (attributes != null && attributes.Length > 0)
                         {
                         {
-                            EditableAttribute editableAttribute = attributes[0] as EditableAttribute;
-                            Debug.Assert(editableAttribute != null);
+                            var editableAttribute = (EditableAttribute)attributes[0];
                             if (!editableAttribute.AllowEdit)
                             if (!editableAttribute.AllowEdit)
                             {
                             {
                                 return true;
                                 return true;

+ 2 - 37
src/Avalonia.Controls.DataGrid/DataGridRow.cs

@@ -543,7 +543,6 @@ namespace Avalonia.Controls
             RootElement = e.NameScope.Find<Panel>(DATAGRIDROW_elementRoot);
             RootElement = e.NameScope.Find<Panel>(DATAGRIDROW_elementRoot);
             if (RootElement != null)
             if (RootElement != null)
             {
             {
-                EnsureBackground();
                 UpdatePseudoClasses();
                 UpdatePseudoClasses();
             }
             }
 
 
@@ -668,43 +667,9 @@ namespace Avalonia.Controls
             Slot = -1;
             Slot = -1;
         }
         }
 
 
-        // Make sure the row's background is set to its correct value.  It could be explicity set or inherit
-        // DataGrid.RowBackground or DataGrid.AlternatingRowBackground
-        internal void EnsureBackground()
+        internal void InvalidateCellsIndex()
         {
         {
-            // Inherit the DataGrid's RowBackground properties only if this row doesn't explicity have a background set
-            if (RootElement != null && OwningGrid != null)
-            {
-                IBrush newBackground = null;
-                if (Background == null)
-                {
-                    if (Index % 2 == 0 || OwningGrid.AlternatingRowBackground == null)
-                    {
-                        // Use OwningGrid.RowBackground if the index is even or if the OwningGrid.AlternatingRowBackground is null
-                        if (OwningGrid.RowBackground != null)
-                        {
-                            newBackground = OwningGrid.RowBackground;
-                        }
-                    }
-                    else
-                    {
-                        // Alternate row
-                        if (OwningGrid.AlternatingRowBackground != null)
-                        {
-                            newBackground = OwningGrid.AlternatingRowBackground;
-                        }
-                    }
-                }
-                else
-                {
-                    newBackground = Background;
-                }
-
-                if (RootElement.Background != newBackground)
-                {
-                    RootElement.Background = newBackground;
-                }
-            }
+            _cellsElement?.InvalidateChildIndex();
         }
         }
 
 
         internal void EnsureFillerVisibility()
         internal void EnsureFillerVisibility()

+ 4 - 3
src/Avalonia.Controls.DataGrid/DataGridRows.cs

@@ -5,6 +5,7 @@
 
 
 using Avalonia.Collections;
 using Avalonia.Collections;
 using Avalonia.Controls.Utils;
 using Avalonia.Controls.Utils;
+using Avalonia.LogicalTree;
 using Avalonia.Media;
 using Avalonia.Media;
 using Avalonia.Utilities;
 using Avalonia.Utilities;
 using System;
 using System;
@@ -811,7 +812,7 @@ namespace Avalonia.Controls
                 if (row.Slot > slotDeleted)
                 if (row.Slot > slotDeleted)
                 {
                 {
                     CorrectRowAfterDeletion(row, wasRow);
                     CorrectRowAfterDeletion(row, wasRow);
-                    row.EnsureBackground();
+                    _rowsPresenter?.InvalidateChildIndex(row);
                 }
                 }
             }
             }
 
 
@@ -867,7 +868,7 @@ namespace Avalonia.Controls
                 if (row.Slot >= slotInserted)
                 if (row.Slot >= slotInserted)
                 {
                 {
                     DataGrid.CorrectRowAfterInsertion(row, rowInserted);
                     DataGrid.CorrectRowAfterInsertion(row, rowInserted);
-                    row.EnsureBackground();
+                    _rowsPresenter?.InvalidateChildIndex(row);
                 }
                 }
             }
             }
 
 
@@ -1485,8 +1486,8 @@ namespace Avalonia.Controls
             // If the row has been recycled, reapply the BackgroundBrush
             // If the row has been recycled, reapply the BackgroundBrush
             if (row.IsRecycled)
             if (row.IsRecycled)
             {
             {
-                row.EnsureBackground();
                 row.ApplyCellsState();
                 row.ApplyCellsState();
+                _rowsPresenter?.InvalidateChildIndex(row);
             }
             }
             else if (row == EditingRow)
             else if (row == EditingRow)
             {
             {

+ 1 - 4
src/Avalonia.Controls.DataGrid/DataGridTextColumn.cs

@@ -19,8 +19,6 @@ namespace Avalonia.Controls
     /// </summary>
     /// </summary>
     public class DataGridTextColumn : DataGridBoundColumn
     public class DataGridTextColumn : DataGridBoundColumn
     {
     {
-        private const string DATAGRID_TextColumnCellTextBlockMarginKey = "DataGridTextColumnCellTextBlockMargin";
-
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="T:Avalonia.Controls.DataGridTextColumn" /> class.
         /// Initializes a new instance of the <see cref="T:Avalonia.Controls.DataGridTextColumn" /> class.
         /// </summary>
         /// </summary>
@@ -178,8 +176,7 @@ namespace Avalonia.Controls
         {
         {
             TextBlock textBlockElement = new TextBlock
             TextBlock textBlockElement = new TextBlock
             {
             {
-                [!Layoutable.MarginProperty] = new DynamicResourceExtension(DATAGRID_TextColumnCellTextBlockMarginKey),
-                VerticalAlignment = VerticalAlignment.Center
+                Name = "CellTextBlock"
             };
             };
 
 
             SyncProperties(textBlockElement);
             SyncProperties(textBlockElement);

+ 36 - 3
src/Avalonia.Controls.DataGrid/Primitives/DataGridCellsPresenter.cs

@@ -3,12 +3,13 @@
 // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
 // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
 // All other rights reserved.
 // All other rights reserved.
 
 
+using Avalonia.LogicalTree;
 using Avalonia.Media;
 using Avalonia.Media;
 using Avalonia.Utilities;
 using Avalonia.Utilities;
 using System;
 using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
 using System.Diagnostics;
 using System.Diagnostics;
-using Avalonia.Controls;
-using Avalonia.Controls.Utils;
 
 
 namespace Avalonia.Controls.Primitives
 namespace Avalonia.Controls.Primitives
 {
 {
@@ -16,9 +17,10 @@ namespace Avalonia.Controls.Primitives
     /// Used within the template of a <see cref="T:Avalonia.Controls.DataGrid" />
     /// Used within the template of a <see cref="T:Avalonia.Controls.DataGrid" />
     /// to specify the location in the control's visual tree where the cells are to be added. 
     /// to specify the location in the control's visual tree where the cells are to be added. 
     /// </summary>
     /// </summary>
-    public sealed class DataGridCellsPresenter : Panel
+    public sealed class DataGridCellsPresenter : Panel, IChildIndexProvider
     {
     {
         private double _fillerLeftEdge;
         private double _fillerLeftEdge;
+        private EventHandler<ChildIndexChangedEventArgs> _childIndexChanged;
 
 
         // The desired height needs to be cached due to column virtualization; otherwise, the cells
         // The desired height needs to be cached due to column virtualization; otherwise, the cells
         // would grow and shrink as the DataGrid scrolls horizontally
         // would grow and shrink as the DataGrid scrolls horizontally
@@ -42,6 +44,25 @@ namespace Avalonia.Controls.Primitives
             set;
             set;
         }
         }
 
 
+        event EventHandler<ChildIndexChangedEventArgs> IChildIndexProvider.ChildIndexChanged
+        {
+            add => _childIndexChanged += value;
+            remove => _childIndexChanged -= value;
+        }
+
+        int IChildIndexProvider.GetChildIndex(ILogical child)
+        {
+            return child is DataGridCell cell
+                ? OwningGrid.ColumnsInternal.GetColumnDisplayIndex(cell.ColumnIndex)
+                : throw new InvalidOperationException("Invalid cell type");
+        }
+
+        bool IChildIndexProvider.TryGetTotalCount(out int count)
+        {
+            count = OwningGrid.ColumnsInternal.VisibleColumnCount;
+            return true;
+        }
+
         /// <summary>
         /// <summary>
         /// Arranges the content of the <see cref="T:Avalonia.Controls.Primitives.DataGridCellsPresenter" />.
         /// Arranges the content of the <see cref="T:Avalonia.Controls.Primitives.DataGridCellsPresenter" />.
         /// </summary>
         /// </summary>
@@ -120,6 +141,13 @@ namespace Avalonia.Controls.Primitives
             }
             }
         }
         }
 
 
+        protected override void ChildrenChanged(object sender, NotifyCollectionChangedEventArgs e)
+        {
+            base.ChildrenChanged(sender, e);
+
+            InvalidateChildIndex();
+        }
+
         private static void EnsureCellDisplay(DataGridCell cell, bool displayColumn)
         private static void EnsureCellDisplay(DataGridCell cell, bool displayColumn)
         {
         {
             if (cell.IsCurrent)
             if (cell.IsCurrent)
@@ -304,6 +332,11 @@ namespace Avalonia.Controls.Primitives
             DesiredHeight = 0;
             DesiredHeight = 0;
         }
         }
 
 
+        internal void InvalidateChildIndex()
+        {
+            _childIndexChanged?.Invoke(this, ChildIndexChangedEventArgs.Empty);
+        }
+
         private bool ShouldDisplayCell(DataGridColumn column, double frozenLeftEdge, double scrollingLeftEdge)
         private bool ShouldDisplayCell(DataGridColumn column, double frozenLeftEdge, double scrollingLeftEdge)
         {
         {
             if (!column.IsVisible)
             if (!column.IsVisible)

+ 35 - 1
src/Avalonia.Controls.DataGrid/Primitives/DataGridColumnHeadersPresenter.cs

@@ -3,8 +3,10 @@
 // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
 // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
 // All other rights reserved.
 // All other rights reserved.
 
 
+using Avalonia.LogicalTree;
 using Avalonia.Media;
 using Avalonia.Media;
 using System;
 using System;
+using System.Collections.Specialized;
 using System.Diagnostics;
 using System.Diagnostics;
 
 
 namespace Avalonia.Controls.Primitives
 namespace Avalonia.Controls.Primitives
@@ -13,10 +15,11 @@ namespace Avalonia.Controls.Primitives
     /// Used within the template of a <see cref="T:Avalonia.Controls.DataGrid" /> to specify the 
     /// Used within the template of a <see cref="T:Avalonia.Controls.DataGrid" /> to specify the 
     /// location in the control's visual tree where the column headers are to be added.
     /// location in the control's visual tree where the column headers are to be added.
     /// </summary>
     /// </summary>
-    public sealed class DataGridColumnHeadersPresenter : Panel
+    public sealed class DataGridColumnHeadersPresenter : Panel, IChildIndexProvider
     {
     {
         private Control _dragIndicator;
         private Control _dragIndicator;
         private IControl _dropLocationIndicator;
         private IControl _dropLocationIndicator;
+        private EventHandler<ChildIndexChangedEventArgs> _childIndexChanged;
 
 
         /// <summary>
         /// <summary>
         /// Tracks which column is currently being dragged.
         /// Tracks which column is currently being dragged.
@@ -104,6 +107,25 @@ namespace Avalonia.Controls.Primitives
             set;
             set;
         }
         }
 
 
+        event EventHandler<ChildIndexChangedEventArgs> IChildIndexProvider.ChildIndexChanged
+        {
+            add => _childIndexChanged += value;
+            remove => _childIndexChanged -= value;
+        }
+
+        int IChildIndexProvider.GetChildIndex(ILogical child)
+        {
+            return child is DataGridColumnHeader header
+                ? OwningGrid.ColumnsInternal.GetColumnDisplayIndex(header.ColumnIndex)
+                : throw new InvalidOperationException("Invalid cell type");
+        }
+
+        bool IChildIndexProvider.TryGetTotalCount(out int count)
+        {
+            count = OwningGrid.ColumnsInternal.VisibleColumnCount;
+            return true;
+        }
+
         /// <summary>
         /// <summary>
         /// Arranges the content of the <see cref="T:Avalonia.Controls.Primitives.DataGridColumnHeadersPresenter" />.
         /// Arranges the content of the <see cref="T:Avalonia.Controls.Primitives.DataGridColumnHeadersPresenter" />.
         /// </summary>
         /// </summary>
@@ -391,5 +413,17 @@ namespace Avalonia.Controls.Primitives
             OwningGrid.ColumnsInternal.EnsureVisibleEdgedColumnsWidth();
             OwningGrid.ColumnsInternal.EnsureVisibleEdgedColumnsWidth();
             return new Size(OwningGrid.ColumnsInternal.VisibleEdgedColumnsWidth, height);
             return new Size(OwningGrid.ColumnsInternal.VisibleEdgedColumnsWidth, height);
         }
         }
+
+        protected override void ChildrenChanged(object sender, NotifyCollectionChangedEventArgs e)
+        {
+            base.ChildrenChanged(sender, e);
+
+            InvalidateChildIndex();
+        }
+
+        internal void InvalidateChildIndex()
+        {
+            _childIndexChanged?.Invoke(this, ChildIndexChangedEventArgs.Empty);
+        }
     }
     }
 }
 }

+ 27 - 2
src/Avalonia.Controls.DataGrid/Primitives/DataGridRowsPresenter.cs

@@ -7,8 +7,8 @@ using System;
 using System.Diagnostics;
 using System.Diagnostics;
 
 
 using Avalonia.Input;
 using Avalonia.Input;
-using Avalonia.Input.GestureRecognizers;
 using Avalonia.Layout;
 using Avalonia.Layout;
+using Avalonia.LogicalTree;
 using Avalonia.Media;
 using Avalonia.Media;
 
 
 namespace Avalonia.Controls.Primitives
 namespace Avalonia.Controls.Primitives
@@ -17,8 +17,10 @@ namespace Avalonia.Controls.Primitives
     /// Used within the template of a <see cref="T:Avalonia.Controls.DataGrid" /> to specify the
     /// Used within the template of a <see cref="T:Avalonia.Controls.DataGrid" /> to specify the
     /// location in the control's visual tree where the rows are to be added.
     /// location in the control's visual tree where the rows are to be added.
     /// </summary>
     /// </summary>
-    public sealed class DataGridRowsPresenter : Panel
+    public sealed class DataGridRowsPresenter : Panel, IChildIndexProvider
     {
     {
+        private EventHandler<ChildIndexChangedEventArgs> _childIndexChanged;
+
         public DataGridRowsPresenter()
         public DataGridRowsPresenter()
         {
         {
             AddHandler(Gestures.ScrollGestureEvent, OnScrollGesture);
             AddHandler(Gestures.ScrollGestureEvent, OnScrollGesture);
@@ -44,6 +46,29 @@ namespace Avalonia.Controls.Primitives
             }
             }
         }
         }
 
 
+        event EventHandler<ChildIndexChangedEventArgs> IChildIndexProvider.ChildIndexChanged
+        {
+            add => _childIndexChanged += value;
+            remove => _childIndexChanged -= value;
+        }
+
+        int IChildIndexProvider.GetChildIndex(ILogical child)
+        {
+            return child is DataGridRow row
+                ? row.Index
+                : throw new InvalidOperationException("Invalid DataGrid child");
+        }
+
+        bool IChildIndexProvider.TryGetTotalCount(out int count)
+        {
+            return OwningGrid.DataConnection.TryGetCount(false, true, out count);
+        }
+
+        internal void InvalidateChildIndex(DataGridRow row)
+        {
+            _childIndexChanged?.Invoke(this, new ChildIndexChangedEventArgs(row));
+        }
+
         /// <summary>
         /// <summary>
         /// Arranges the content of the <see cref="T:Avalonia.Controls.Primitives.DataGridRowsPresenter" />.
         /// Arranges the content of the <see cref="T:Avalonia.Controls.Primitives.DataGridRowsPresenter" />.
         /// </summary>
         /// </summary>

+ 90 - 55
src/Avalonia.Controls.DataGrid/Themes/Default.xaml

@@ -12,23 +12,32 @@
     <Setter Property="VerticalContentAlignment" Value="Stretch" />
     <Setter Property="VerticalContentAlignment" Value="Stretch" />
     <Setter Property="Template">
     <Setter Property="Template">
       <ControlTemplate>
       <ControlTemplate>
-        <Grid ColumnDefinitions="*,Auto"
-              Background="{TemplateBinding Background}">
-          <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}"
-                            Content="{TemplateBinding Content}"
-                            Margin="{TemplateBinding Padding}"
-                            TextElement.Foreground="{TemplateBinding Foreground}"
-                            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
-                            VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
-
-          <Rectangle Name="PART_RightGridLine"
-                     Grid.Column="1"
-                     VerticalAlignment="Stretch"
-                     Width="1" />
-        </Grid>
+        <Border x:Name="CellBorder"
+                Background="{TemplateBinding Background}"
+                BorderBrush="{TemplateBinding BorderBrush}"
+                BorderThickness="{TemplateBinding BorderThickness}"
+                CornerRadius="{TemplateBinding CornerRadius}">
+          <Grid ColumnDefinitions="*,Auto">
+            <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}"
+                              Content="{TemplateBinding Content}"
+                              Margin="{TemplateBinding Padding}"
+                              Foreground="{TemplateBinding Foreground}"
+                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
+                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
+
+            <Rectangle Name="PART_RightGridLine"
+                       Grid.Column="1"
+                       VerticalAlignment="Stretch"
+                       Width="1" />
+          </Grid>
+        </Border>
       </ControlTemplate>
       </ControlTemplate>
     </Setter>
     </Setter>
   </Style>
   </Style>
+  <Style Selector="DataGridCell > TextBlock#CellTextBlock">
+    <Setter Property="Margin" Value="{DynamicResource DataGridTextColumnCellTextBlockMargin}" />
+    <Setter Property="VerticalAlignment" Value="Center" />
+  </Style>
 
 
   <Style Selector="DataGridColumnHeader">
   <Style Selector="DataGridColumnHeader">
     <Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}" />
     <Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}" />
@@ -40,35 +49,40 @@
 
 
     <Setter Property="Template">
     <Setter Property="Template">
       <ControlTemplate>
       <ControlTemplate>
-        <Grid ColumnDefinitions="*,Auto"
-              Background="{TemplateBinding Background}">
-
-          <Grid ColumnDefinitions="*,Auto"
-                HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
-                VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
-                Margin="{TemplateBinding Padding}">
-            <ContentPresenter Content="{TemplateBinding Content}" 
-                              ContentTemplate="{TemplateBinding ContentTemplate}" />
-
-            <Path Name="SortIcon"
-                  Grid.Column="1"
-                  Fill="{TemplateBinding Foreground}"
-                  HorizontalAlignment="Left"
-                  VerticalAlignment="Center"
-                  Stretch="Uniform"
-                  Width="8"
-                  Margin="4,0,0,0"
-                  Data="F1 M -5.215,6.099L 5.215,6.099L 0,0L -5.215,6.099 Z "/>
+        <Border x:Name="HeaderBorder"
+                Background="{TemplateBinding Background}"
+                BorderBrush="{TemplateBinding BorderBrush}"
+                BorderThickness="{TemplateBinding BorderThickness}"
+                CornerRadius="{TemplateBinding CornerRadius}">
+          <Grid ColumnDefinitions="*,Auto">
+
+            <Grid ColumnDefinitions="*,Auto"
+                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
+                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
+                  Margin="{TemplateBinding Padding}">
+              <ContentPresenter Content="{TemplateBinding Content}"
+                                ContentTemplate="{TemplateBinding ContentTemplate}" />
+
+              <Path Name="SortIcon"
+                    Grid.Column="1"
+                    Fill="{TemplateBinding Foreground}"
+                    HorizontalAlignment="Left"
+                    VerticalAlignment="Center"
+                    Stretch="Uniform"
+                    Width="8"
+                    Margin="4,0,0,0"
+                    Data="F1 M -5.215,6.099L 5.215,6.099L 0,0L -5.215,6.099 Z "/>
 
 
-          </Grid>
+            </Grid>
 
 
-          <Rectangle Name="VerticalSeparator"
-                     Grid.Column="1" Width="1"
-                     VerticalAlignment="Stretch"
-                     Fill="{TemplateBinding SeparatorBrush}"
-                     IsVisible="{TemplateBinding AreSeparatorsVisible}" />
+            <Rectangle Name="VerticalSeparator"
+                       Grid.Column="1" Width="1"
+                       VerticalAlignment="Stretch"
+                       Fill="{TemplateBinding SeparatorBrush}"
+                       IsVisible="{TemplateBinding AreSeparatorsVisible}" />
 
 
-        </Grid>
+          </Grid>
+        </Border>
       </ControlTemplate>
       </ControlTemplate>
     </Setter>
     </Setter>
   </Style>
   </Style>
@@ -102,22 +116,35 @@
   <Style Selector="DataGridRow">
   <Style Selector="DataGridRow">
     <Setter Property="Template">
     <Setter Property="Template">
       <ControlTemplate>
       <ControlTemplate>
-        <DataGridFrozenGrid Name="PART_Root"
-                                 RowDefinitions="*,Auto,Auto"
-                                 ColumnDefinitions="Auto,*">
+        <Border x:Name="RowBorder"
+                Background="{TemplateBinding Background}"
+                BorderBrush="{TemplateBinding BorderBrush}"
+                BorderThickness="{TemplateBinding BorderThickness}"
+                CornerRadius="{TemplateBinding CornerRadius}">
+          <DataGridFrozenGrid Name="PART_Root"
+                              RowDefinitions="*,Auto,Auto"
+                              ColumnDefinitions="Auto,*">
 
 
-          <Rectangle Name="BackgroundRectangle" Grid.RowSpan="2" Grid.ColumnSpan="2"/>
+            <Rectangle Name="BackgroundRectangle" Grid.RowSpan="2" Grid.ColumnSpan="2"/>
 
 
-          <DataGridRowHeader Grid.RowSpan="3" Name="PART_RowHeader" DataGridFrozenGrid.IsFrozen="True" />
-          <DataGridCellsPresenter Grid.Column="1" Name="PART_CellsPresenter" DataGridFrozenGrid.IsFrozen="True" />
-          <DataGridDetailsPresenter Grid.Row="1" Grid.Column="1" Name="PART_DetailsPresenter"/>
-          <Rectangle Grid.Row="2" Grid.Column="1" Name="PART_BottomGridLine" HorizontalAlignment="Stretch" Height="1" />
+            <DataGridRowHeader Grid.RowSpan="3" Name="PART_RowHeader" DataGridFrozenGrid.IsFrozen="True" />
+            <DataGridCellsPresenter Grid.Column="1" Name="PART_CellsPresenter" DataGridFrozenGrid.IsFrozen="True" />
+            <DataGridDetailsPresenter Grid.Row="1" Grid.Column="1" Name="PART_DetailsPresenter"/>
+            <Rectangle Grid.Row="2" Grid.Column="1" Name="PART_BottomGridLine" HorizontalAlignment="Stretch" Height="1" />
 
 
-        </DataGridFrozenGrid>
+          </DataGridFrozenGrid>
+        </Border>
       </ControlTemplate>
       </ControlTemplate>
     </Setter>
     </Setter>
   </Style>
   </Style>
 
 
+  <Style Selector="DataGridRow">
+    <Setter Property="Background" Value="{Binding $parent[DataGrid].RowBackground}" />
+  </Style>
+  <Style Selector="DataGridRow:nth-child(even)">
+    <Setter Property="Background" Value="{Binding $parent[DataGrid].AlternatingRowBackground}" />
+  </Style>
+
   <Style Selector="DataGridRow /template/ Rectangle#BackgroundRectangle">
   <Style Selector="DataGridRow /template/ Rectangle#BackgroundRectangle">
     <Setter Property="IsVisible" Value="False"/>
     <Setter Property="IsVisible" Value="False"/>
     <Setter Property="Fill" Value="{DynamicResource HighlightBrush}" />
     <Setter Property="Fill" Value="{DynamicResource HighlightBrush}" />
@@ -180,12 +207,18 @@
     <Setter Property="Template">
     <Setter Property="Template">
       <ControlTemplate>
       <ControlTemplate>
         <DataGridFrozenGrid Name="Root"
         <DataGridFrozenGrid Name="Root"
-                                 Background="{TemplateBinding Background}"
-                                 ColumnDefinitions="Auto,Auto,Auto,Auto"
-                                 RowDefinitions="Auto,*,Auto">
+                            ColumnDefinitions="Auto,Auto,Auto,Auto"
+                            RowDefinitions="Auto,*,Auto">
 
 
           <Rectangle Grid.Column="1" Grid.Row="1" Name="IndentSpacer" />
           <Rectangle Grid.Column="1" Grid.Row="1" Name="IndentSpacer" />
-          <ToggleButton Grid.Column="2" Grid.Row="1" Name="ExpanderButton" Margin="2,0,0,0"/>
+          <ToggleButton Grid.Column="2" Grid.Row="1"
+                        Name="ExpanderButton"
+                        Margin="2,0,0,0"
+                        BorderBrush="{TemplateBinding BorderBrush}"
+                        BorderThickness="{TemplateBinding BorderThickness}"
+                        Background="{TemplateBinding Background}"
+                        CornerRadius="{TemplateBinding CornerRadius}"
+                        Foreground="{TemplateBinding Foreground}" />
 
 
           <StackPanel Grid.Column="3" Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Center" Margin="0,1,0,1">
           <StackPanel Grid.Column="3" Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Center" Margin="0,1,0,1">
             <TextBlock Name="PropertyNameElement" Margin="4,0,0,0" IsVisible="{TemplateBinding IsPropertyNameVisible}"/>
             <TextBlock Name="PropertyNameElement" Margin="4,0,0,0" IsVisible="{TemplateBinding IsPropertyNameVisible}"/>
@@ -238,9 +271,11 @@
     </Setter>
     </Setter>
     <Setter Property="Template">
     <Setter Property="Template">
       <ControlTemplate>
       <ControlTemplate>
-        <Border Background="{TemplateBinding Background}"
+        <Border x:Name="DataGridBorder"
+                Background="{TemplateBinding Background}"
+                BorderBrush="{TemplateBinding BorderBrush}"
                 BorderThickness="{TemplateBinding BorderThickness}"
                 BorderThickness="{TemplateBinding BorderThickness}"
-                BorderBrush="{TemplateBinding BorderBrush}">
+                CornerRadius="{TemplateBinding CornerRadius}">
           <Grid RowDefinitions="Auto,*,Auto,Auto" ColumnDefinitions="Auto,*,Auto">
           <Grid RowDefinitions="Auto,*,Auto,Auto" ColumnDefinitions="Auto,*,Auto">
 
 
             <DataGridColumnHeader Name="PART_TopLeftCornerHeader" Width="22" />
             <DataGridColumnHeader Name="PART_TopLeftCornerHeader" Width="22" />

+ 145 - 119
src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml

@@ -93,58 +93,66 @@
     <Setter Property="Focusable" Value="False" />
     <Setter Property="Focusable" Value="False" />
     <Setter Property="Template">
     <Setter Property="Template">
       <ControlTemplate>
       <ControlTemplate>
-        <Grid x:Name="PART_CellRoot"
-              ColumnDefinitions="*,Auto"
-              Background="{TemplateBinding Background}">
+        <Border x:Name="CellBorder"
+                Background="{TemplateBinding Background}"
+                BorderBrush="{TemplateBinding BorderBrush}"
+                BorderThickness="{TemplateBinding BorderThickness}"
+                CornerRadius="{TemplateBinding CornerRadius}">
+          <Grid x:Name="PART_CellRoot" ColumnDefinitions="*,Auto">
 
 
-          <Rectangle x:Name="CurrencyVisual"
-                     HorizontalAlignment="Stretch"
-                     VerticalAlignment="Stretch"
-                     Fill="Transparent"
-                     IsHitTestVisible="False"
-                     Stroke="{DynamicResource DataGridCurrencyVisualPrimaryBrush}"
-                     StrokeThickness="1" />
-          <Grid x:Name="FocusVisual"
-                IsHitTestVisible="False">
-            <Rectangle HorizontalAlignment="Stretch"
-                       VerticalAlignment="Stretch"
-                       Fill="Transparent"
-                       IsHitTestVisible="False"
-                       Stroke="{DynamicResource DataGridCellFocusVisualPrimaryBrush}"
-                       StrokeThickness="2" />
-            <Rectangle Margin="2"
+            <Rectangle x:Name="CurrencyVisual"
                        HorizontalAlignment="Stretch"
                        HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch"
                        VerticalAlignment="Stretch"
                        Fill="Transparent"
                        Fill="Transparent"
                        IsHitTestVisible="False"
                        IsHitTestVisible="False"
-                       Stroke="{DynamicResource DataGridCellFocusVisualSecondaryBrush}"
+                       Stroke="{DynamicResource DataGridCurrencyVisualPrimaryBrush}"
                        StrokeThickness="1" />
                        StrokeThickness="1" />
-          </Grid>
+            <Grid x:Name="FocusVisual" IsHitTestVisible="False">
+              <Rectangle HorizontalAlignment="Stretch"
+                         VerticalAlignment="Stretch"
+                         Fill="Transparent"
+                         IsHitTestVisible="False"
+                         Stroke="{DynamicResource DataGridCellFocusVisualPrimaryBrush}"
+                         StrokeThickness="2" />
+              <Rectangle Margin="2"
+                         HorizontalAlignment="Stretch"
+                         VerticalAlignment="Stretch"
+                         Fill="Transparent"
+                         IsHitTestVisible="False"
+                         Stroke="{DynamicResource DataGridCellFocusVisualSecondaryBrush}"
+                         StrokeThickness="1" />
+            </Grid>
 
 
-          <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}"
-                            Content="{TemplateBinding Content}"
-                            Margin="{TemplateBinding Padding}"
-                            TextElement.Foreground="{TemplateBinding Foreground}"
-                            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
-                            VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
+            <ContentPresenter Margin="{TemplateBinding Padding}"
+                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
+                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
+                              Content="{TemplateBinding Content}"
+                              ContentTemplate="{TemplateBinding ContentTemplate}"
+                              Foreground="{TemplateBinding Foreground}" />
 
 
-          <Rectangle x:Name="InvalidVisualElement"
-                     HorizontalAlignment="Stretch"
-                     VerticalAlignment="Stretch"
-                     IsHitTestVisible="False"
-                     Stroke="{DynamicResource DataGridCellInvalidBrush}"
-                     StrokeThickness="1" />
+            <Rectangle x:Name="InvalidVisualElement"
+                       HorizontalAlignment="Stretch"
+                       VerticalAlignment="Stretch"
+                       IsHitTestVisible="False"
+                       Stroke="{DynamicResource DataGridCellInvalidBrush}"
+                       StrokeThickness="1" />
 
 
-          <Rectangle Name="PART_RightGridLine"
-                     Grid.Column="1"
-                     VerticalAlignment="Stretch"
-                     Width="1"
-                     Fill="{DynamicResource DataGridFillerColumnGridLinesBrush}" />
-        </Grid>
+            <Rectangle Name="PART_RightGridLine"
+                       Grid.Column="1"
+                       Width="1"
+                       VerticalAlignment="Stretch"
+                       Fill="{DynamicResource DataGridFillerColumnGridLinesBrush}" />
+          </Grid>
+        </Border>
       </ControlTemplate>
       </ControlTemplate>
     </Setter>
     </Setter>
   </Style>
   </Style>
 
 
+  <Style Selector="DataGridCell > TextBlock#CellTextBlock">
+    <Setter Property="Margin" Value="{DynamicResource DataGridTextColumnCellTextBlockMargin}" />
+    <Setter Property="VerticalAlignment" Value="Center" />
+  </Style>
+  
   <Style Selector="DataGridCell /template/ Rectangle#CurrencyVisual">
   <Style Selector="DataGridCell /template/ Rectangle#CurrencyVisual">
     <Setter Property="IsVisible" Value="False" />
     <Setter Property="IsVisible" Value="False" />
   </Style>
   </Style>
@@ -180,57 +188,58 @@
     <Setter Property="MinHeight" Value="32" />
     <Setter Property="MinHeight" Value="32" />
     <Setter Property="Template">
     <Setter Property="Template">
       <ControlTemplate>
       <ControlTemplate>
-        <Grid Name="PART_ColumnHeaderRoot"
-              ColumnDefinitions="*,Auto"
-              Background="{TemplateBinding Background}">
-
-          <Grid HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
-                VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
-                Margin="{TemplateBinding Padding}">
-            <Grid.ColumnDefinitions>
-              <ColumnDefinition Width="*" />
-              <ColumnDefinition MinWidth="32"
-                                Width="Auto" />
-            </Grid.ColumnDefinitions>
-
-            <ContentPresenter Content="{TemplateBinding Content}" 
-                              ContentTemplate="{TemplateBinding ContentTemplate}" />
-
-            <Path Name="SortIcon"
-                  Grid.Column="1"
-                  Fill="{TemplateBinding Foreground}"
-                  HorizontalAlignment="Center"
-                  VerticalAlignment="Center"
-                  Stretch="Uniform"
-                  Height="12" />
-          </Grid>
-
-          <Rectangle Name="VerticalSeparator"
-                     Grid.Column="1"
-                     Width="1"
-                     VerticalAlignment="Stretch"
-                     Fill="{TemplateBinding SeparatorBrush}"
-                     IsVisible="{TemplateBinding AreSeparatorsVisible}" />
+        <Border x:Name="HeaderBorder"
+                Background="{TemplateBinding Background}"
+                BorderBrush="{TemplateBinding BorderBrush}"
+                BorderThickness="{TemplateBinding BorderThickness}"
+                CornerRadius="{TemplateBinding CornerRadius}">
+          <Grid Name="PART_ColumnHeaderRoot" ColumnDefinitions="*,Auto">
+
+            <Grid Margin="{TemplateBinding Padding}"
+                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
+                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
+              <Grid.ColumnDefinitions>
+                <ColumnDefinition Width="*" />
+                <ColumnDefinition Width="Auto" MinWidth="32" />
+              </Grid.ColumnDefinitions>
+
+              <ContentPresenter Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" />
+
+              <Path Name="SortIcon"
+                    Grid.Column="1"
+                    Height="12"
+                    HorizontalAlignment="Center"
+                    VerticalAlignment="Center"
+                    Fill="{TemplateBinding Foreground}"
+                    Stretch="Uniform" />
+            </Grid>
 
 
-          <Grid x:Name="FocusVisual"
-                IsHitTestVisible="False">
-            <Rectangle x:Name="FocusVisualPrimary"
-                       HorizontalAlignment="Stretch"
+            <Rectangle Name="VerticalSeparator"
+                       Grid.Column="1"
+                       Width="1"
                        VerticalAlignment="Stretch"
                        VerticalAlignment="Stretch"
-                       Fill="Transparent"
-                       IsHitTestVisible="False"
-                       Stroke="{DynamicResource DataGridCellFocusVisualPrimaryBrush}"
-                       StrokeThickness="2" />
-            <Rectangle x:Name="FocusVisualSecondary"
-                       Margin="2"
-                       HorizontalAlignment="Stretch"
-                       VerticalAlignment="Stretch"
-                       Fill="Transparent"
-                       IsHitTestVisible="False"
-                       Stroke="{DynamicResource DataGridCellFocusVisualSecondaryBrush}"
-                       StrokeThickness="1" />
+                       Fill="{TemplateBinding SeparatorBrush}"
+                       IsVisible="{TemplateBinding AreSeparatorsVisible}" />
+
+            <Grid x:Name="FocusVisual" IsHitTestVisible="False">
+              <Rectangle x:Name="FocusVisualPrimary"
+                         HorizontalAlignment="Stretch"
+                         VerticalAlignment="Stretch"
+                         Fill="Transparent"
+                         IsHitTestVisible="False"
+                         Stroke="{DynamicResource DataGridCellFocusVisualPrimaryBrush}"
+                         StrokeThickness="2" />
+              <Rectangle x:Name="FocusVisualSecondary"
+                         Margin="2"
+                         HorizontalAlignment="Stretch"
+                         VerticalAlignment="Stretch"
+                         Fill="Transparent"
+                         IsHitTestVisible="False"
+                         Stroke="{DynamicResource DataGridCellFocusVisualSecondaryBrush}"
+                         StrokeThickness="1" />
+            </Grid>
           </Grid>
           </Grid>
-        </Grid>
+        </Border>
       </ControlTemplate>
       </ControlTemplate>
     </Setter>
     </Setter>
   </Style>
   </Style>
@@ -271,38 +280,51 @@
     <Setter Property="Focusable" Value="False" />
     <Setter Property="Focusable" Value="False" />
     <Setter Property="Template">
     <Setter Property="Template">
       <ControlTemplate>
       <ControlTemplate>
-        <DataGridFrozenGrid Name="PART_Root"
-                            RowDefinitions="*,Auto,Auto"
-                            ColumnDefinitions="Auto,*">
-
-          <Rectangle Name="BackgroundRectangle"
-                     Grid.RowSpan="2"
-                     Grid.ColumnSpan="2" />
-          <Rectangle x:Name="InvalidVisualElement"
-                     Grid.ColumnSpan="2"
-                     Fill="{DynamicResource DataGridRowInvalidBrush}" />
-
-          <DataGridRowHeader Name="PART_RowHeader"
-                             Grid.RowSpan="3"
-                             DataGridFrozenGrid.IsFrozen="True" />
-          <DataGridCellsPresenter Name="PART_CellsPresenter"
-                                  Grid.Column="1"
-                                  DataGridFrozenGrid.IsFrozen="True" />
-          <DataGridDetailsPresenter Name="PART_DetailsPresenter"
-                                    Grid.Row="1"
+        <Border x:Name="RowBorder"
+                Background="{TemplateBinding Background}"
+                BorderBrush="{TemplateBinding BorderBrush}"
+                BorderThickness="{TemplateBinding BorderThickness}"
+                CornerRadius="{TemplateBinding CornerRadius}">
+          <DataGridFrozenGrid Name="PART_Root"
+                              ColumnDefinitions="Auto,*"
+                              RowDefinitions="*,Auto,Auto">
+
+            <Rectangle Name="BackgroundRectangle"
+                       Grid.RowSpan="2"
+                       Grid.ColumnSpan="2" />
+            <Rectangle x:Name="InvalidVisualElement"
+                       Grid.ColumnSpan="2"
+                       Fill="{DynamicResource DataGridRowInvalidBrush}" />
+
+            <DataGridRowHeader Name="PART_RowHeader"
+                               Grid.RowSpan="3"
+                               DataGridFrozenGrid.IsFrozen="True" />
+            <DataGridCellsPresenter Name="PART_CellsPresenter"
                                     Grid.Column="1"
                                     Grid.Column="1"
-                                    Background="{DynamicResource DataGridDetailsPresenterBackgroundBrush}" />
-          <Rectangle Name="PART_BottomGridLine"
-                     Grid.Row="2"
-                     Grid.Column="1"
-                     HorizontalAlignment="Stretch"
-                     Height="1" />
+                                    DataGridFrozenGrid.IsFrozen="True" />
+            <DataGridDetailsPresenter Name="PART_DetailsPresenter"
+                                      Grid.Row="1"
+                                      Grid.Column="1"
+                                      Background="{DynamicResource DataGridDetailsPresenterBackgroundBrush}" />
+            <Rectangle Name="PART_BottomGridLine"
+                       Grid.Row="2"
+                       Grid.Column="1"
+                       Height="1"
+                       HorizontalAlignment="Stretch" />
 
 
-        </DataGridFrozenGrid>
+          </DataGridFrozenGrid>
+        </Border>
       </ControlTemplate>
       </ControlTemplate>
     </Setter>
     </Setter>
   </Style>
   </Style>
 
 
+  <Style Selector="DataGridRow">
+    <Setter Property="Background" Value="{Binding $parent[DataGrid].RowBackground}" />
+  </Style>
+  <Style Selector="DataGridRow:nth-child(even)">
+    <Setter Property="Background" Value="{Binding $parent[DataGrid].AlternatingRowBackground}" />
+  </Style>
+
   <Style Selector="DataGridRow /template/ Rectangle#InvalidVisualElement">
   <Style Selector="DataGridRow /template/ Rectangle#InvalidVisualElement">
     <Setter Property="Opacity" Value="0" />
     <Setter Property="Opacity" Value="0" />
   </Style>
   </Style>
@@ -430,9 +452,12 @@
                         Width="12"
                         Width="12"
                         Height="12"
                         Height="12"
                         Margin="12,0,0,0"
                         Margin="12,0,0,0"
+                        BorderBrush="{TemplateBinding BorderBrush}"
+                        BorderThickness="{TemplateBinding BorderThickness}"
                         Background="{TemplateBinding Background}"
                         Background="{TemplateBinding Background}"
-                        Foreground="{TemplateBinding Foreground}"
-                        Focusable="False" />
+                        CornerRadius="{TemplateBinding CornerRadius}"
+                        Focusable="False"
+                        Foreground="{TemplateBinding Foreground}" />
 
 
           <StackPanel Grid.Column="3"
           <StackPanel Grid.Column="3"
                       Orientation="Horizontal"
                       Orientation="Horizontal"
@@ -559,11 +584,12 @@
     </Setter>
     </Setter>
     <Setter Property="Template">
     <Setter Property="Template">
       <ControlTemplate>
       <ControlTemplate>
-        <Border Background="{TemplateBinding Background}"
+        <Border x:Name="DataGridBorder"
+                Background="{TemplateBinding Background}"
+                BorderBrush="{TemplateBinding BorderBrush}"
                 BorderThickness="{TemplateBinding BorderThickness}"
                 BorderThickness="{TemplateBinding BorderThickness}"
-                BorderBrush="{TemplateBinding BorderBrush}">
-          <Grid RowDefinitions="Auto,*,Auto,Auto"
-                ColumnDefinitions="Auto,*,Auto">
+                CornerRadius="{TemplateBinding CornerRadius}">
+          <Grid ColumnDefinitions="Auto,*,Auto" RowDefinitions="Auto,*,Auto,Auto">
             <Grid.Resources>
             <Grid.Resources>
               <ControlTemplate x:Key="TopLeftHeaderTemplate"
               <ControlTemplate x:Key="TopLeftHeaderTemplate"
                                TargetType="DataGridColumnHeader">
                                TargetType="DataGridColumnHeader">

+ 1 - 1
src/Avalonia.Controls/ItemsControl.cs

@@ -166,7 +166,7 @@ namespace Avalonia.Controls
             if (Presenter is IChildIndexProvider innerProvider)
             if (Presenter is IChildIndexProvider innerProvider)
             {
             {
                 innerProvider.ChildIndexChanged += PresenterChildIndexChanged;
                 innerProvider.ChildIndexChanged += PresenterChildIndexChanged;
-                _childIndexChanged?.Invoke(this, new ChildIndexChangedEventArgs());
+                _childIndexChanged?.Invoke(this, ChildIndexChangedEventArgs.Empty);
             }
             }
         }
         }
 
 

+ 1 - 1
src/Avalonia.Controls/Panel.cs

@@ -147,7 +147,7 @@ namespace Avalonia.Controls
                     throw new NotSupportedException();
                     throw new NotSupportedException();
             }
             }
 
 
-            _childIndexChanged?.Invoke(this, new ChildIndexChangedEventArgs());
+            _childIndexChanged?.Invoke(this, ChildIndexChangedEventArgs.Empty);
             InvalidateMeasureOnChildrenChanged();
             InvalidateMeasureOnChildrenChanged();
         }
         }
 
 

+ 1 - 1
src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs

@@ -158,7 +158,7 @@ namespace Avalonia.Controls.Presenters
             {
             {
                 ItemsChanged(e);
                 ItemsChanged(e);
 
 
-                _childIndexChanged?.Invoke(this, new ChildIndexChangedEventArgs());
+                _childIndexChanged?.Invoke(this, ChildIndexChangedEventArgs.Empty);
             }
             }
         }
         }