Вопрос

При использовании Onrender, чтобы нарисовать что-то на экране, есть ли способ выполнить удары на развлеченной графике?

Образец кода

    protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)
    {
        base.OnRender(drawingContext);

        drawingContext.DrawRectangle(Brushes.Black, null, new Rect(50, 50, 100, 100));
    }

Очевидно, что человек не имеет ссылки на нарисованное прямоугольник, что было бы необходимости выполнять тестирование ударов или я ошибаюсь об этом? Я знаю, что я могу использовать DrawsVisual, мне просто любопытно, если мое понимание правильно, что используя Onrender, чтобы нарисовать то, что вы не можете выполнить тестирование на нарисованные вещи?

Это было полезно?

Решение

Вы поняли правильно, нет никакого способа хитристы на графике, которую вы сделали с помощью методов DrawingContext, потому что они не представлены как объекты в визуальном дереве.

Другие советы

Если я не полностью недопонимаю вопрос о вопросах ОП, ответ да, это тест на удары основан на том, что рисуется во время OnRender. Отказ Вы можете сказать, переопределение OnMouseEnter в том же классе, в котором вы переопределяете OnRender. Отказ Во время переопределения OnMouseEnter попробуй это:

var htr = VisualTreeHelper.HitTest(this, e.GetPosition(this));
if (htr != null)
     System.Diagnostics.Debug.WriteLine("It's a hit!");

Теперь я замечаю, что вы все еще звонили base.OnRender что говорит о том, что вы пытаетесь нарисовать на то, что Visual в противном случае обратился бы. То, что вы не сможете сделать, то это отличает попадание на то, что родительский класс, сделанный из того, что вы визурили в вашем переопределении. Однако, если вам это нужно, просто держите свой рисунок, содержащийся к своему Visual.

Мое быстрое решение. Это не идеально во многом, но это работает для меня как начать. Может быть легко рефраксировано для производительности, если это станет необходимым.

    /// <summary>
    /// Provides basic hit testing
    /// </summary>
    public class RadarHitTestUtility
    {
        public Dictionary<Tuple<int,int>, HitContainer> HitStorage = new Dictionary<Tuple<int, int>, HitContainer>();

        public void AddEllipse(RadarObject radarObject, Point point, double x, double y)
        {
            // Geometry used for hit testing
            var elipse = new EllipseGeometry
            {
                Center = point,
                RadiusX = x,
                RadiusY = y,
            };

            var key = new Tuple<int, int>((int)point.X, (int)point.Y);

            var hit = new HitContainer
            {
                Geometry = elipse,
                Bounds = elipse.Bounds,
                RadarObject = radarObject
            };

            if(!HitStorage.ContainsKey(key))
                HitStorage.Add(key, hit);
        }

        /// <summary>
        /// Gets first radar object whose center point is within distance of point.
        /// </summary>
        public HitContainer GetSimpleHit(Point point, int distance = 5)
        {
            foreach (var hit in HitStorage)
            {
                if (Math.Abs(hit.Key.Item1 - point.X) <= distance && Math.Abs(hit.Key.Item2 - point.Y) <= distance)
                {
                    hit.Value.Intersection = IntersectionDetail.NotCalculated;
                    return hit.Value;
                }
            }
            return default(HitContainer);
        }

        /// <summary>
        /// Gets first radar object that contains point
        /// </summary>
        public HitContainer GetHit(Point point)
        {
            var PreCheckDistance = 50;

            foreach (var hit in HitStorage)
            {
                if (Math.Abs(hit.Key.Item1 - point.X) <= PreCheckDistance && Math.Abs(hit.Key.Item2 - point.Y) <= PreCheckDistance)
                {
                    if (hit.Value.Geometry.FillContains(point))
                    {
                        hit.Value.Intersection = IntersectionDetail.FullyInside;
                        return hit.Value;
                    }                    
                }
            }
            return default(HitContainer);
        }

        /// <summary>
        /// Gets first radar object that intersects with geometry
        /// </summary>
        public HitContainer GetHit(Geometry geometry)
        {
            var PreCheckDistance = 50;
            var GeometryCheckTolerance = 1;
            var center = geometry.Bounds.Center();

            foreach (var hit in HitStorage)
            {
                if (Math.Abs(hit.Key.Item1 - center.X) <= PreCheckDistance && Math.Abs(hit.Key.Item2 - center.Y) <= PreCheckDistance)
                {
                    var result = hit.Value.Geometry.FillContainsWithDetail(geometry, GeometryCheckTolerance, ToleranceType.Absolute);
                    if (result != IntersectionDetail.Empty)
                    {
                        hit.Value.Intersection = result;
                        return hit.Value;
                    }
                }
            }
            return default(HitContainer);
        }

        public class HitContainer
        {
            public RadarObject RadarObject { get; set; }
            public Geometry Geometry { get; set; }
            public Rect Bounds { get; set; }
            public IntersectionDetail Intersection { get; set; }
        }

        public void Clear()
        {
            HitStorage.Clear();
        }
    }

Объявить экземпляр в вашем контроле

public RadarHitTestUtility HitTester = new RadarHitTestUtility();

Вам нужно будет позвонить четко () в какой-то момент, чтобы существовать только текущие объекты в сборе ударов.

HitTester.Clear();

В Onrender (), когда вы хотите, чтобы вызов ничьей должен быть записан для целей тестирования ударов, вы можете записать его с помощью Addellipse ()

HitTester.AddEllipse(radarObject, radarObject.Point, actorRadius, actorRadius);

Вот как я звоню на чек удара

    private void MouseDownHandler(object sender, MouseButtonEventArgs e)
    {
        IsMouseDown = true;
        Cursor = Cursors.Hand;
        DragInitialPosition = Mouse.GetPosition(this);
        DragInitialPanOffset = CanvasData.PanOffset;

        var hit = FindElementUnderClick(sender, e);
        if (hit != null)
        {
            SelectedItem = hit.RadarObject.Actor;
        }            
    }

    private RadarHitTestUtility.HitContainer FindElementUnderClick(object sender, MouseEventArgs e)
    {
        var position = e.GetPosition((UIElement)sender);            
        return HitTester.GetHit(position);
    }

Если вы хотите иметь возможность проверить фигуры, отличные от эллипса, вы просто добавили подходящую метод записи в RADARHITTETTUTIVE и вызывать его, создавая другой вид геометрии для тестирования.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top