Расположение элемента при наведении - WPF - C# - Динамическое отображение данных

В динамическом отображении данных есть класс MarkerPointsGraph. Это происходит от FrameWorkElement (через ряд других классов по пути, самым непосредственным родителем которого является PointsGraphBase) и переопределяет OnRenderMethod для рисования набора маркеров на диаграмме.

Это делается путем вызова метода рендеринга с соответствующим типом маркера (скажем, треугольник, круг и т. Д.) Один раз для каждой точки, отображаемой на экране. Мне нужно найти способ определить, когда мышь находится на одном из этих маркеров, чтобы я мог установить подсказку для этого маркера.

У меня есть набор методов, которые позволяют мне преобразовывать точку из положения экрана в положение области просмотра и в положение данных и обратно. т.е. преобразует экранное значение в соответствующее значение данных или значение области просмотра и наоборот.

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

Тем не менее, преобразования и методы для преобразования значений, кажется, не работают нормально, особенно в направлении х. У-направление кажется хорошим.

Ниже приведен пример кода, который объяснит идею:

                    double selectedPointX = 0;
                    double selectedPointY = 0;

                    CoordinateTransform transformLocal = this.primaryPlotter.Transform;

                    if (series.SeriesDescription.YAxisAffinity == AxisAffinity_Y.Y1)
                    {
                        selectedPointX = Mouse.GetPosition(this.primaryPlotter).ScreenToViewport(transformLocal).X; //Getting the mouse positions
                        selectedPointY = Mouse.GetPosition(this.primaryPlotter).ScreenToViewport(transformLocal).Y;
                    }
                    else if (series.SeriesDescription.YAxisAffinity == AxisAffinity_Y.Y2 && injSecondaryAxis != null)
                    {
                        transformLocal = injSecondaryAxis.Transform;

                        selectedPointX = Mouse.GetPosition(this.injSecondaryAxis).ScreenToViewport(transformLocal).X;
                        selectedPointY = Mouse.GetPosition(this.injSecondaryAxis).ScreenToViewport(transformLocal).Y;
                    }
                    else if (series.SeriesDescription.YAxisAffinity == AxisAffinity_Y.Y3 && injTertiaryAxis != null)
                    {
                        transformLocal = injTertiaryAxis.Transform;

                        selectedPointX = Mouse.GetPosition(this.injTertiaryAxis).ScreenToViewport(transformLocal).X;
                        selectedPointY = Mouse.GetPosition(this.injTertiaryAxis).ScreenToViewport(transformLocal).Y;
                    }

                    foreach (var item in SeriesList)
                    {
                        if (item.Key == GraphKey)
                        {
                            for (int i = 0; i < item.Value.Collection.Count; i++)
                            {
//Calculate the size of the marker on the screen and allow for some level of inaccuracy in identifying the marker i.e anywhere within the marker is allowed. 
                                double xlowerBound = item.Value.Collection[i].DataToViewport(transformLocal).X - series.MarkerSize;
                                double xUpperBound = item.Value.Collection[i].DataToViewport(transformLocal).X + series.MarkerSize;
                                double ylowerBound = item.Value.Collection[i].DataToViewport(transformLocal).Y - series.MarkerSize;
                                double yUpperBound = item.Value.Collection[i].DataToViewport(transformLocal).Y + series.MarkerSize;

                                //If point is within bounds
                                if (!(selectedPointX < xlowerBound || selectedPointX > xUpperBound || selectedPointY < ylowerBound || selectedPointY > yUpperBound))
                                {
                                    strToolTip = item.Value.Collection[i].X + ", " + item.Value.Collection[i].Y; //This point is set as the tooltip
                                    break;
                                }
                            }

                            break;
                        }
                    }

Здесь injSecondary и injTertiary - это два инжектированных плоттера, которые обеспечивают две вертикальные оси Y. Они ведут себя очень похоже на основной график плоттера.

Здесь что-то не так? По какой-то причине точки, намного опережающие фактическую точку щелчка, проходят через условие буфера.

2 ответа

Хм, похоже, ты поступаешь из-за этого неправильно для меня. Если вы покопаетесь в исходном коде D3, вы можете открыть один из классов маркеров и напрямую отредактировать подсказку. Каждый элемент System.Windows.Shapes имеет свойство Tooltip, которое можно назначить прямо в классе маркера. Все, что вам нужно сделать, это решить, какие данные содержит подсказка.

Пример - класс CircleElementPointMarker:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;

namespace Microsoft.Research.DynamicDataDisplay.PointMarkers
{
/// <summary>Adds Circle element at every point of graph</summary>
public class CircleElementPointMarker : ShapeElementPointMarker {

    public override UIElement CreateMarker()
    {
        Ellipse result = new Ellipse();
        result.Width = Size;
        result.Height = Size;
        result.Stroke = Brush;
        result.Fill = Fill;
        if (!String.IsNullOrEmpty(ToolTipText))
        {
            ToolTip tt = new ToolTip();
            tt.Content = ToolTipText;
            result.ToolTip = tt;
        }
        return result;
    }

    public override void SetMarkerProperties(UIElement marker)
    {
        Ellipse ellipse = (Ellipse)marker;

        ellipse.Width = Size;
        ellipse.Height = Size;
        ellipse.Stroke = Brush;
        ellipse.Fill = Fill;

        if (!String.IsNullOrEmpty(ToolTipText))
        {
            ToolTip tt = new ToolTip();
            tt.Content = ToolTipText;
            ellipse.ToolTip = tt;
        }
    }

    public override void SetPosition(UIElement marker, Point screenPoint)
    {
        Canvas.SetLeft(marker, screenPoint.X - Size / 2);
        Canvas.SetTop(marker, screenPoint.Y - Size / 2);
    }
}
}

Вы можете видеть, что в этом классе есть встроенный код для обработки всплывающих подсказок. ToolTipText - это свойство, которое наследуется от родительского класса - ShapeElementPointMarker. Все, что вам нужно сделать, это назначить это свойство с данными, которые вам нужно показать.

Используйте курсор-координату на графике вместо Mouse.GetPosition, чтобы получить правильное положение экрана и избежать преобразования ScreenToViewport. Также используйте DataToScreen при создании границ.

Другие вопросы по тегам