定位悬停元素-WPF-C#-动态数据显示



在动态数据显示中,有一个名为MarkerPointsGraph的类。这源于FrameWorkElement(通过一系列其他类,最直接的父类是PointsGraphBase),并覆盖OnRenderMethod在图表上绘制一组标记。

它通过为屏幕上渲染的每个点调用一次适当标记类型(如三角形、圆形等)的渲染方法来实现这一点。我需要找到一种方法来识别鼠标何时悬停在其中一个标记上,以便设置该标记的工具提示。

我有一组方法,可以将点从屏幕位置转换为视口位置,再转换为数据位置。即将屏幕值转换为相应的数据值或视口值,反之亦然。

我还有这个框架元素上的工具提示打开事件和每个标记的像素大小。只要用户悬停在一个特定的标记上,我就需要确定他悬停在哪个点上,并让标记绘图设置工具提示值。

然而,转换和转换值的方法似乎不太好用,尤其是在x方向上。y方向似乎不错。

以下是一些示例代码,将解释这个想法:

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和injThirdy是两个注入的绘图仪,提供两个垂直的Y轴。它们的行为与主图表绘制器非常相似。

这里出了什么问题吗?出于某种原因,位于实际单击点之前的点正在传递缓冲区子句。

嗯,我觉得你做这件事的方式不对。如果你深入研究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。

最新更新