20

I have an ItemsControl that draws thousands of Ellipses in a scatter plot on a Canvas. My problem is, if I position an Ellipse at the coordinates (4, 6) with a Height and Width of 10. The top left of the Ellipse is at (4, 6) and the shape extends down and to the right.

What I'd like to do is center the Ellipses on specific coordinates in XAML without having to use adjustments in my ViewModel layer.

Here's the working UserControl that has my graph:

<Grid>
        <ItemsControl ItemsSource="{Binding State.Data}">

            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas  ClipToBounds="False"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>

            <ItemsControl.ItemContainerStyle>
                <Style TargetType="ContentPresenter">
                    <Setter Property="Canvas.Left" Value="{Binding Path=X}" />
                    <Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
                </Style>
            </ItemsControl.ItemContainerStyle>

            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Ellipse Fill="Red"  VerticalAlignment="Center" HorizontalAlignment="Center"  Width="10" Height="20"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>

        </ItemsControl>
    </Grid>

This works great except for the uncentered ellipses. Any ideas?

bufferz
  • 3,400
  • 5
  • 24
  • 37

4 Answers4

22

You can use EllipseGeometry to accomplish this.

The XAML:

<Path Stroke="Black" StrokeThickness="3" Fill="Red" >
    <Path.Data>
        <EllipseGeometry 
            Center="{Binding Path=CenterPoint}" 
            RadiusX="5" 
            RadiusY="10" />
    </Path.Data>
</Path>

The View Model:

public Point CenterPoint { get; set;}

Can't take credit, I found this here.

Robert Gowland
  • 7,677
  • 6
  • 40
  • 58
  • Binding EllipseGeometry.Center does not work when I try it. At least not from inside of a ControlTemplate. The ellipse just goes to 0,0 and does not move when the point is changed. – Nick Jul 01 '14 at 19:28
  • @Nick, sounds like a binding issue rather than anything inherent to `EllipseGeometry` or `ControlTemplate`. In the above example, I'd search the program output for "CenterPoint" to see if there are any Binding Errors. Otherwise, it's sounds like it would make a good question on its own. All I can say about this is that it works just fine without binding. – Robert Gowland Jul 02 '14 at 14:00
  • I added a new question for this. In case you are interested: https://stackoverflow.com/questions/24534148/how-can-i-bind-to-the-center-property-of-an-ellipsegeometry – Nick Jul 02 '14 at 14:48
  • Helped me big time, though not the way the question was asked. – AgentFire Oct 18 '14 at 10:16
  • Tried all the other solutions and this is the only one that worked for me. A little bit longer to type, but it worked the first time. Thanks! – Anthony Nichols May 23 '16 at 17:38
9

Its not fully automatic but this solution does at least keep the centering logic inside the view and doesn't muddy your model

<Ellipse Fill="Red" Width="10" Height="20">
  <Ellipse.RenderTransform>
    <TranslateTransform X="-5" Y="-10" />
   </Ellipse.RenderTransform>
</Ellipse>
Mr Bell
  • 9,228
  • 18
  • 84
  • 134
2

I suggest, you DO change your ViewModel and name the properties Left and Top, so it is clear what is meant. If you also need the X and Y values, just leave them. I suggest this, because X and Y can mean different things, dependent on the shape you are drawing.

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • If I do that then I'll have to know the radius of the Ellipse in order to properly center it where I want it to. I'd really like to avoid doing that so I can mess with my View and keep those ellipses centered. – bufferz Mar 24 '11 at 17:28
  • @bufferz: I don't understand you. How do you think, you can achieve this, without knowing the exact parameters of your shape? As djacobson pointed out, you don't need to know the radius, when you have the width and height. – Daniel Hilgarth Mar 24 '11 at 17:35
  • I was hoping this could be done automatically, without me having to know the radius (or width/height) of the ellipse. Kind of like how you can center a TextBlock or Label without knowing the length of its contents. – bufferz Mar 24 '11 at 17:50
  • @bufferz: Just pause a moment and think: How do you want to center a shape, when you don't know its width and height? Whoever executes the centering needs to know all parameters. – Daniel Hilgarth Mar 24 '11 at 17:52
  • I do know the width and height, so does my UserControl. As you can see I did specify those parameters in the Ellipse template. If I can calculate the center position of the Ellipse using my desired center and the width/height parameters, why can't WPF? Also -- I realize I'm circling the drain here and that what I'd like to do isn't possible. However thanks for chiming in to help me out. – bufferz Mar 24 '11 at 17:58
2

Since the Canvas.Left/Right/Top/Bottom properties measure distance between those sides of the Canvas and the associated sides of your Ellipse, the only way to use them to control where the center of the Ellipse lands is to accommodate its Height and Width in the ViewModel.

In other words, however you've determined that the Ellipse's center should land at (4,6), and that it should have Height/Width = 10, the X and Y properties exposed by the ViewModel should have the values 4 - 10 and 6 - 10 (i.e. (-6,-4)), which would be the resulting values of Canvas.Left and Canvas.Top.

Update: After thinking about this a little more, an alternative occurred to me. As a caveat, I haven't tested this. But if you just used your current solution and styled the Ellipses such that their Margin (or at least their Top/Left margins) were equal to -1 * Height (or Width), that would (I think) land their center on the coordinates given by X and Y... Worth a shot. :)

Dan J
  • 16,319
  • 7
  • 50
  • 82