Home > Software design >  WPF vs WinForms Oxyplot Customize Tooltip/Tracker
WPF vs WinForms Oxyplot Customize Tooltip/Tracker

Time:04-05

I am building a WPF application and rendering a chart using OxyPlot.

In order to maximize the performance of the chart, I switched to OxyPlot.WindowsForms and embedded the chart using WindowsFormsHost. Source: enter image description here

WPF: enter image description here

Is there any way to customize the WindowsForms tooltip to look anything like the WPF one? The most important things are the vertical and horizontal line of the point.

CodePudding user response:

Looking into the source code of the component, it's not really a tooltip, enter image description here

Using the following code:

private Label trackerLabel;
private void Form1_Load(object sender, EventArgs e)
{
    var trackerLabelField = plotView1.GetType().GetField("trackerLabel",
        System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
    trackerLabel = new BalloonLabel()
    {
        Visible = false,
        Parent = plotView1
    };
    trackerLabelField.SetValue(plotView1, trackerLabel);

    var myModel = new PlotModel { Title = "Example 1" };
    myModel.Series.Add(new FunctionSeries(Math.Cos, 0, 10, 0.1, "cos(x)"));
    this.plotView1.Model = myModel;
    this.plotView1.Paint  = PlotView1_Paint;
    trackerLabel.VisibleChanged  = TrackerLabel_VisibleChanged;
}
private void TrackerLabel_VisibleChanged(object sender, EventArgs e)
{
    plotView1.Invalidate();
}
private void PlotView1_Paint(object sender, PaintEventArgs e)
{
    if (trackerLabel.Visible)
    {
        var r = plotView1.Model.PlotArea;
        e.Graphics.DrawLine(Pens.Blue, trackerLabel.Left   trackerLabel.Width / 2, (int)r.Top,
            trackerLabel.Left   trackerLabel.Width / 2, (int)r.Bottom);
        e.Graphics.DrawLine(Pens.Blue, (int)r.Left, trackerLabel.Bottom, (int)r.Right, trackerLabel.Bottom);
    }
}

And this balloon label, which I assume is a good-enough start point:

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
public class BalloonLabel : Label
{
    public BalloonLabel()
    {
        BackColor = SystemColors.Info;
        Padding = new Padding(5, 5, 5, 20);
        ArrowSize = new Size(10, 20);
        AutoSize = true;
    }
    private Size arrowSize;
    public Size ArrowSize
    {
        get { return arrowSize; }
        set
        {
            arrowSize = value;
            this.RecreateRegion();
        }
    }

    private GraphicsPath GetBalloon(Rectangle bounds)
    {
        GraphicsPath path = new GraphicsPath();
        path.StartFigure();

        if (arrowSize.Width > 0 && arrowSize.Height > 0)
        {
            path.AddLine(bounds.Left, bounds.Bottom - arrowSize.Height / 2, bounds.Left, bounds.Top);
            path.AddLine(bounds.Left, bounds.Top, bounds.Right, bounds.Top);
            path.AddLine(bounds.Right, bounds.Top, bounds.Right, bounds.Bottom - arrowSize.Height / 2);
            path.AddLine(bounds.Right, bounds.Bottom - arrowSize.Height / 2, bounds.Left   bounds.Width / 2   arrowSize.Width / 2, bounds.Bottom - arrowSize.Height / 2);
            path.AddLine(bounds.Left   bounds.Width / 2   arrowSize.Width / 2, bounds.Bottom - arrowSize.Height / 2,
                bounds.Left   bounds.Width / 2, bounds.Bottom);
            path.AddLine(bounds.Left   bounds.Width / 2, bounds.Bottom,
                bounds.Left   bounds.Width / 2 - arrowSize.Width / 2, bounds.Bottom - arrowSize.Height / 2);
            path.AddLine(bounds.Left   bounds.Width / 2 - arrowSize.Width / 2, bounds.Bottom - arrowSize.Height / 2,
                bounds.Left, bounds.Bottom - arrowSize.Height / 2);
        }
        else
        {
            path.AddLine(bounds.Left, bounds.Bottom, bounds.Left, bounds.Top);
            path.AddLine(bounds.Left, bounds.Top, bounds.Right, bounds.Top);
            path.AddLine(bounds.Right, bounds.Top, bounds.Right, bounds.Bottom);
            path.AddLine(bounds.Right, bounds.Bottom, bounds.Left, bounds.Bottom);
        }
        path.CloseFigure();
        return path;
    }

    private void RecreateRegion()
    {
        var r = ClientRectangle;
        using (var path = GetBalloon(r))
            this.Region = new Region(path);
        this.Invalidate();
    }
    protected override void OnSizeChanged(EventArgs e)
    {
        base.OnSizeChanged(e);
        this.RecreateRegion();
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        var r = ClientRectangle;
        r.Inflate(-1, -1);
        using (var path = GetBalloon(r))
        {
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
            using (var pen = new Pen(Color.Gray, 1) { Alignment = PenAlignment.Inset })
                e.Graphics.DrawPath(pen, path);
            if (Parent != null)
                Parent.Invalidate();
        }
    }
}

And here is the animated result:

enter image description here

  • Related