0
votes

2 Shape arrays inside 2 ItemsControls

I want to develop a kind of Vector Image Editor using WPF. Every shape with the same form is placed in an ItemsControl. There are at least 4 kind of shapes (line, rectangle, bitmap etc). The problem is:

I cannot click the shape from layer below the other layer.

The requirement:

  1. ItemsControl ItemsPanelTemplate must be Canvas with size cannot be 0.
  2. Every shape can be click anytime without activate IsHitTestVisible at the clickable shape.

The questions:

How can I enable to click shape below other shape in upper ItemsControl?

Edit 1: Add code snippet

<Grid>
    <!--Array of Ellipses-->
    <ItemsControl ItemsSource="{Binding EllipseSource}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
                <Setter Property="Canvas.Left" Value="{Binding Path=Distance}" />
                <Setter Property="Canvas.Width" Value="10" />
                <Setter Property="Canvas.Top" Value="{Binding Path=Top}" />
                <Setter Property="Canvas.Height" Value="10" />
            </Style>
        </ItemsControl.ItemContainerStyle>
        <ItemsControl.ItemTemplate>
            <Ellipse MouseDown="EllipseOnMouseDown" />
        </ItemsControl.ItemTemplate>
    </ItemsControl>

    <!--Array of Rectangles-->
    <ItemsControl ItemsSource="{Binding RectangleSource}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
                <Setter Property="Canvas.Left" Value="{Binding Path=Distance}" />
                <Setter Property="Canvas.Width" Value="10" />
                <Setter Property="Canvas.Top" Value="{Binding Path=Top}" />
                <Setter Property="Canvas.Height" Value="10" />
            </Style>
        </ItemsControl.ItemContainerStyle>
        <ItemsControl.ItemTemplate>
            <Rectangle MouseDown="RectangleOnMouseDown" />
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>
1
So with two overlap items, you want to get click event only with lower items, ignore the upper items?Tuyen Pham
Are you looking for Panel.ZIndex Attached Property MSDNGopichandar
@Gopichandar Panel.ZIndex change how a shape hide other shapes, which is overlap each other.Tuyen Pham
Something like this. May be you can make the ZIndex dynamic based on the events.Gopichandar
@Sakura I should be able to click on any shapes where ever they are. So the upper items are also important and should not be ignored.Yohanes Nurcahyo

1 Answers

1
votes

Note:

  • name your Grid control as grid
  • Change your function RectangleOnMouseDown and EllipseOnMouseDown to shape_MouseLeftButtonDown

You can use: XAML:

<Grid name="grid">
    <!--Array of Ellipses-->
    <ItemsControl ItemsSource="{Binding EllipseSource}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
                <Setter Property="Canvas.Left" Value="{Binding Path=Distance}" />
                <Setter Property="Canvas.Width" Value="10" />
                <Setter Property="Canvas.Top" Value="{Binding Path=Top}" />
                <Setter Property="Canvas.Height" Value="10" />
            </Style>
        </ItemsControl.ItemContainerStyle>
        <ItemsControl.ItemTemplate>
            <Ellipse MouseDown="shape_MouseLeftButtonDown" />
        </ItemsControl.ItemTemplate>
    </ItemsControl>

    <!--Array of Rectangles-->
    <ItemsControl ItemsSource="{Binding RectangleSource}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
                <Setter Property="Canvas.Left" Value="{Binding Path=Distance}" />
                <Setter Property="Canvas.Width" Value="10" />
                <Setter Property="Canvas.Top" Value="{Binding Path=Top}" />
                <Setter Property="Canvas.Height" Value="10" />
            </Style>
        </ItemsControl.ItemContainerStyle>
        <ItemsControl.ItemTemplate>
            <Rectangle MouseDown="shape_MouseLeftButtonDown" />
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>

Code:

List<DependencyObject> hitResultsList = new List<DependencyObject>();

// Return the result of the hit test to the callback.
public HitTestResultBehavior MyHitTestResult(HitTestResult result)
{
    hitResultsList.Add(result.VisualHit);
    return HitTestResultBehavior.Continue;
}

private void shape_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    Point pt = Mouse.GetPosition(grid);
    hitResultsList.Clear();
    VisualTreeHelper.HitTest(grid, null, new HitTestResultCallback(MyHitTestResult), new PointHitTestParameters(pt));

    foreach (var ee in hitResultsList)
    {
        if(ee is Ellipse)
        {
            MessageBox.Show("rectangle clicked!");
            var ellipse = ee as Ellipse;
            // Do something with ellipse
        }
        if(ee is Rectangle)
        {
            MessageBox.Show("ellipse clicked!");
            var rec = ee as Rectangle;
            // Do something with rectangle
        }

    }
}