Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In a WPF Grid, how can I find the Row & Column at the mouse location?

I have a WPF Grid with some rows and columns, e.g.

<Grid Name="myGrid" MouseMove="OnMouseMove">
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>

    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
</Grid>

With a handler for MouseMove in the .cs file, e.g.

private void OnMouseMove(object sender, MouseEventArgs e)
{
    var position = e.GetPosition(myGrid);

    // What row & col is the mouse over?
}

I want to be able to find which row and column in the grid the mouse is over, is this possible?

[Note: this is a simplified version of the problem, so it looks a little odd to present it in this way - it's part of some drag & drop between grids functionality]

like image 922
Wilka Avatar asked Aug 11 '09 10:08

Wilka


People also ask

How do I show Grid lines in WPF?

First Method: By typing XAML Code RowDefinitions property and a ColumnDefinition Element for each column inside the Grid. ColumnDefinitions property. By default, GridLines are invisible. For showing the GridLines, set the ShowGridLines property of the Grid to True.

What is Grid RowSpan in WPF?

You can span across multiple rows and columns using the Grid. RowSpan and Grid. ColumnSpan attached properties. The default value for both these properties is 1. The Grid will attempt to assign as many row spans or column spans as it can up to the amount specified by the Grid.

What is GridView in WPF?

A GridView is a control that displays data items in rows and columns. Actually a ListView displays data. By default, it contains a GridView.

How do I use GridView in XAML?

XAML doesn't support a GridView element. However, you can use a ListView to create a GridView like UI. The code sample in this article is an example of creating GridView in XAML. You can learn more about ListView control here: ListView in WPF.


5 Answers

I hope you have already find a solution. I faced to the same problem and I found this unanswered post. So I think the next one will be happy to find this solution :

private void OnMouseMove(object sender, MouseEventArgs e)
{
    var element = (UIElement)e.Source;

    int c = Grid.GetColumn(element);
    int r = Grid.GetRow(element);
}
like image 65
Nicolas Avatar answered Sep 19 '22 03:09

Nicolas


This the following can be done (but shouldn't be used on larger Grids). It is only for Rows, but a second loop can be applied to the columns...

The answer of Nicolas only works if the grid contains some UIElements (whose position in the grid are determined - I guess that would also cause trouble if an element spans several rows/columns).

    private void ItemsGrid_MouseMove(object sender, MouseEventArgs e)
    {
        double y = e.GetPosition(ItemsGrid).Y;
        double start = 0.0;
        int row = 0;
        foreach(RowDefinition rd in ItemsGrid.RowDefinitions)
        {
            start += rd.ActualHeight;
            if (y < start)
            {
                break;
            }
            row++;
        }
        System.Diagnostics.Debug.WriteLine("Row : " + row);
    }
like image 30
Andre Avatar answered Sep 17 '22 03:09

Andre


public static class GridExtentions
{
    public static T Parent<T>(this DependencyObject root) where T : class
    {
        if (root is T) { return root as T; }

        DependencyObject parent = VisualTreeHelper.GetParent(root);
        return parent != null ? parent.Parent<T>() : null;
    }

    public static Point GetColumnRow(this Grid obj, Point relativePoint) { return new Point(GetColumn(obj, relativePoint.X), GetRow(obj, relativePoint.Y)); }
    private static int GetRow(Grid obj, double relativeY) { return GetData(obj.RowDefinitions, relativeY); }
    private static int GetColumn(Grid obj, double relativeX) { return GetData(obj.ColumnDefinitions, relativeX); }

    private static int GetData<T>(IEnumerable<T> list, double value) where T : DefinitionBase
    {
        var start = 0.0;
        var result = 0;

        var property = typeof(T).GetProperties().FirstOrDefault(p => p.Name.StartsWith("Actual"));
        if (property == null) { return result; }

        foreach (var definition in list)
        {
            start += (double)property.GetValue(definition);
            if (value < start) { break; }

            result++;
        }

        return result;
    }
}

Usage:

protected override void OnMouseDown(MouseButtonEventArgs e)
{
    base.OnMouseDown(e);
    var hit = VisualTreeHelper.HitTest(this, e.GetPosition(this));
    if (hit == null) { return; }

    var grid = hit.VisualHit.Parent<Grid>();
    if (grid == null) { return; }

    var gridPosition = grid.GetColumnRow(e.GetPosition(grid));
    MessageBox.Show(string.Format("Grid location Row: {1} Column: {0}", gridPosition.X, gridPosition.Y));
}
like image 23
Magikos Avatar answered Sep 20 '22 03:09

Magikos


replace Grid.ColumnDefinitions with reference to Grid component

int GetColumn(double point)
{
   int index = 0;
   foreach(var column in Grid.ColumnDefinitions)
   {
      if(point > column.Offset && point < (column.Offset + column.ActualWidth))
          return index;
      index++;
   }
   return 0;
}
like image 35
JLCNZ Avatar answered Sep 19 '22 03:09

JLCNZ


Hope can help. it's working well for my app

        public class GridCell
        {
            public int GridRow { get; set; }
            public int GridCol { get; set; }
        }

        private void Window_MouseMove(object sender, MouseEventArgs e)
        {
            Point point = e.GetPosition(this.myGrid);

            Grid gridTarget = GetLastedGridContainPoint(point, this.myGrid);

            Point pointTarget = this.myGrid.TranslatePoint(point, gridTarget);

            GridCell cell = GetGridCellContainPoint(pointTarget, gridTarget);
        }

        private bool IsPointInGrid(Point relativePoint, Grid grid)
        {
            if (relativePoint.X < 0 || relativePoint.X > grid.ActualWidth ||
                relativePoint.Y < 0 || relativePoint.Y > grid.ActualHeight)
            {
                return false;
            }

            return true;
        }

        private Grid GetLastedGridContainPoint(Point relativePoint, Grid gridParent)
        {
            Grid gridReturn = null;

            if (gridParent.Children.Count > 0)
            {
                Point relativeChildPoint;
                foreach (UIElement e in gridParent.Children)
                {
                    if (e is Grid)
                    {
                        relativeChildPoint = gridParent.TranslatePoint(relativePoint, (e as Grid));
                        gridReturn = GetLastedGridContainPoint(relativeChildPoint, (e as Grid));

                        if (gridReturn != null)
                        {
                            break;
                        }
                    }
                }
            }

            if (gridReturn == null)
            {
                if (IsPointInGrid(relativePoint, gridParent))
                {
                    gridReturn = gridParent;
                }
            }

            return gridReturn;
        }

        private GridCell GetGridCellContainPoint(Point relativePoint, Grid gridTarget)
        {
            if (!IsPointInGrid(relativePoint, gridTarget))
            {
                return null;
            }

            GridCell cell = new GridCell();
            double dbStart = 0;
            double dbEnd = 0;

            if (gridTarget.ColumnDefinitions.Count > 0)
            {
                for (int i = 0; i < gridTarget.ColumnDefinitions.Count; i++)
                {
                    dbStart = dbEnd;
                    dbEnd += gridTarget.ColumnDefinitions[i].ActualWidth;

                    if (relativePoint.X >= dbStart && relativePoint.X < dbEnd)
                    {
                        cell.GridCol = i;
                        break;
                    }
                }
            }

            dbStart = 0;
            dbEnd = 0;

            if (gridTarget.RowDefinitions.Count > 0)
            {
                for (int i = 0; i < gridTarget.RowDefinitions.Count; i++)
                {
                    dbStart = dbEnd;
                    dbEnd += gridTarget.RowDefinitions[i].ActualHeight;

                    if (relativePoint.Y >= dbStart && relativePoint.Y < dbEnd)
                    {
                        cell.GridRow = i;
                        break;
                    }
                }
            }

            return cell;
        }
like image 31
MemoryLeaks Avatar answered Sep 21 '22 03:09

MemoryLeaks