如何获得WPF DataGridCell可视水平(X轴)位置?

时间:2011-03-13 03:09:22

标签: wpf datagrid

我需要获取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只是由...定义的     <DataGrid x:Name="EditingDataGrid"/&GT;

也许存在获取DataGridCell位置的替代方法?

2 个答案:

答案 0 :(得分:6)

您可以像这样从CurrentCell获取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();

答案 1 :(得分:0)

我猜是正在发生的事情是网格的默认选择模式是完整行,您用来获取DataGridCell的代码是获得第一个选中的单元格,其中包含“ Id ”列值。

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

<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;
}

希望这有帮助,尊重