如何获取 WPF DataGrid 单元格的位置?
How do get the location of a WPF DataGrid cell?
我有一个 DataGrid
绑定到 Appointment
个对象的集合。网格显示给定一周的约会,列为天数,行为时间,因此每个单元格都绑定到一个约会。
当用户单击一个单元格时,我想显示一个小的 window,其中包含该单元格约会的摘要。由于复杂的原因,我无法为单元格设置模板来显示摘要,更重要的是,我希望摘要下拉并覆盖所选单元格下方的单元格。
在我链接到单击的命令中,通过一些魔法,我得到了所选单元格本身的 DataGridCellInfo
,但该对象没有提供任何定位的提示,只有一些尺寸。双击的输入绑定如下所示:
<DataGrid.InputBindings>
<!--TODO Remove name 'TheGrid' and find parent DataGrid-->
<MouseBinding MouseAction="LeftDoubleClick" Command="{Binding ApptClickCommand}" CommandParameter="{Binding ElementName=TheGrid, Path=SelectedCells}" />
</DataGrid.InputBindings>
命令代码接收一个SelectedCellsCollection
类型的参数,其中只包含一个DataGridCellInfo
。我没有其他信息可以在命令中使用。事实上,我对 viewmodel 中的视图如此亲密,所以我在作弊,所以我想避免过分直接使用代码隐藏事件。
弹出窗口是 UI 特定的东西,在我看来应该以某种方式从视图中定位。
过去 something similar,我的 ViewModel 跟踪实际数据、SelectedItem 和 IsDetailsVisible 的标志。
从视图中,我会有一个 "popup" UserControl 位于我的网格顶部。它的可见性绑定到 IsDetailsVisible
属性,数据绑定到 SelectedItem
。对于我的项目,弹出窗口居中,但是让 View 设置 PopupUserControl 的 Top/Left 属性以便它与用户单击的单元格匹配应该是一个简单的案例。
要在 UI 中找到实际的网格单元格,有几种方法可以解决这个问题。最简单的方法可能是使用 Click 或 MouseDown 事件,然后根据 Clicked DataGridCell 从那里定位 PopupUserControl。正如我所说,这种事情对我来说是视图特定的,所以应该放在视图后面的代码中。
此外,我从不喜欢 WPF 的弹出窗口,因此制作了我自己的自定义 UserControl,我会一直使用它。如果您有兴趣使用它或做类似的事情,可以在我的博客 here 上找到该代码。
下面是一个示例,说明如何获取 DataGridCell 元素,然后使用 Visual.PointToScreen 方法查找其屏幕坐标:
private void AppClickCommandExecuted(IList<DataGridCellInfo> cells)
{
if(cells != null && cells.Count > 0)
{
DataGridCellInfo cellInfo = cells[0];
FrameworkElement cellContent = cellInfo.Column.GetCellContent(cellInfo.Item);
if (cellContent != null)
{
DataGridCell cell = cellContent.Parent as DataGridCell;
if(cell != null)
{
Point screenCoordinates = cell.PointToScreen(new Point(0, 0));
//place your popup based on the screen coordinates of the cell...
}
}
}
}
我有一个 DataGrid
绑定到 Appointment
个对象的集合。网格显示给定一周的约会,列为天数,行为时间,因此每个单元格都绑定到一个约会。
当用户单击一个单元格时,我想显示一个小的 window,其中包含该单元格约会的摘要。由于复杂的原因,我无法为单元格设置模板来显示摘要,更重要的是,我希望摘要下拉并覆盖所选单元格下方的单元格。
在我链接到单击的命令中,通过一些魔法,我得到了所选单元格本身的 DataGridCellInfo
,但该对象没有提供任何定位的提示,只有一些尺寸。双击的输入绑定如下所示:
<DataGrid.InputBindings>
<!--TODO Remove name 'TheGrid' and find parent DataGrid-->
<MouseBinding MouseAction="LeftDoubleClick" Command="{Binding ApptClickCommand}" CommandParameter="{Binding ElementName=TheGrid, Path=SelectedCells}" />
</DataGrid.InputBindings>
命令代码接收一个SelectedCellsCollection
类型的参数,其中只包含一个DataGridCellInfo
。我没有其他信息可以在命令中使用。事实上,我对 viewmodel 中的视图如此亲密,所以我在作弊,所以我想避免过分直接使用代码隐藏事件。
弹出窗口是 UI 特定的东西,在我看来应该以某种方式从视图中定位。
过去 something similar,我的 ViewModel 跟踪实际数据、SelectedItem 和 IsDetailsVisible 的标志。
从视图中,我会有一个 "popup" UserControl 位于我的网格顶部。它的可见性绑定到 IsDetailsVisible
属性,数据绑定到 SelectedItem
。对于我的项目,弹出窗口居中,但是让 View 设置 PopupUserControl 的 Top/Left 属性以便它与用户单击的单元格匹配应该是一个简单的案例。
要在 UI 中找到实际的网格单元格,有几种方法可以解决这个问题。最简单的方法可能是使用 Click 或 MouseDown 事件,然后根据 Clicked DataGridCell 从那里定位 PopupUserControl。正如我所说,这种事情对我来说是视图特定的,所以应该放在视图后面的代码中。
此外,我从不喜欢 WPF 的弹出窗口,因此制作了我自己的自定义 UserControl,我会一直使用它。如果您有兴趣使用它或做类似的事情,可以在我的博客 here 上找到该代码。
下面是一个示例,说明如何获取 DataGridCell 元素,然后使用 Visual.PointToScreen 方法查找其屏幕坐标:
private void AppClickCommandExecuted(IList<DataGridCellInfo> cells)
{
if(cells != null && cells.Count > 0)
{
DataGridCellInfo cellInfo = cells[0];
FrameworkElement cellContent = cellInfo.Column.GetCellContent(cellInfo.Item);
if (cellContent != null)
{
DataGridCell cell = cellContent.Parent as DataGridCell;
if(cell != null)
{
Point screenCoordinates = cell.PointToScreen(new Point(0, 0));
//place your popup based on the screen coordinates of the cell...
}
}
}
}