简体   繁体   中英

C# wpf hittest diagonal line

I try a hittest on a diagonal line.

Unfortunatly the hittest returns true, when clicking on the bounding box of the line.

Know anyone whether it is possible to filter that without calculate it manually? Thanks!

    private void MainWindow_PreviewMouseDown(object sender)
    {
        System.Windows.Point pt = Mouse.GetPosition((UIElement)sender);

        SheetHitResultList.Clear();

        VisualTreeHelper.HitTest((UIElement)sender, new HitTestFilterCallback(OnHitTestFilter), new HitTestResultCallback(MyHitTestResult), new PointHitTestParameters(pt));
        if (Mouse.LeftButton == MouseButtonState.Pressed)
        {
            if (SheetHitResultList.Count > 0)
            {
                foreach (HitTestResult htr in SheetHitResultList)
                {
                    var temp = htr.VisualHit;
                    if (temp.GetType() == typeof(Line))
                    {
                        MessageBox.Show("Hitted");
                        //Here the MessageBox will be shown even when I click on the bounding box
                    }
                }
            }
        }
    }

    public HitTestResultBehavior MyHitTestResult(HitTestResult result)
    {
        SheetHitResultList.Add(result);

        return HitTestResultBehavior.Continue;
    }

    HitTestFilterBehavior OnHitTestFilter(DependencyObject target)
    {
        if (target.GetType() == typeof(Line))
        {

            return HitTestFilterBehavior.Continue;
        }
        else
        {
            return HitTestFilterBehavior.ContinueSkipSelf;
        }
    }

This is an adaptation of some code I have for hit testing:

    private void Canvas_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        Point pt = Mouse.GetPosition(ParentCanvas);
        AddIfInPath(ParentCanvas, pt);
    }
    private List<DependencyObject> foundControls = new List<DependencyObject>();
    private void AddIfInPath(Canvas canvas, Point point)
    {
        Point pt = new Point(point.X + 1, point.Y + 1);
        var hitTestArea = new EllipseGeometry(pt, 1, 1);
        foundControls.Clear();
        VisualTreeHelper.HitTest(
              canvas
            , null
            , new HitTestResultCallback(SelectionResult)
            , new GeometryHitTestParameters(hitTestArea));
        if (foundControls.Count > 0 && foundControls[0] is Line)
        {
            MessageBox.Show("Hit!");
        }
    }
    public HitTestResultBehavior SelectionResult(HitTestResult result)
    {
        IntersectionDetail id = ((GeometryHitTestResult)result).IntersectionDetail;
        switch (id)
        {
            case IntersectionDetail.FullyContains:
            case IntersectionDetail.FullyInside:
            case IntersectionDetail.Intersects:
                foundControls.Add(result.VisualHit);
                return HitTestResultBehavior.Continue;
            default:
                return HitTestResultBehavior.Stop;
        }
    }

My view

  <Grid>
    <Canvas PreviewMouseDown="Canvas_PreviewMouseDown"
            Name="ParentCanvas"
            >
        <Line X1="0" Y1="0" X2="700" Y2="500" Stroke="Black" StrokeThickness="2"/>
    </Canvas>
  </Grid>
</Window>

Note that hit testing is extremely expensive and hence relatively slow. If you wanted to use this programmatically to find whether a point is on a given line and do that just once then hit testing would likely be fast enough. If you want to do numerous hit test checks then they might not be a good way to go. A Bresenham line algorithm is integer based and would very quickly give you a list of integer X,Y cells between two given points. Round your double based x,y values and compare.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM