如何获取WPF DataGridCell的水平视觉位置(X轴)?

4

我需要获取WPF DataGridCell的位置,在DataGrid单元格更改事件中获得,但只能获取垂直位置(Y轴)。水平位置保持不变,即使指向不同的列。

以下是几乎可用的代码。通过单击不同的单元格进行测试。

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    List<Person> Persons = new List<Person>();

    public MainWindow()
    {
        InitializeComponent();

        Persons.Add(new Person { Id = 1, Name = "John", City = "London" });
        Persons.Add(new Person { Id = 2, Name = "Charles", City = "Rome" });
        Persons.Add(new Person { Id = 3, Name = "Paul", City = "Chicago" });

        this.EditingDataGrid.ItemsSource = Persons;
        this.EditingDataGrid.CurrentCellChanged += new EventHandler<EventArgs>(EditingDataGrid_CurrentCellChanged);
    }

    void EditingDataGrid_CurrentCellChanged(object sender, EventArgs e)
    {
        DataGridCell Cell = GetCurrentCell(this.EditingDataGrid);
        var Position = Cell.PointToScreen(new Point(0, 0));
        // WHY X NEVER CHANGES??!!
        MessageBox.Show("X=" + Position.X.ToString() + ", Y=" + Position.Y.ToString(), "Position");
    }

    /// <summary>
    /// Returns, for this supplied Source Data-Grid, the current Data-Grid-Cell.
    /// May return null if no associated Cell is found.
    /// </summary>
    public static DataGridCell GetCurrentCell(DataGrid SourceDataGrid)
    {
        if (SourceDataGrid.CurrentCell == null)
            return null;

        var RowContainer = SourceDataGrid.ItemContainerGenerator.ContainerFromItem(SourceDataGrid.CurrentCell.Item);
        if (RowContainer == null)
            return null;

        var RowPresenter = GetVisualChild<System.Windows.Controls.Primitives.DataGridCellsPresenter>(RowContainer);
        if (RowPresenter == null)
            return null;

        var Container = RowPresenter.ItemContainerGenerator.ContainerFromItem(SourceDataGrid.CurrentCell.Item);
        var Cell = Container as DataGridCell;

        // Try to get the cell if null, because maybe the cell is virtualized
        if (Cell == null)
        {
            SourceDataGrid.ScrollIntoView(RowContainer, SourceDataGrid.CurrentCell.Column);
            Container = RowPresenter.ItemContainerGenerator.ContainerFromItem(SourceDataGrid.CurrentCell.Item);
            Cell = Container as DataGridCell;
        }

        return Cell;
    }

    /// <summary>
    /// Returns the nearest child having the specified TRet type for the supplied Target.
    /// </summary>
    public static TRet GetVisualChild<TRet>(DependencyObject Target) where TRet : DependencyObject
    {
        if (Target == null)
            return null;

        for (int ChildIndex = 0; ChildIndex < VisualTreeHelper.GetChildrenCount(Target); ChildIndex++)
        {
            var Child = VisualTreeHelper.GetChild(Target, ChildIndex);

            if (Child != null && Child is TRet)
                return (TRet)Child;
            else
            {
                TRet childOfChild = GetVisualChild<TRet>(Child);

                if (childOfChild != null)
                    return childOfChild;
            }
        }

        return null;
    }
}

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string City { get; set; }
}

数据网格只需使用以下代码进行定义:<DataGrid x:Name="EditingDataGrid"/>。
也许存在其他方法来获取数据网格单元格的位置?
2个回答

6
您可以通过以下方式从CurrentCell获取DataGridCell: DataGridCell
void EditingDataGrid_CurrentCellChanged(object sender, EventArgs e)
{
    DataGridCell Cell = GetDataGridCell(EditingDataGrid.CurrentCell);
    var Position = Cell.PointToScreen(new Point(0, 0));
    MessageBox.Show("X=" + Position.X.ToString() + ", Y=" + Position.Y.ToString(), "Position");
}
public static DataGridCell GetDataGridCell(DataGridCellInfo cellInfo)
{
    if (cellInfo.IsValid == false)
    {
        return null;
    }
    var cellContent = cellInfo.Column.GetCellContent(cellInfo.Item);
    if (cellContent == null)
    {
        return null;
    }
    return cellContent.Parent as DataGridCell;
}

你可以在 DataGrid 上创建一个扩展方法来实现这个功能。 DataGridExtensions.cs
public static class DataGridExtensions
{
    public static DataGridCell GetCurrentDataGridCell(this DataGrid dataGrid)
    {
        DataGridCellInfo cellInfo = dataGrid.CurrentCell;
        if (cellInfo.IsValid == false)
        {
            return null;
        }
        var cellContent = cellInfo.Column.GetCellContent(cellInfo.Item);
        if (cellContent == null)
        {
            return null;
        }
        return cellContent.Parent as DataGridCell;
    }
}

每次需要获取当前的DataGridCell时,您可以像这样使用它

DataGridCell Cell = EditingDataGrid.GetCurrentDataGridCell();

这就是解决方案!使用您的方法获得的DataGridCell实际上正确报告了X和Y坐标。 谢谢! - Néstor Sánchez A.

0

我猜发生的情况是你的网格的默认选择模式是整行,你用于获取DataGridCell的代码正在获取第一个选定的单元格,该单元格包含"Id"列值。

您可以尝试更改网格的选择模式为“Cell”,这将触发具有正确坐标的消息框。

<DataGrid x:Name="EditingDataGrid" SelectionUnit="Cell"/>

我也稍微修改了你的代码,请看看它是否适用:

void EditingDataGrid_CurrentCellChanged(object sender, EventArgs e)
{
    // this will iterate through all selected cell of the datagrid
    foreach (DataGridCellInfo cellInfo in this.EditingDataGrid.SelectedCells)
    {
        DataGridCell Cell = GetCurrentCell(this.EditingDataGrid, cellInfo);
        if (Cell != null)
        {
            var Position = Cell.PointToScreen(new Point(0, 0));
            MessageBox.Show("X=" + Position.X.ToString() + 
                            ", Y=" + Position.Y.ToString() + 
                            " Content = " + ((TextBlock)Cell.Content).Text.ToString(), "Position");
        }
    }
}

/// <summary>
/// Returns, for this supplied Source Data-Grid, the current Data-Grid-Cell.
/// May return null if no associated Cell is found.
/// </summary>
public static DataGridCell GetCurrentCell(DataGrid grid, DataGridCellInfo cellInfo)
{
    DataGridCell result = null;
    DataGridRow row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromItem(cellInfo.Item);
    if (row != null)
    {
        int columnIndex = grid.Columns.IndexOf(cellInfo.Column);
        if (columnIndex > -1)
        {
            DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(row);
            result = presenter.ItemContainerGenerator.ContainerFromIndex(columnIndex) as DataGridCell;
        }
    }
    return result;
}

/// <summary>
/// Returns the nearest child having the specified TRet type for the supplied Target.
/// </summary>
static T GetVisualChild<T>(Visual parent) where T : Visual
{
    T child = default(T);
    int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
    for (int i = 0; i < numVisuals; i++)
    {
        Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
        child = v as T;
        if (child == null)
        {
            child = GetVisualChild<T>(v);
        }
        if (child != null)
        {
            break;
        }
    }
    return child;
}

希望这能有所帮助,敬礼


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接