Pre loader

How to generate RolloverMarkerTemplate in code

Welcome to the SciChart Forums!

  • Please read our Question Asking Guidelines for how to format a good question
  • Some reputation is required to post answers. Get up-voted to avoid the spam filter!
  • We welcome community answers and upvotes. Every Q&A improves SciChart for everyone

WPF Forums | JavaScript Forums | Android Forums | iOS Forums

Answered
2
0

Hi,

Now that I’m binding to a SeriesSource instead of creating my RenderableSeries in XAML, I don’t know how to apply a RolloverMarkerTemplate.

In XAML I had the following:

                        <SciChart:FastLineRenderableSeries SeriesColor="Blue">
                            <SciChart:FastLineRenderableSeries.Style>
                                <Style TargetType="{x:Type SciChart:FastLineRenderableSeries}">
                                    <Setter Property="RolloverMarkerTemplate">
                                        <Setter.Value>
                                            <ControlTemplate>
                                                <Ellipse Width="7" Height="7" Fill="SlateGray" Stroke="SlateGray" StrokeThickness="1" />
                                            </ControlTemplate>
                                        </Setter.Value>
                                    </Setter>
                                </Style>
                            </SciChart:FastLineRenderableSeries.Style>
                        </SciChart:FastLineRenderableSeries>

But now I do something like this:

    _chartSeries.Add(New ChartSeriesViewModel(rawSeries, New FastLineRenderableSeries()))
            With _chartSeries(0).RenderSeries
                .SeriesColor = Colors.Blue
            End With

I’m able to set the SeriesColor = Colors.Blue in code, but I don’t know how to generate the RolloverMarkerTemplate to control other features such as the ellipse shape.

Thanks,
–George

  • You must to post comments
Best Answer
4
0

Hi George,

This is a problem we’re trying to solve (MVVM in general) and there’s no good answer at the moment! Just a note, there may be some changes in the SeriesSource API in the next major release (quite a while off though) to make this easier.

The problem is we need to separate view & viewmodel, yet retain control over series-type, colors, point-markers from the viewmodel which are much better defined in the XAML.

If you wanted to apply the same RolloverMarker to all series, you could use an unnamed style, e.g.

<!-- Define in UserControl.Resources, or Application resources, with no key -->
<Style TargetType="{x:Type SciChart:FastLineRenderableSeries}">
            <Setter Property="RolloverMarkerTemplate">
                <Setter.Value>
                    <ControlTemplate>
                        <Ellipse Width="7" Height="7" Fill="SlateGray" Stroke="SlateGray" StrokeThickness="1" />
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

This will apply the same Rollover Marker to all FastLineRenderableSeries’ in that scope.

Perhaps another solution is to define a ResourceDictionary which contains your styles (this time keyed) and set them using an attached property? E.g. if a resource dictionary was added to the App.xaml you can retrieve styles and templates from it by calling Application.Current.Resources[“key”]. Rather than getting application resources in your viewmodel sometime’s it’s better to define a property in your viewmodel of type string, and use attached properties to apply the style.

For example:

        <!-- TODO: ControlTemplates can be defined in resource dictionaries and added to App.Xaml -->
        <ControlTemplate x:Key="GrayMarkerTemplate">
            <Ellipse Width="7" Height="7" Fill="SlateGray" Stroke="SlateGray" StrokeThickness="1" />
        </ControlTemplate>

        <ControlTemplate x:Key="BlueMarkerTemplate">
            <Ellipse Width="7" Height="7" Fill="SteelBlue" Stroke="SteelBlue" StrokeThickness="1" />
        </ControlTemplate>
// Create attached properties and attached behaviours to assist and work around MVVM's limitations
public class RolloverMarkerHelper : DependencyObject
    {
        public static readonly DependencyProperty RolloverTemplateKeyProperty =
            DependencyProperty.RegisterAttached("StyleKey", typeof (string), typeof (RolloverMarkerHelper), new PropertyMetadata(default(string), OnRolloverTemplateKeyChanged));

        public static void SetRolloverTemplateKey(UIElement element, string value)
        {
            element.SetValue(RolloverTemplateKeyProperty, value);
        }

        public static string GetRolloverTemplateKey(UIElement element)
        {
            return (string) element.GetValue(RolloverTemplateKeyProperty);
        }

        private static void OnRolloverTemplateKeyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var element = d as BaseRenderableSeries;

            if (element == null)
                return;

            if (e.NewValue == null)
            {
                element.RolloverMarkerTemplate = null;
                return;
            }

            if (Application.Current != null)
            {
                var resource = Application.Current.TryFindResource(e.NewValue) as ControlTemplate;
                element.RolloverMarkerTemplate = resource;
            }
        }
    }

