Question

I have a collection of type MyType { double X, double Y, string Text }.

How to show it like points (or markers) with X, Y-coordinates and with labels with Text as text?

  • Labels have to be seen constantly - so no tooltips.
  • The Text property varies from point to point.
Was it helpful?

Solution

Well, the solution is to make your own marker with text dependency property and then add mapping to this property. And it comes to something like this (it seems to look a bit grubby, but it illustrates the main idea). It is the pulse sequence with labels with duration time at start of each pulse:

Custom marker class without minor properties (I derive not from ShapeElementPointMarker because of the last one has undesirable properties for me):

public class LabeledPointMarker : ElementPointMarker
{
    #region TextProperty
    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register(
        "Text",
        typeof(string),
        typeof(LabeledPointMarker));

    public string Text
    {
        get { return (string)this.GetValue(LabeledPointMarker.TextProperty); }
        set { this.SetValue(LabeledPointMarker.TextProperty, value); }
    }
    #endregion TextProperty

    // ...
    // Another dependency properties in the same manner.
    // ...

    public override UIElement CreateMarker()
    {
        TextBlock tb = new TextBlock()
        {
            Text = this.Text,
            Foreground = this.TextBrush
        };

        Border b = new Border()
        {
            BorderBrush = this.BorderBrush,
            BorderThickness = this.BorderThickness,
            Background = this.BorderBackground,
            Child = tb
        };

        return b;
    }

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

Now you can create a "N-dimensional collection" (in simple words) that is an one-dimensional collection of complex type. For me I just use the Tuple:

var data =
    results.Data
    .Select(d => 
        new Tuple<double, double, string>(
        d.StartIndex, 
        0, 
        d.DurationTime.ToString("######.####")))
    .ToList();

And then you create data source, set mappings (another key - AddMapping method), create marker template (and set the properties in the template that isn't setted in the mappings), create ElementMarkerPointsGraph, add map source and marker template to this graph, and at last add this graph to the plotter (sorry for my English - I'm not englishspeaker :) ):

EnumerableDataSource<Tuple<double, double, string>> dataSource =
    new EnumerableDataSource<Tuple<double, double, string>>(data);
dataSource.SetXMapping(x => x.Item1);
dataSource.SetYMapping(y => y.Item2);
dataSource.AddMapping(LabeledPointMarker.TextProperty, t => t.Item3);

ElementMarkerPointsGraph empg = new ElementMarkerPointsGraph();
empg.DataSource = dataSource;
empg.Marker = new LabeledPointMarker()
{
    TextBrush = Brushes.Black,
    BorderBackground = Brushes.Red,
    BorderBrush = Brushes.Purple,
    BorderThickness = new Thickness(2)
};

chartPlotter.Children.Add(empg);

In addition, it may need to return not the same UIElement in the CreateMarker, but its copy. Otherwise it may throws exception because of mapping at the same UIElement ("dataSource.AddMapping" part of the code above). Because of UIElement is an object it may be not trivial to get its copy. So the easiest way that I found is to use the copy technique like this.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top