|
@@ -14,6 +14,9 @@ using System.Collections.Specialized;
|
|
|
using System.ComponentModel;
|
|
using System.ComponentModel;
|
|
|
using System.Diagnostics;
|
|
using System.Diagnostics;
|
|
|
using System.Linq;
|
|
using System.Linq;
|
|
|
|
|
+using Avalonia.Data;
|
|
|
|
|
+using Avalonia.Styling;
|
|
|
|
|
+using JetBrains.Annotations;
|
|
|
|
|
|
|
|
namespace Avalonia.Controls
|
|
namespace Avalonia.Controls
|
|
|
{
|
|
{
|
|
@@ -117,7 +120,7 @@ namespace Avalonia.Controls
|
|
|
detailsCount += GetDetailsCountInclusive(DisplayData.LastScrollingSlot + 1, SlotCount - 1);
|
|
detailsCount += GetDetailsCountInclusive(DisplayData.LastScrollingSlot + 1, SlotCount - 1);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- //
|
|
|
|
|
|
|
+ //
|
|
|
double totalDetailsHeight = detailsCount * RowDetailsHeightEstimate;
|
|
double totalDetailsHeight = detailsCount * RowDetailsHeightEstimate;
|
|
|
|
|
|
|
|
return totalRowsHeight + totalDetailsHeight;
|
|
return totalRowsHeight + totalDetailsHeight;
|
|
@@ -163,7 +166,7 @@ namespace Avalonia.Controls
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
|
- /// Clears the entire selection except the indicated row. Displayed rows are deselected explicitly to
|
|
|
|
|
|
|
+ /// Clears the entire selection except the indicated row. Displayed rows are deselected explicitly to
|
|
|
/// visualize potential transition effects. The row indicated is selected if it is not already.
|
|
/// visualize potential transition effects. The row indicated is selected if it is not already.
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
internal void ClearRowSelection(int slotException, bool setAnchorSlot)
|
|
internal void ClearRowSelection(int slotException, bool setAnchorSlot)
|
|
@@ -270,10 +273,10 @@ namespace Avalonia.Controls
|
|
|
bool isRow = rowIndex != -1;
|
|
bool isRow = rowIndex != -1;
|
|
|
if (isCollapsed)
|
|
if (isCollapsed)
|
|
|
{
|
|
{
|
|
|
- InsertElement(slot,
|
|
|
|
|
- element: null,
|
|
|
|
|
|
|
+ InsertElement(slot,
|
|
|
|
|
+ element: null,
|
|
|
updateVerticalScrollBarOnly: true,
|
|
updateVerticalScrollBarOnly: true,
|
|
|
- isCollapsed: true,
|
|
|
|
|
|
|
+ isCollapsed: true,
|
|
|
isRow: isRow);
|
|
isRow: isRow);
|
|
|
}
|
|
}
|
|
|
else if (SlotIsDisplayed(slot))
|
|
else if (SlotIsDisplayed(slot))
|
|
@@ -285,18 +288,18 @@ namespace Avalonia.Controls
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
- InsertElement(slot, GenerateRowGroupHeader(slot, groupInfo),
|
|
|
|
|
|
|
+ InsertElement(slot, GenerateRowGroupHeader(slot, groupInfo),
|
|
|
updateVerticalScrollBarOnly: false,
|
|
updateVerticalScrollBarOnly: false,
|
|
|
- isCollapsed: false,
|
|
|
|
|
|
|
+ isCollapsed: false,
|
|
|
isRow: isRow);
|
|
isRow: isRow);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
- InsertElement(slot,
|
|
|
|
|
|
|
+ InsertElement(slot,
|
|
|
element: null,
|
|
element: null,
|
|
|
updateVerticalScrollBarOnly: _vScrollBar == null || _vScrollBar.IsVisible,
|
|
updateVerticalScrollBarOnly: _vScrollBar == null || _vScrollBar.IsVisible,
|
|
|
- isCollapsed: false,
|
|
|
|
|
|
|
+ isCollapsed: false,
|
|
|
isRow: isRow);
|
|
isRow: isRow);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -417,7 +420,7 @@ namespace Avalonia.Controls
|
|
|
if (scrolledHorizontally && DisplayData.FirstScrollingSlot <= slot && DisplayData.LastScrollingSlot >= slot)
|
|
if (scrolledHorizontally && DisplayData.FirstScrollingSlot <= slot && DisplayData.LastScrollingSlot >= slot)
|
|
|
{
|
|
{
|
|
|
// If the slot is displayed and we scrolled horizontally, column virtualization could cause the rows to grow.
|
|
// If the slot is displayed and we scrolled horizontally, column virtualization could cause the rows to grow.
|
|
|
- // As a result we need to force measure on the rows we're displaying and recalculate our First and Last slots
|
|
|
|
|
|
|
+ // As a result we need to force measure on the rows we're displaying and recalculate our First and Last slots
|
|
|
// so they're accurate
|
|
// so they're accurate
|
|
|
foreach (DataGridRow row in DisplayData.GetScrollingRows())
|
|
foreach (DataGridRow row in DisplayData.GetScrollingRows())
|
|
|
{
|
|
{
|
|
@@ -455,7 +458,7 @@ namespace Avalonia.Controls
|
|
|
deltaY -= GetSlotElementsHeight(slot, firstFullSlot);
|
|
deltaY -= GetSlotElementsHeight(slot, firstFullSlot);
|
|
|
if (DisplayData.FirstScrollingSlot - slot > 1)
|
|
if (DisplayData.FirstScrollingSlot - slot > 1)
|
|
|
{
|
|
{
|
|
|
- //
|
|
|
|
|
|
|
+ //
|
|
|
|
|
|
|
|
ResetDisplayedRows();
|
|
ResetDisplayedRows();
|
|
|
}
|
|
}
|
|
@@ -519,7 +522,7 @@ namespace Avalonia.Controls
|
|
|
_verticalOffset = NegVerticalOffset;
|
|
_verticalOffset = NegVerticalOffset;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- //
|
|
|
|
|
|
|
+ //
|
|
|
Debug.Assert(MathUtilities.LessThanOrClose(NegVerticalOffset, _verticalOffset));
|
|
Debug.Assert(MathUtilities.LessThanOrClose(NegVerticalOffset, _verticalOffset));
|
|
|
|
|
|
|
|
SetVerticalOffset(_verticalOffset);
|
|
SetVerticalOffset(_verticalOffset);
|
|
@@ -1025,6 +1028,10 @@ namespace Avalonia.Controls
|
|
|
dataGridRow.Slot = slot;
|
|
dataGridRow.Slot = slot;
|
|
|
dataGridRow.OwningGrid = this;
|
|
dataGridRow.OwningGrid = this;
|
|
|
dataGridRow.DataContext = dataContext;
|
|
dataGridRow.DataContext = dataContext;
|
|
|
|
|
+ if (RowTheme is {} rowTheme)
|
|
|
|
|
+ {
|
|
|
|
|
+ dataGridRow.SetValue(ThemeProperty, rowTheme, BindingPriority.TemplatedParent);
|
|
|
|
|
+ }
|
|
|
CompleteCellsCollection(dataGridRow);
|
|
CompleteCellsCollection(dataGridRow);
|
|
|
|
|
|
|
|
OnLoadingRow(new DataGridRowEventArgs(dataGridRow));
|
|
OnLoadingRow(new DataGridRowEventArgs(dataGridRow));
|
|
@@ -1104,7 +1111,7 @@ namespace Avalonia.Controls
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
|
/// Checks if the row for the provided dataContext has been generated and is present
|
|
/// Checks if the row for the provided dataContext has been generated and is present
|
|
|
- /// in either the loaded rows, pre-fetched rows, or editing row.
|
|
|
|
|
|
|
+ /// in either the loaded rows, pre-fetched rows, or editing row.
|
|
|
/// The displayed rows are *not* searched. Returns null if the row does not belong to those 3 categories.
|
|
/// The displayed rows are *not* searched. Returns null if the row does not belong to those 3 categories.
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
private DataGridRow GetGeneratedRow(object dataContext)
|
|
private DataGridRow GetGeneratedRow(object dataContext)
|
|
@@ -1152,8 +1159,8 @@ namespace Avalonia.Controls
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
- // If we're grouping, the GroupLevel needs to be fixed later by methods calling this
|
|
|
|
|
- // which end up inserting rows. We don't do it here because elements could be inserted
|
|
|
|
|
|
|
+ // If we're grouping, the GroupLevel needs to be fixed later by methods calling this
|
|
|
|
|
+ // which end up inserting rows. We don't do it here because elements could be inserted
|
|
|
// from top to bottom or bottom to up so it's better to do in one pass
|
|
// from top to bottom or bottom to up so it's better to do in one pass
|
|
|
slotElement = GenerateRow(RowIndexFromSlot(slot), slot);
|
|
slotElement = GenerateRow(RowIndexFromSlot(slot), slot);
|
|
|
}
|
|
}
|
|
@@ -1161,7 +1168,6 @@ namespace Avalonia.Controls
|
|
|
return slotElement;
|
|
return slotElement;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- //TODO Styles
|
|
|
|
|
private void InsertDisplayedElement(int slot, Control element, bool wasNewlyAdded, bool updateSlotInformation)
|
|
private void InsertDisplayedElement(int slot, Control element, bool wasNewlyAdded, bool updateSlotInformation)
|
|
|
{
|
|
{
|
|
|
// We can only support creating new rows that are adjacent to the currently visible rows
|
|
// We can only support creating new rows that are adjacent to the currently visible rows
|
|
@@ -1479,7 +1485,6 @@ namespace Avalonia.Controls
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- //TODO Styles
|
|
|
|
|
// Makes sure the row shows the proper visuals for selection, currency, details, etc.
|
|
// Makes sure the row shows the proper visuals for selection, currency, details, etc.
|
|
|
private void LoadRowVisualsForDisplay(DataGridRow row)
|
|
private void LoadRowVisualsForDisplay(DataGridRow row)
|
|
|
{
|
|
{
|
|
@@ -1694,7 +1699,7 @@ namespace Avalonia.Controls
|
|
|
{
|
|
{
|
|
|
// Figure out what row we've scrolled down to and update the value for NegVerticalOffset
|
|
// Figure out what row we've scrolled down to and update the value for NegVerticalOffset
|
|
|
NegVerticalOffset = 0;
|
|
NegVerticalOffset = 0;
|
|
|
- //
|
|
|
|
|
|
|
+ //
|
|
|
if (height > 2 * CellsHeight &&
|
|
if (height > 2 * CellsHeight &&
|
|
|
(RowDetailsVisibilityMode != DataGridRowDetailsVisibilityMode.VisibleWhenSelected || RowDetailsTemplate == null))
|
|
(RowDetailsVisibilityMode != DataGridRowDetailsVisibilityMode.VisibleWhenSelected || RowDetailsTemplate == null))
|
|
|
{
|
|
{
|
|
@@ -1755,7 +1760,7 @@ namespace Avalonia.Controls
|
|
|
// Figure out what row we've scrolled up to and update the value for NegVerticalOffset
|
|
// Figure out what row we've scrolled up to and update the value for NegVerticalOffset
|
|
|
deltaY = -NegVerticalOffset;
|
|
deltaY = -NegVerticalOffset;
|
|
|
NegVerticalOffset = 0;
|
|
NegVerticalOffset = 0;
|
|
|
- //
|
|
|
|
|
|
|
+ //
|
|
|
|
|
|
|
|
if (height < -2 * CellsHeight &&
|
|
if (height < -2 * CellsHeight &&
|
|
|
(RowDetailsVisibilityMode != DataGridRowDetailsVisibilityMode.VisibleWhenSelected || RowDetailsTemplate == null))
|
|
(RowDetailsVisibilityMode != DataGridRowDetailsVisibilityMode.VisibleWhenSelected || RowDetailsTemplate == null))
|
|
@@ -1813,7 +1818,7 @@ namespace Avalonia.Controls
|
|
|
if (MathUtilities.GreaterThanOrClose(0, newVerticalOffset) && newFirstScrollingSlot != 0)
|
|
if (MathUtilities.GreaterThanOrClose(0, newVerticalOffset) && newFirstScrollingSlot != 0)
|
|
|
{
|
|
{
|
|
|
// We've scrolled to the top of the ScrollBar, automatically place the user at the very top
|
|
// We've scrolled to the top of the ScrollBar, automatically place the user at the very top
|
|
|
- // of the DataGrid. If this produces very odd behavior, evaluate the RowHeight estimate.
|
|
|
|
|
|
|
+ // of the DataGrid. If this produces very odd behavior, evaluate the RowHeight estimate.
|
|
|
// strategy. For most data, this should be unnoticeable.
|
|
// strategy. For most data, this should be unnoticeable.
|
|
|
ResetDisplayedRows();
|
|
ResetDisplayedRows();
|
|
|
NegVerticalOffset = 0;
|
|
NegVerticalOffset = 0;
|
|
@@ -1994,7 +1999,6 @@ namespace Avalonia.Controls
|
|
|
VisibleSlotCount = 0;
|
|
VisibleSlotCount = 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- //TODO Styles
|
|
|
|
|
private void UnloadRow(DataGridRow dataGridRow)
|
|
private void UnloadRow(DataGridRow dataGridRow)
|
|
|
{
|
|
{
|
|
|
Debug.Assert(dataGridRow != null);
|
|
Debug.Assert(dataGridRow != null);
|
|
@@ -2010,16 +2014,13 @@ namespace Avalonia.Controls
|
|
|
OnUnloadingRow(new DataGridRowEventArgs(dataGridRow));
|
|
OnUnloadingRow(new DataGridRowEventArgs(dataGridRow));
|
|
|
bool recycleRow = CurrentSlot != dataGridRow.Index;
|
|
bool recycleRow = CurrentSlot != dataGridRow.Index;
|
|
|
|
|
|
|
|
- // Don't recycle if the row has a custom Style set
|
|
|
|
|
- //recycleRow &= (dataGridRow.Style == null || dataGridRow.Style == RowStyle);
|
|
|
|
|
-
|
|
|
|
|
if (recycleRow)
|
|
if (recycleRow)
|
|
|
{
|
|
{
|
|
|
DisplayData.AddRecyclableRow(dataGridRow);
|
|
DisplayData.AddRecyclableRow(dataGridRow);
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
- //
|
|
|
|
|
|
|
+ //
|
|
|
_rowsPresenter.Children.Remove(dataGridRow);
|
|
_rowsPresenter.Children.Remove(dataGridRow);
|
|
|
dataGridRow.DetachFromDataGrid(false);
|
|
dataGridRow.DetachFromDataGrid(false);
|
|
|
}
|
|
}
|
|
@@ -2240,10 +2241,10 @@ namespace Avalonia.Controls
|
|
|
group.Items.CollectionChanged += CollectionViewGroup_CollectionChanged;
|
|
group.Items.CollectionChanged += CollectionViewGroup_CollectionChanged;
|
|
|
}
|
|
}
|
|
|
var newGroupInfo = new DataGridRowGroupInfo(group, true, parentGroupInfo.Level + 1, insertSlot, insertSlot);
|
|
var newGroupInfo = new DataGridRowGroupInfo(group, true, parentGroupInfo.Level + 1, insertSlot, insertSlot);
|
|
|
- InsertElementAt(insertSlot,
|
|
|
|
|
- rowIndex: -1,
|
|
|
|
|
- item: null,
|
|
|
|
|
- groupInfo: newGroupInfo,
|
|
|
|
|
|
|
+ InsertElementAt(insertSlot,
|
|
|
|
|
+ rowIndex: -1,
|
|
|
|
|
+ item: null,
|
|
|
|
|
+ groupInfo: newGroupInfo,
|
|
|
isCollapsed: isCollapsed);
|
|
isCollapsed: isCollapsed);
|
|
|
RowGroupHeadersTable.AddValue(insertSlot, newGroupInfo);
|
|
RowGroupHeadersTable.AddValue(insertSlot, newGroupInfo);
|
|
|
}
|
|
}
|
|
@@ -2256,9 +2257,9 @@ namespace Avalonia.Controls
|
|
|
{
|
|
{
|
|
|
AutoGenerateColumnsPrivate();
|
|
AutoGenerateColumnsPrivate();
|
|
|
}
|
|
}
|
|
|
- InsertElementAt(insertSlot, rowIndex,
|
|
|
|
|
|
|
+ InsertElementAt(insertSlot, rowIndex,
|
|
|
item: e.NewItems[0],
|
|
item: e.NewItems[0],
|
|
|
- groupInfo: null,
|
|
|
|
|
|
|
+ groupInfo: null,
|
|
|
isCollapsed: isCollapsed);
|
|
isCollapsed: isCollapsed);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -2448,13 +2449,12 @@ namespace Avalonia.Controls
|
|
|
VisibleSlotCount = SlotCount;
|
|
VisibleSlotCount = SlotCount;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- //TODO Styles
|
|
|
|
|
private void RefreshRowGroupHeaders()
|
|
private void RefreshRowGroupHeaders()
|
|
|
{
|
|
{
|
|
|
if (DataConnection.CollectionView != null
|
|
if (DataConnection.CollectionView != null
|
|
|
&& DataConnection.CollectionView.CanGroup
|
|
&& DataConnection.CollectionView.CanGroup
|
|
|
&& DataConnection.CollectionView.Groups != null
|
|
&& DataConnection.CollectionView.Groups != null
|
|
|
- && DataConnection.CollectionView.IsGrouping
|
|
|
|
|
|
|
+ && DataConnection.CollectionView.IsGrouping
|
|
|
&& DataConnection.CollectionView.GroupingDepth > 0)
|
|
&& DataConnection.CollectionView.GroupingDepth > 0)
|
|
|
{
|
|
{
|
|
|
// Initialize our array for the height of the RowGroupHeaders by Level.
|
|
// Initialize our array for the height of the RowGroupHeaders by Level.
|
|
@@ -2476,7 +2476,7 @@ namespace Avalonia.Controls
|
|
|
double indent;
|
|
double indent;
|
|
|
for (int i = 0; i < groupLevelCount; i++)
|
|
for (int i = 0; i < groupLevelCount; i++)
|
|
|
{
|
|
{
|
|
|
- indent = DATAGRID_defaultRowGroupSublevelIndent;
|
|
|
|
|
|
|
+ indent = DATAGRID_defaultRowGroupSublevelIndent;
|
|
|
RowGroupSublevelIndents[i] = indent;
|
|
RowGroupSublevelIndents[i] = indent;
|
|
|
if (i > 0)
|
|
if (i > 0)
|
|
|
{
|
|
{
|
|
@@ -2742,6 +2742,10 @@ namespace Avalonia.Controls
|
|
|
groupHeader.RowGroupInfo = rowGroupInfo;
|
|
groupHeader.RowGroupInfo = rowGroupInfo;
|
|
|
groupHeader.DataContext = rowGroupInfo.CollectionViewGroup;
|
|
groupHeader.DataContext = rowGroupInfo.CollectionViewGroup;
|
|
|
groupHeader.Level = rowGroupInfo.Level;
|
|
groupHeader.Level = rowGroupInfo.Level;
|
|
|
|
|
+ if (RowGroupTheme is {} rowGroupTheme)
|
|
|
|
|
+ {
|
|
|
|
|
+ groupHeader.SetValue(ThemeProperty, rowGroupTheme, BindingPriority.TemplatedParent);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
// Set the RowGroupHeader's PropertyName. Unfortunately, CollectionViewGroup doesn't have this
|
|
// Set the RowGroupHeader's PropertyName. Unfortunately, CollectionViewGroup doesn't have this
|
|
|
// so we have to set it manually
|
|
// so we have to set it manually
|