如何通过列和行索引获取WPF网格中单元格的x,y坐标

时间:2011-11-18 12:00:06

标签: c# wpf wpf-controls grid

我有一个网格,我在其中以progamatic方式添加rowdefinitions和col定义。

<Grid>
    <Grid Name="layoutGrid" ></Grid>
    <Canvas Name="overlayedCanvas"></Canvas>
</Grid>

// create rows
for (int r = 0; r < rowCount; r++)
    layoutGrid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto});
// create columns
for (int c = 0; c < colCount; c++)
    layoutGrid.ColumnDefinitions.Add(new ColumnDefinition {Width = GridLength.Auto});

然后我将我的usercontrols放在一些单元格中。 网格会根据各个用户控件的大小自动调整大小。

我的目标是绘制一个连接某些单元格的多边形。 例如它可以是从单元格[1,1]的左上角开始直到细胞[3,3]右下角的Rect(1,1,3,3)。 我正在考虑使用这种方法access children by x,y coordinates,但我必须在每个单元格中创建虚拟控件。

然后我可以计算细胞位置:

Point topLeft = uc.TranslatePoint(new Point(0,0), layoutGrid);
Point bottomRight = uc.TranslatePoint(new Point(uc.ActualWidth, uc.ActualHeight), layoutGrid);

有更好的方法吗?

感谢

2 个答案:

答案 0 :(得分:0)

public partial class MainWindow : Window
{
    private delegate void LoadDelegate();

    public MainWindow()
    {
        InitializeComponent();

        LoadDelegate oD = Load;
        Dispatcher.BeginInvoke (
            oD,  
            System.Windows.Threading.DispatcherPriority.Loaded, 
            null
        );
    }

    private void Load()
    {
        var items = LogicalTreeHelper
                        .GetChildren(uiGrid)
                        .OfType<Border>()
                        .Select(brd => new { Column = Grid.GetColumn(brd), Row = Grid.GetRow(brd), Item = brd })
                        .ToList();
        Border oStart = items
                            .FirstOrDefault(item => item.Column == 1 && item.Row == 1)
                            .Item;
        Border oStop = items
                            .FirstOrDefault(item => item.Column == 2 && item.Row == 2)
                            .Item;

        Point topLeft = oStart.PointToScreen(new Point(0, 0));
        Point bottomRight = oStop.PointToScreen(new Point(oStop.ActualWidth, oStop.ActualHeight));

        Rectangle oRect = new Rectangle();
        oRect.Fill = new SolidColorBrush(Color.FromRgb(0, 255, 0));

        Point oLeft = uiCanvas.PointFromScreen(topLeft);
        Canvas.SetLeft(oRect, oLeft.X);
        Canvas.SetTop(oRect, oLeft.Y);
        oRect.Width = bottomRight.X - topLeft.X;
        oRect.Height = bottomRight.Y - topLeft.Y;

        uiCanvas.Children.Add(oRect);
    }
}

...

<Grid>
    <Grid x:Name="uiGrid">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>

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

        <Border Background="Red" Grid.Column="1" Grid.Row="1" />
        <Border Background="Red" Grid.Column="2" Grid.Row="2" />
    </Grid>

    <Canvas x:Name="uiCanvas" />
</Grid>

答案 1 :(得分:0)

获取WPF Rect[ , ]中所有单元格的维度Grid

  

返回RowDefinition.​ActualHeightColumnDefinition.ActualWidth报告的WPF Grid所有单元格的当前运行时维度。结果以二维数组Rect[row,column]返回。例如,返回数组中最后一个元素的PointRect.BottomRight将等于调用时Grid的{​​{3}}。


public static Rect[,] GetCellRects(this Grid grid) =>
                      GetCellRects(grid.RowDefinitions, grid.ColumnDefinitions);

static Rect[,] GetCellRects(RowDefinitionCollection rows, ColumnDefinitionCollection cols)
{
    int i = rows.Count, j = cols.Count;
    var a = new Rect[i, j];
    if (i > 0 && j > 0)
    {
        Double x;
        for (i = a.GetLength(0); --i >= 0;)
            for (x = rows[i].ActualHeight, j = a.GetLength(1); --j >= 0;)
                a[i, j].Height = x;

        for (j = a.GetLength(1); --j >= 0;)
            for (x = cols[j].ActualWidth, i = a.GetLength(0); --i >= 0;)
                a[i, j].Width = x;

        for (i = 0; i < a.GetLength(0); i++)
            for (j = 0; j < a.GetLength(1); j++)
            {
                if (j > 0)
                    a[i, j].X = a[i, j - 1].Right;
                if (i > 0)
                    a[i, j].Y = a[i - 1, j].Bottom;
            }
    }
    return a;
}


另外,此代码使用了一个经典的RenderSize规范示例。这里的好处是每个ActualHeightActualWidth属性每行或每列只能访问一次,这个数字显然是最小的。尝试设计此处显示的代码的替代方案来保留该行为是一种有趣的练习。或者相反,说服自己为什么最终的嵌套循环不能反向进行,就像之前的循环一样......?