【问题标题】:How to get WPF DataGridCell visual horizontal (X-axis) position?如何获得 WPF DataGridCell 视觉水平(X 轴)位置?
【发布时间】:2011-03-13 03:09:22
【问题描述】:

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

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

【问题讨论】:

    标签: wpf datagrid


    【解决方案1】:

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

    【讨论】:

    • 这就是解决方案!使用您的方法获得的 DataGridCell 实际上正确报告了 X 和 Y 坐标。谢谢!
    【解决方案2】:

    我猜你的网格的默认选择模式是整行,你用来获取 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;
    }
    

    希望这会有所帮助,问候

    【讨论】:

      猜你喜欢
      • 2016-03-25
      • 2014-08-28
      • 2017-02-08
      • 2013-04-08
      • 2017-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多