这个问题类似于Excel,比如 Wpf itemscontrol 中的拖动选择,但我想在 DataGrid 中进行,而不是在 ListBox 中进行。
我正在尝试使 WPF DataGrid 中的选择矩形看起来像 Excel 中的矩形,包括右下角的黑色小方块,并且在每个选定的单元格周围没有边框。有人会在 WPF DataGrid 中有这样的工作示例吗?

这个问题类似于Excel,比如 Wpf itemscontrol 中的拖动选择,但我想在 DataGrid 中进行,而不是在 ListBox 中进行。
我正在尝试使 WPF DataGrid 中的选择矩形看起来像 Excel 中的矩形,包括右下角的黑色小方块,并且在每个选定的单元格周围没有边框。有人会在 WPF DataGrid 中有这样的工作示例吗?

首先,您必须使用此答案中描述的方法隐藏焦点单元格的边框:
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
</Style>
</DataGrid.CellStyle>
然后,您需要使用OnSelectedCellsChanged事件DataGrid来添加/删除将绘制选择矩形的装饰器。对于填充句柄,您可以使用 a Thumb,它为您处理拖放内容:
void DataGrid_OnSelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
{
var datagrid = (System.Windows.Controls.DataGrid)sender;
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(datagrid);
if (datagrid.SelectedCells.Any())
{
DataGridCellInfo firstCellInfo = datagrid.SelectedCells.First();
FrameworkElement firstElt = firstCellInfo.Column.GetCellContent(firstCellInfo.Item);
DataGridCellInfo lastCellInfo = datagrid.SelectedCells.Last();
FrameworkElement lastElt = lastCellInfo.Column.GetCellContent(lastCellInfo.Item);
if (firstElt != null && lastElt != null)
{
var firstcell = (DataGridCell)firstElt.Parent;
var lastCell = (DataGridCell) lastElt.Parent;
Point topLeft = datagrid.PointFromScreen(firstcell.PointToScreen(new Point(0, 0)));
Point bottomRight = datagrid.PointFromScreen(lastCell.PointToScreen(new Point(lastCell.ActualWidth, lastCell.ActualHeight)));
var rect = new Rect(topLeft, bottomRight);
if (fillHandleAdorner == null)
{
fillHandleAdorner = new FillHandleAdorner(datagrid, rect);
adornerLayer.Add(fillHandleAdorner);
}
else
fillHandleAdorner.Rect = rect;
}
}
else
{
adornerLayer.Remove(fillHandleAdorner);
fillHandleAdorner = null;
}
}
FillHandleAdorner 类的代码:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
namespace DataGrid
{
internal class FillHandleAdorner : Adorner
{
const int SIZE = 5;
Rect rect;
readonly Thumb thumb;
readonly VisualCollection visualChildren;
Point mousePosition;
System.Windows.Controls.DataGrid dataGrid;
public Rect Rect
{
get { return rect; }
set
{
rect = value;
UpdateThumbPos(rect);
mousePosition = rect.BottomRight;
InvalidateVisual();
}
}
public FillHandleAdorner(UIElement adornedElement, Rect rect)
: base(adornedElement)
{
dataGrid = (System.Windows.Controls.DataGrid)adornedElement;
Rect = rect;
visualChildren = new VisualCollection(this);
var border = new FrameworkElementFactory(typeof(Border));
border.SetValue(Border.BackgroundProperty, Brushes.Black);
thumb = new Thumb
{
Cursor = Cursors.Cross,
Background = new SolidColorBrush(Colors.Black),
Height = SIZE,
Template = new ControlTemplate(typeof(Thumb)) { VisualTree = border },
Width = SIZE
};
visualChildren.Add(thumb);
UpdateThumbPos(rect);
thumb.DragDelta += thumb_DragDelta;
}
void UpdateThumbPos(Rect rect)
{
if (thumb == null) return;
mousePosition = rect.BottomRight;
mousePosition.Offset(-SIZE/2 - 1, -SIZE/2 - 1);
thumb.Arrange(new Rect(mousePosition, new Size(SIZE, SIZE)));
}
void thumb_DragDelta(object sender, DragDeltaEventArgs e)
{
mousePosition.Offset(e.HorizontalChange, e.VerticalChange);
IInputElement inputElt = dataGrid.InputHitTest(mousePosition);
var tb = inputElt as TextBlock;
if (tb == null) return;
Point bottomRight = dataGrid.PointFromScreen(tb.PointToScreen(new Point(tb.ActualWidth + 1, tb.ActualHeight + 1)));
Rect = new Rect(rect.TopLeft, bottomRight);
}
protected override int VisualChildrenCount
{
get { return visualChildren.Count; }
}
protected override Visual GetVisualChild(int index)
{
return visualChildren[index];
}
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
var blackSolidBrush = new SolidColorBrush(Colors.Black);
var pen = new Pen(blackSolidBrush, 3);
pen.Freeze();
double halfPenWidth = pen.Thickness / 2;
Rect rangeBorderRect = rect;
rangeBorderRect.Offset(-1, -1);
GuidelineSet guidelines = new GuidelineSet();
guidelines.GuidelinesX.Add(rangeBorderRect.Left + halfPenWidth);
guidelines.GuidelinesX.Add(rangeBorderRect.Right + halfPenWidth);
guidelines.GuidelinesY.Add(rangeBorderRect.Top + halfPenWidth);
guidelines.GuidelinesY.Add(rangeBorderRect.Bottom + halfPenWidth);
Point p1 = rangeBorderRect.BottomRight;
p1.Offset(0, -4);
guidelines.GuidelinesY.Add(p1.Y + halfPenWidth);
Point p2 = rangeBorderRect.BottomRight;
p2.Offset(-4, 0);
guidelines.GuidelinesX.Add(p2.X + halfPenWidth);
drawingContext.PushGuidelineSet(guidelines);
var geometry = new StreamGeometry();
using (StreamGeometryContext ctx = geometry.Open())
{
ctx.BeginFigure(p1, true, false);
ctx.LineTo(rangeBorderRect.TopRight, true, false);
ctx.LineTo(rangeBorderRect.TopLeft, true, false);
ctx.LineTo(rangeBorderRect.BottomLeft, true, false);
ctx.LineTo(p2, true, false);
}
geometry.Freeze();
drawingContext.DrawGeometry(null, pen, geometry);
drawingContext.Pop();
}
}
}
代码不完整,因为它用于尚未启动的项目,但它应该可以帮助您启动。