Hello again,
I'm trying to figure out how to make the series lines dotted in a Silverlight xamWebChart. I have so far tried two approaches without much luck.
Firstly, I tried applying a dotted line style directly to the series object - I received the exception "Element is already the child of another element".
Then, I found an example that specified the following:
<igWebChart:XamWebChart.Resources>
<Style TargetType="{x:Type Line}">
<Setter Property="StrokeDashArray" Value="2,1" />
</Style>
</igWebChart:XamWebChart.Resources>
However, I receive the error that "Type" is not found.
Any insight would be appreciated. Thanks again!
the x:Type markup extension doesn't exist in Silverlight, only WPF. Try just TargetType="Line" although I'm not sure if the implicit style will work in this case or not. Let me know if it doesn't and I'll see if I can help.
^ Silverlight and recent versions of WPF will automatically try to convert string values into types without the need of a markup extension.
-Graham
This seems to work, but only for the first segment of the line. I've included the code below as a reference. I'm also seeing a message in the xaml that "Resource {x:Type System.Windows.Shapes.Line} is never used.", although clearly at least the first segment of the line is dotted.
<Style TargetType="Line">
Thank you again for your time!
Is it possible that this is somehow due to other bindings I'm doing? Here is the full xaml of my grid (sans three of the axes, since their bindings are almost identical).
<Grid x:Name="LayoutRoot">
<igWebChart:XamWebChart x:Name="Chart">
<igWebChart:XamWebChart.Axes>
<igWebChart:Axis AxisType="PrimaryX" Visibility="{Binding PrimaryXAxisVisibility, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Visible}" AutoRange="{Binding PrimaryXAxisAutoRange}" Minimum="{Binding PrimaryXAxisMinimum}" Maximum="{Binding PrimaryXAxisMaximum}" Unit="{Binding PrimaryXAxisUnit}">
<igWebChart:Axis.MajorGridline>
<igWebChart:GridlineGroup Visibility="{Binding PrimaryXAxisGridlineVisibility, Converter={StaticResource BooleanToVisibilityConverter}}" Stroke="{Binding PrimaryXAxisGridlineColor}" GridlineStyle="{Binding PrimaryXAxisGridlineStyle, Converter={StaticResource StringToGridlineStyleConverter}}"/>
</igWebChart:Axis.MajorGridline>
<igWebChart:Axis.Label>
<igWebChart:LabelGroup Angle="{Binding PrimaryXAxisLabelAngle}" Format="{Binding PrimaryXAxisLabelFormat}" FontFamily="{Binding PrimaryXAxisLabelFontFamily}" FontSize="{Binding PrimaryXAxisLabelFontSize}" Foreground="{Binding PrimaryXAxisLabelFontColor}"/>
</igWebChart:Axis.Label>
</igWebChart:Axis>
</igWebChart:XamWebChart.Axes>
<igWebChart:XamWebChart.Legend>
<igWebChart:Legend Visibility="{Binding LegendVisibility, Converter={StaticResource BooleanToVisibilityConverter}}" FontFamily="{Binding LegendFontFamily}" FontSize="{Binding LegendFontSize}" Foreground="{Binding LegendFontColor}" />
</igWebChart:XamWebChart.Legend>
<igWebChart:XamWebChart.Series>
<igWebChart:Series ChartType="Line" DataSource="{Binding ChartData}" DataMapping="Value = Value;Label = Label" />
</igWebChart:XamWebChart.Series>
</igWebChart:XamWebChart>
</Grid>
You are actually hitting a bug in the Silverlight runtime whereby the value for a StrokeDashArray cannot be shared between multiple elements. Our line is composed of multiple line segments, so when you attempt to use the style to set the same stroke dash array for all the elements, Silverlight only applies it to the first element. I'll let you know if I find some work around, but I suspect Silverlight will stand in your way on this one.
One workaround would be to create a copy of your style for each data point, and assign each data point that style directly. But this is a bit of an annoying solution to the problem.
Thanks for your response. I think the annoying solution will work for now.
Luckily enough, I don't like to let Silverlight tell me what I can't do.
<Style TargetType="Line"> <Setter Property="local:WorkArounds.StrokeDashArraySetter"> <Setter.Value> <local:StrokeDashArraySetter Value="2,1" /> </Setter.Value> </Setter> </Style>
And to support it:
public static class WorkArounds { public static readonly DependencyProperty StrokeDashArraySetterProperty = DependencyProperty.RegisterAttached( "StrokeDashArraySetter", typeof(StrokeDashArraySetter), typeof(WorkArounds), new PropertyMetadata(null, (o, e) => OnDataPointStylerChanged(o, e))); public static void SetStrokeDashArraySetter( DependencyObject target, StrokeDashArraySetter value) { target.SetValue(StrokeDashArraySetterProperty, value); } public static StrokeDashArraySetter GetStrokeDashArraySetter( DependencyObject target) { return (StrokeDashArraySetter)target .GetValue(StrokeDashArraySetterProperty); } private static void OnDataPointStylerChanged( DependencyObject o, DependencyPropertyChangedEventArgs e) { var oldValue = e.OldValue as StrokeDashArraySetter; var newValue = e.NewValue as StrokeDashArraySetter; if (oldValue != null) { oldValue.Detach(o); } if (newValue != null) { newValue.Attach(o); } } } public class StrokeDashArraySetter { public string Value { get; set; } private DependencyObject _owner; internal void Attach(DependencyObject o) { if (_owner != null) { Detach(_owner); } var dep = o; if (dep == null) { return; } _owner = dep; if (_owner is Shape) { var shape = _owner as Shape; if (Value == null) { return; } string[] vals = Value.Split(','); DoubleCollection coll = new DoubleCollection(); foreach (var val in vals) { double res; if (double.TryParse(val, out res)) { coll.Add(res); } } shape.StrokeDashArray = coll; } } internal void Detach(DependencyObject o) { _owner = null; } }
Hope this helps!
It works splendidly. The problem was that I had somehow undone my changes to the xaml for the style, and was using the old version instead of your new Workarounds version. You have more than answered my question, thank you sir.
Hi,
Could you explain how your scenario differs from this sample which shows all line segments as dotted for me:
App.xaml:
<Application.Resources> <Style x:Key="lineStyle" TargetType="Line"> <Setter Property="local:WorkArounds.StrokeDashArraySetter"> <Setter.Value> <local:StrokeDashArraySetter Value="5,1" /> </Setter.Value> </Setter> </Style> </Application.Resources>
MainPage.xaml:
<Grid x:Name="LayoutRoot" Background="White"> <igChart:XamWebChart x:Name="chart1" Loaded="chart1_Loaded"> <igChart:XamWebChart.Series> <igChart:Series ChartType="Line"> <igChart:Series.DataPoints> <igChart:DataPoint Label="A" Value="1" /> <igChart:DataPoint Label="B" Value="2" /> <igChart:DataPoint Label="C" Value="3" /> <igChart:DataPoint Label="D" Value="4" /> <igChart:DataPoint Label="E" Value="5" /> <igChart:DataPoint Label="F" Value="4" /> <igChart:DataPoint Label="G" Value="3" /> <igChart:DataPoint Label="H" Value="2" /> <igChart:DataPoint Label="I" Value="1" /> <igChart:DataPoint Label="J" Value="2" /> <igChart:DataPoint Label="K" Value="3" /> </igChart:Series.DataPoints> </igChart:Series> </igChart:XamWebChart.Series> </igChart:XamWebChart> </Grid>
Code behind:
public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } private void chart1_Loaded(object sender, RoutedEventArgs e) { foreach (DataPoint point in chart1.Series[0].DataPoints) { point.Style = (Style)Application.Current.Resources["lineStyle"]; } } } public static class WorkArounds { public static readonly DependencyProperty StrokeDashArraySetterProperty = DependencyProperty.RegisterAttached( "StrokeDashArraySetter", typeof(StrokeDashArraySetter), typeof(WorkArounds), new PropertyMetadata(null, (o, e) => OnDataPointStylerChanged(o, e))); public static void SetStrokeDashArraySetter( DependencyObject target, StrokeDashArraySetter value) { target.SetValue(StrokeDashArraySetterProperty, value); } public static StrokeDashArraySetter GetStrokeDashArraySetter( DependencyObject target) { return (StrokeDashArraySetter)target .GetValue(StrokeDashArraySetterProperty); } private static void OnDataPointStylerChanged( DependencyObject o, DependencyPropertyChangedEventArgs e) { var oldValue = e.OldValue as StrokeDashArraySetter; var newValue = e.NewValue as StrokeDashArraySetter; if (oldValue != null) { oldValue.Detach(o); } if (newValue != null) { newValue.Attach(o); } } } public class StrokeDashArraySetter { public string Value { get; set; } private DependencyObject _owner; internal void Attach(DependencyObject o) { if (_owner != null) { Detach(_owner); } var dep = o; if (dep == null) { return; } _owner = dep; if (_owner is Shape) { var shape = _owner as Shape; if (Value == null) { return; } string[] vals = Value.Split(','); DoubleCollection coll = new DoubleCollection(); foreach (var val in vals) { double res; if (double.TryParse(val, out res)) { coll.Add(res); } } shape.StrokeDashArray = coll; } } internal void Detach(DependencyObject o) { _owner = null; } }
It's not null afterwards - and I did put that style in my app.xaml.
Something else interesting - if I place the style in <igWebChart:XamWebChart.Resources>, it only applies itself to the first line segment if it does not have a key name. Not really important, but I noticed it.
I only want to apply the dotted style to my series sometimes, so I need to be able to do it programmatically rather than having it explicitly set all the time. Sorry for the hassle, but I'm really hoping you can help me solve this. Thanks again.
make sure that point.Style is not null after that line, in other words.
I suspect you have your style defined at a lower level than App.xaml.
try: point.Style = (Style)Resources["dottedline"];