Search code examples
wpfxamllayoutuser-interfacepanels

Can I make two containers (e.g. Grid and Canvas) take the same space to combine their abilities?


I have the following layout:

enter image description here

The Rectangles are placed using a Grid. On top of that, I want to add more "fluid" stuff, like Paths and lines that would be located dynamically.

For instance:

  • the lines between the Rectangles, are stretched from one Rectangle's mid-point to the mid-point of the one below it
  • The left-manually-drawn-ugly-red-"path" originate from the mid-point of the left-half of the top-Rectangle, and go to the mid-point of the left Rectange below it.

So the question is: the Rectangles match Grid behavior, other stuff, like the lines, match Canvas behavior. How do I use the advantages of both these containers? can I lay one over the other?


Solution

  • Yes you can lay the Canvas on top of a Grid, but you probably don't want to.

    <Grid x:Name="container">
        <!-- We use this to put the two items in the same location -->
        <!-- i.e. Row="0" Column="0" is implicit for both the canvas and the grid below-->
      <Grid x:Name="rectangleGrid"/>
      <Canvas x:Name="shapeCanvas"/>
    </Grid>
    

    It really is that simple, but lets have a look at what we have now.

    • The shapeCanvas will be in front of the rectangleGrid (and if it isn't just tweak its ZIndex). If it has a non-transparent BackColor then you won't of course see the rectangleGrid, so you will need to sort that out.
    • If we want to line up the right hand red-line of yours we need to work out where to draw it from. Given that gridColumns don't expose sizes, then that's leftRectangle.ActualWidth + leftRectangle.Margin.Left + leftRectangle.Margin.Right + rightRectangle.Margin.Left + (rightRectangle.ActualWidth/2) and topRectangle.ActualHeight + topRectangle.Margin.Top + someConstantForHowTallThatSpacerRowIs + rightRectangle.Margin.Top + (rightRectangle.Height/2). Ouch
    • If we resize the container, then the rectangleGrid will also resize, but if you have used start-sizing for your columns then the rectangles all just resized. Now I have to go and recalculate all the sizes again.

    So at this point, I'd start asking myself if I really wanted the rectangleGrid to handle the sizing or maybe I should just put everything into the Canvas.

    • You don't need to resize (although be careful because there are lots of high DPI screens out there now)
    • If you resize then the sizes are much simpler (e.g. if we assume that our margins are rectangles are 3/4 of the size and the margins 1/8 each side) so that redline top point now becomes shapeCanvas.Size *11/16 and (shapeCanvas.Height - someConstantForHowTallThatSpacerRowIs)/14