Sic.Framework-Nanjing-Baishi/MECF.Framework.UI.Client/RecipeEditorLib/DGExtension/XDataGrid.cs

373 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using MECF.Framework.UI.Client.DataGridTransform.DataGrid.Microsoft.Windows.Controls.Primitives;
using MECF.Framework.UI.Client.RecipeEditorLib.DGExtension.CustomColumn;
using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel;
using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel.Params;
using EGC = ExtendedGrid.Microsoft.Windows.Controls;
namespace MECF.Framework.UI.Client.RecipeEditorLib.DGExtension
{
public sealed class XDataGrid : ExtendedGrid.Microsoft.Windows.Controls.DataGrid
{
#region Variables
public ScrollViewer ref_scrollviewer;
#endregion
#region Constructors
public XDataGrid()
{
SelectionChanged += OnSelectionChanged;
}
#endregion
#region Properties
public static readonly DependencyProperty SelectedItemsListProperty = DependencyProperty.Register(
nameof(SelectedItemsList), typeof(IList), typeof(XDataGrid), new PropertyMetadata(default(IList)));
public IList SelectedItemsList
{
get => (IList)GetValue(SelectedItemsListProperty);
set => SetValue(SelectedItemsListProperty, value);
}
public static readonly DependencyProperty UseHorizontalScrollingProperty = DependencyProperty.RegisterAttached("UseHorizontalScrolling", typeof(bool), typeof(XDataGrid),
new PropertyMetadata(default(bool), UseHorizontalScrollingChangedCallback));
public bool UseHorizontalScrolling
{
get => (bool)GetValue(UseHorizontalScrollingProperty);
set => SetValue(UseHorizontalScrollingProperty, value);
}
public static readonly DependencyProperty IsCellAccessPermissionEditModeProperty = DependencyProperty.Register(
nameof(IsCellAccessPermissionEditMode), typeof(bool), typeof(XDataGrid), new PropertyMetadata(default(bool)));
/// <summary>
/// 设置或返回当前DataGrid是否处于单元格访问权限编辑模式。
/// </summary>
public bool IsCellAccessPermissionEditMode
{
get => (bool)GetValue(IsCellAccessPermissionEditModeProperty);
set => SetValue(IsCellAccessPermissionEditModeProperty, value);
}
#endregion
#region Excel-Like Cell Drag-To-Fill Adorner
private DataGridCellDragToFillAdorner _lastAdorner;
private void ClearCellSelectionAdorner()
{
// 清空之前的Adorner
if (_lastAdorner != null && _lastAdorner.AdornedElement is EGC.DataGridCell cell)
{
var al = AdornerLayer.GetAdornerLayer(cell);
var ads = al?.GetAdorners(cell)?.ToList();
if (ads != null && ads.Any())
foreach (var ad in ads)
al.Remove(ad);
}
if (_lastAdorner != null)
{
(_lastAdorner.AdornedElement as EGC.DataGridCell).KeyDown -= Cell_KeyDown;
_lastAdorner.OnDragStart -= LastAdornerOnOnDragStart;
_lastAdorner.OnDragDelta -= LastAdornerOnOnDragDelta;
_lastAdorner.OnDragCompleted -= LastAdornerOnOnDragCompleted;
}
_lastAdorner = null;
}
private void CreateCellSelectionAdorner(EGC.DataGridCellInfo? cellInfo)
{
ClearCellSelectionAdorner();
// 如果选中了单元格并且没有在编辑模式显示Adorner
if (!CurrentCellContainer.IsEditing && cellInfo.HasValue)
{
if (!CheckIsCellSupportAdorner(TryFindCell(cellInfo.Value)))
return;
var cell = TryFindCell(cellInfo.Value);
cell.KeyDown += Cell_KeyDown;
if (cell != null)
{
_lastAdorner = new DataGridCellDragToFillAdorner(cell, new Size(cell.ActualWidth, cell.ActualHeight));
_lastAdorner.OnDragStart += LastAdornerOnOnDragStart;
_lastAdorner.OnDragDelta += LastAdornerOnOnDragDelta;
_lastAdorner.OnDragCompleted += LastAdornerOnOnDragCompleted;
AdornerLayer.GetAdornerLayer(cell).Add(_lastAdorner);
}
}
}
private Param GetParamFromCell(EGC.DataGridCellInfo? cellInfo)
{
if (cellInfo.HasValue
&& cellInfo.Value.Item is RecipeStep rs
&& cellInfo.Value.Column is EditorDataGridTemplateColumnBase col)
{
return rs.FirstOrDefault(x => x.Name == col.ControlName);
}
return null;
}
private Param GetParamFromCell(EGC.DataGridCell cell)
{
return GetParamFromCell(new EGC.DataGridCellInfo(cell));
}
private bool CheckIsCellSupportAdorner(EGC.DataGridCell cell)
{
if (cell.Column is EditorDataGridTemplateColumnBase col)
{
if (col.IsExpander || col.IsReadOnly)
return false;
return true;
}
return false;
}
/// <summary>
/// If ESC key down when dragging, cancel the dragging.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Cell_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
_lastAdorner?.Cancel();
}
}
private void LastAdornerOnOnDragStart(object sender, DragStartedEventArgs e)
{
//throw new NotImplementedException();
}
private void LastAdornerOnOnDragCompleted(object sender, DragCompletedEventArgs e)
{
if (sender is DataGridCellDragToFillAdorner adorner
&& adorner.AdornedElement is EGC.DataGridCell cell
&& _selectionAnchor != null)
{
// 源单元格不支持拖放填充
if (!CheckIsCellSupportAdorner(cell))
return;
if (adorner.StartCellIndex != adorner.EndCellIndex)
{
// 复制值
var srcParam = GetParamFromCell(_selectionAnchor);
if ((srcParam is ExpanderParam) == false)
{
// 获取源数据
var value = srcParam.GetValue();
Panel itemsHost = InternalItemsHost;
if (itemsHost != null)
{
var start = Math.Min(adorner.StartCellIndex, adorner.EndCellIndex);
var end = Math.Max(adorner.StartCellIndex, adorner.EndCellIndex);
for (var i = start; i <= end; i++)
{
if (itemsHost.Children[i] is EGC.DataGridRow row)
{
var targetCell = row.TryGetCell(_selectionAnchor.Value.Column.DisplayIndex);
if (GetParamFromCell(targetCell) is IParam p)
p.SetValue(value);
}
}
}
}
}
// 更新adorner尺寸
//adorner.Arrange(adorner.GetSelectionBound());
}
}
private void LastAdornerOnOnDragDelta(object sender, DragDeltaEventArgs e)
{
if (sender is DataGridCellDragToFillAdorner adorner && adorner.AdornedElement is EGC.DataGridCell cell)
{
// 检查当前Cell是否支持拖动填充
if (!CheckIsCellSupportAdorner(cell))
return;
var itemsHost = InternalItemsHost;
if (itemsHost == null)
return;
// 获取当前鼠标附近的Cell
var closestCell = MouseOverCell ?? GetCellNearMouse();
if (closestCell != null)
{
var originCellInfo = new EGC.DataGridCellInfo(cell);
var closestCellInfo = new EGC.DataGridCellInfo(closestCell);
var startIndex = Items.IndexOf(originCellInfo.Item);
var endIndex = Items.IndexOf(closestCellInfo.Item);
// 判断当前鼠标的Y坐标是否超过了当前Row高度的一半。
// 如果超过一半,则选中当前行对应的单元格;否则不选择。
var closestRow = closestCell.RowOwner;
var pt = Mouse.GetPosition(closestRow);
var rowBounds = new Rect(new Point(), closestRow.RenderSize);
// 默认选择当前单元格
var recRender = new Rect(0, 0, cell.ActualWidth, cell.ActualHeight);
// 判断鼠标是否划过当前Cell一半的位置超过一半选中没超过则不选中。
if (endIndex > startIndex) // Select the cells below the origin cell.
{
if (pt.Y < (rowBounds.Height / 2.0))
endIndex -= 1; // don't select the cell nearby mouse
recRender.Height = 0;
for (var i = startIndex; i <= endIndex; i++)
{
if (itemsHost.Children[i] is EGC.DataGridRow row)
recRender.Height += row.RenderSize.Height;
}
}
else if (endIndex < startIndex) // Select the cells above the origin cell.
{
if (pt.Y > (rowBounds.Height / 2.0))
endIndex += 1; // don't select the cell nearby mouse
recRender.Height = 0;
for (var i = endIndex; i <= startIndex; i++)
{
if (itemsHost.Children[i] is EGC.DataGridRow row)
recRender.Height += row.RenderSize.Height;
}
/*Debug.WriteLine($"Start: {startIndex}, End: {endIndex}", "Adorner");
Debug.WriteLine($"Rendering Adorner: {recRender}", "Adorner");
Debug.WriteLine($"Cell Height: {cell.ActualHeight}, Render Height: {recRender.Height}", "Adorner");*/
recRender.Y = cell.ActualHeight - recRender.Height;
//Debug.WriteLine($"Render Y: {recRender.Y}", "Adorner");
}
// 重新计算Adorner尺寸
adorner.ArrangeSelectionBound(recRender, startIndex, endIndex);
}
}
}
protected override void EnsureInternalScrollControls()
{
base.EnsureInternalScrollControls();
if (_internalScrollHost != null)
_internalScrollHost.ScrollChanged += (sender, args) =>
{
// Clear the cell adorner while the view is scrolling.
ClearCellSelectionAdorner();
};
}
protected override void MakeFullRowSelection(object dataItem, bool allowsExtendSelect, bool allowsMinimalSelect)
{
base.MakeFullRowSelection(dataItem, allowsExtendSelect, allowsMinimalSelect);
/*if (CurrentCell != null)
CreateCellSelectionAdorner(CurrentCell);*/
}
protected override void MakeCellSelection(EGC.DataGridCellInfo cellInfo, bool allowsExtendSelect, bool allowsMinimalSelect)
{
base.MakeCellSelection(cellInfo, allowsExtendSelect, allowsMinimalSelect);
// 如果是单元格访问权限编辑模式则不要启用Drag-To-Fill功能
if (IsCellAccessPermissionEditMode)
return;
if (_selectionAnchor != null)
CreateCellSelectionAdorner(_selectionAnchor);
}
public override bool BeginEdit(RoutedEventArgs editingEventArgs)
{
if (IsCellAccessPermissionEditMode)
return false;
return base.BeginEdit(editingEventArgs);
}
#endregion
#region Methods
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
SelectedItemsList = SelectedItems;
}
private void _UseHorizontalScrollingChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
PreviewMouseWheel += delegate (object sender, MouseWheelEventArgs args)
{
ScrollViewer scrollViewer = GetTemplateChild("DG_ScrollViewer") as ScrollViewer;
if (scrollViewer != null)
{
if (args.Delta > 0)
scrollViewer.LineLeft();
else
scrollViewer.LineRight();
}
ref_scrollviewer = scrollViewer;
args.Handled = true;
};
}
private static void UseHorizontalScrollingChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
if (!(dependencyObject is XDataGrid dg))
throw new ArgumentException("Element is not an ItemsControl");
dg._UseHorizontalScrollingChangedCallback(dependencyObject, dependencyPropertyChangedEventArgs);
}
public static void SetUseHorizontalScrolling(ItemsControl element, bool value)
{
element.SetValue(UseHorizontalScrollingProperty, value);
}
public static bool GetUseHorizontalScrolling(ItemsControl element)
{
return (bool)element.GetValue(UseHorizontalScrollingProperty);
}
#endregion
}
}