Then the template can be applied like this

            _chartSeries = new ObservableCollection<IChartSeriesViewModel>();

            var rSeries0 = new FastLineRenderableSeries();
            RolloverMarkerHelper.SetRolloverTemplateKey(rSeries0, "GrayMarkerTemplate");
            _chartSeries.Add(new ChartSeriesViewModel(ds0, rSeries0));

            var rSeries1 = new FastLineRenderableSeries();
            RolloverMarkerHelper.SetRolloverTemplateKey(rSeries1, "BlueMarkerTemplate");
            _chartSeries.Add(new ChartSeriesViewModel(ds1, rSeries1));

I’ve attached a full example to this post. It’s not the most elegant of solutions but it does show how you can work around some of these issues by using attached properties or attached behaviours.

Hope this helps!
Andrew

Images
  • yefchak
    Thanks for the suggestions and the demo program. When I try the demo code here, it works perfectly. But I'm unable to reproduce the results in my own program. Since I thought I might have miss-translated your RolloverMarkerHelper class from C# to VB correctly, I tried just using the unnamed style in App.xaml as described in your first suggestion above. But this doesn't work either. So then I tried applying the unnamed style approach to your attached demo program. I commented out the first call to RolloverMarkerHelper.SetRolloverTemplateKey(rSeries0, "GrayMarkerTemplate"); and instead added the unnamed style to the App.xaml file. But the rollover template shows its default appearance (red circles) rather than the gray version specified in the style. So... I'm confused. :-) Thanks, --George
  • Yuriy Zadereckiy
    Hi George, You could also achieve this using several approaches: 1. Load the template from string using XamlReader.Load() (take a look here) 2. Create it in ResourceDictionary, then instantiate the dictionary and get template from there 3. Use FrameworkElementFactory:
                    var template = new FrameworkElementFactory(typeof (Ellipse));
                    template.SetValue(Ellipse.FillProperty, new SolidColorBrush(Colors.Red));
                    template.SetValue(Ellipse.StrokeProperty, new SolidColorBrush(Colors.Black));
                    template.SetValue(Ellipse.WidthProperty, 7d);
                    template.SetValue(Ellipse.HeightProperty, 7d);
    
                    var renderableSeries = new FastLineRenderableSeries {SeriesColor = initialColor, PointMarkerTemplate=new ControlTemplate{VisualTree = template}};
    
    But notice, the last approach is deprecated way to do that(from msdn):
    This class is a deprecated way to programmatically create templates, which are subclasses of FrameworkTemplate such as ControlTemplate or DataTemplate; not all of the template functionality is available when you create a template using this class. The recommended way to programmatically create a template is to load XAML from a string or a memory stream using the Load method of the XamlReader class.
    Hope this helps! Best regards, Yuriy
  • yefchak
    :) This is all working fine now. Turns out when I was unable to see rollovers, it was because my XAML was missing the actual RolloverModifier declaration. So none of the assignments I made in code had any rollover to act on. Thanks, --George
  • Yuriy Zadereckiy
    Hi George, You are welcome - glad that you've sorted it out! Please, feel yourself free to ask if you have any questions! Best regards, Yuriy
  • You must to post comments
Great Answer
2
0

Hi, there.
I am use this way to create template for point marker for FastLine serie.
May be it will be helpfull for someone.


public static System.Windows.Controls.ControlTemplate CreateControl(System.Windows.Media.Color color)
        {
            StringBuilder sb = new StringBuilder();

            sb.Append("<ControlTemplate xmlns=" http://schemas.microsoft.com/winfx/2006/xaml/presentation">"); 
            sb.Append("<Ellipse Width="5" Height="5" Fill="" + color.ToString() + ""/>");
            sb.Append("</ControlTemplate>");

            System.IO.StringReader stringReader = new System.IO.StringReader(sb.ToString());
            System.Xml.XmlReader xmlReader = System.Xml.XmlReader.Create(stringReader);
            return (System.Windows.Controls.ControlTemplate)System.Windows.Markup.XamlReader.Load(xmlReader);
        }
  • You must to post comments
Showing 2 results
Your Answer

Please first to submit.

Try SciChart Today

Start a trial and discover why we are the choice
of demanding developers worldwide

Start TrialCase Studies