Search code examples
c#wpfmvvmlegendscichart

SciChart: Move SciChartLegend to separate part of application


Sorry if it look like a duplicate of question asked on SciChart forum https://www.scichart.com/questions/wpf/move-settings-from-legend-to-separate-menu but I didn't found the solution yet. Maybe I will get help here. I am new in SciChart components and I make my application using examples and tutorials at SciChart website. But I am working already a long time ago with C#, WPF & MVVM-pattern and when I add SciChart in my application I used SciChart examples from MVVM tutorial. OK, let's get to the main point. When I thought about UI of my application I decided that better to make several UserControls with panels on which placed a controls. This UserControls will be placed on any part of UI, used as modal windows, will be placed on slide panels etc. Now I have SciChartSurface on one of UserControls

        <Border Grid.Row="1" Grid.Column="0" Margin="5" Padding="5" BorderBrush="Black" BorderThickness="1,1,1,1" CornerRadius="5">
            <Grid>
                <s:SciChartSurface ChartTitle="{localVM:Localization MainChartSciChartSurface}" RenderableSeries="{s:SeriesBinding RenderableSeries}" Annotations="{s:AnnotationsBinding Annotations}">
                    <s:SciChartSurface.XAxis>
                        <s:NumericAxis AxisTitle="{localVM:Localization XNumericAxis}" VisibleRange="{Binding VisibleRangeXAxis, Mode=TwoWay}" />
                    </s:SciChartSurface.XAxis>
                    <s:SciChartSurface.YAxis>
                        <s:NumericAxis AxisTitle="{localVM:Localization YNumericAxis}" VisibleRange="{Binding VisibleRangeYAxis, Mode=TwoWay}"
                                       AutoRange="{Binding IsStaticYAxis, Converter={StaticResource StaticAxisToSciChartAutoRangeConverter}}" GrowBy="0.1,0.1" />
                    </s:SciChartSurface.YAxis>
                    <s:SciChartSurface.ChartModifier>
                        <s:ModifierGroup>
                            <s:SeriesValueModifier />
                            <s:CursorModifier IsEnabled="{Binding IsShowValuesCursor}" />
                            <s:LegendModifier x:Name="SciChartLegendModifier" LegendData="{Binding LegendData}" GetLegendDataFor="AllSeries" ShowLegend="False" />
                        </s:ModifierGroup>
                    </s:SciChartSurface.ChartModifier>
                </s:SciChartSurface>
            </Grid>
        </Border>

Chart series created in ViewModel

        private ObservableCollection<IRenderableSeriesViewModel> _renderableSeries;
        public ObservableCollection<IRenderableSeriesViewModel> RenderableSeries
        {
            get { return _renderableSeries; }
            set
            {
                SetProperty(ref _renderableSeries, value, nameof(RenderableSeries));
            }
        }

        private ObservableCollection<IAnnotationViewModel> _annotations;
        public ObservableCollection<IAnnotationViewModel> Annotations
        {
            get { return _annotations; }
            set
            {
                SetProperty(ref _annotations, value, nameof(Annotations));
            }
        }

        private ChartDataObject _legendData;
        public ChartDataObject LegendData
        {
            get { return _legendData; }
            set
            {
                SetProperty(ref _legendData, value, nameof(LegendData));
            }
        }

        private void InitCharts()
        {
            _renderableSeries = new ObservableCollection<IRenderableSeriesViewModel>();
            _annotations = new ObservableCollection<IAnnotationViewModel>();
            _legendData = new ChartDataObject();

            _lineDataDiameter1 = InitChart(new InitChartRequest() { ChartName = CHART_NAME_DIAMETER_1, LineColor = Colors.OrangeRed, ChartStyle = CHART_LINE_STYLE });
            _lineDataDiameter2 = InitChart(new InitChartRequest() { ChartName = CHART_NAME_DIAMETER_2, LineColor = Colors.BlueViolet, ChartStyle = CHART_LINE_STYLE });
            _lineDataCovering1 = InitChart(new InitChartRequest() { ChartName = CHART_NAME_COVERING_1, LineColor = Colors.LimeGreen, ChartStyle = CHART_LINE_STYLE });
            _lineDataCovering2 = InitChart(new InitChartRequest() { ChartName = CHART_NAME_COVERING_2, LineColor = Colors.DeepSkyBlue, ChartStyle = CHART_LINE_STYLE });
            _lineDataCovering3 = InitChart(new InitChartRequest() { ChartName = CHART_NAME_COVERING_3, LineColor = Colors.White, ChartStyle = CHART_LINE_STYLE });
        }

        private XyDataSeries<double, double> InitChart(InitChartRequest request)
        {
            XyDataSeries<double, double> lineData = new()
            {
                SeriesName = request.ChartName,
            };

            RenderableSeries.Add(new LineRenderableSeriesViewModel()
            {
                Stroke = request.LineColor,
                DataSeries = lineData,
                StyleKey = request.ChartStyle,
            });

            return lineData;
        }

And now I want to place SciChartLegend to another one of UserControls. SciChart website has an example https://www.scichart.com/documentation/win/current/webframe.html#LegendModifier.html how to separate SciChartSurface and SciChartLegend but the problem that in this example they are separated but into one module. I check it on my application and it worked but as I said before I need to place SciChartLegend to another UserControl and we can't use binding like this

LegendData="{Binding LegendData, ElementName=legendModifier, Mode=OneWay}"

And I as understand it is not good way for MVVM. After that I decided to use classic MVVM-binding and added LegendData property with type ChartDataObject in code and bound it to SciChartSurface.ChartModifier.ModifierGroup.LegendModifier.LegendData and SciChartLegend.LegendData (you can see it in XAML code above and below)

        <Border DockPanel.Dock="Top" Margin="5" Padding="5" BorderBrush="Black" BorderThickness="1,1,1,1" CornerRadius="5">
            <StackPanel>
                <s:SciChartLegend x:Name="SciChartLegendControl"
                                  s:ThemeManager.Theme="Chrome"
                                  Margin="5,5"
                                  ScrollViewer.HorizontalScrollBarVisibility="Auto"
                                  ScrollViewer.VerticalScrollBarVisibility="Auto"
                                  LegendData="{Binding LegendData}"
                                  ShowVisibilityCheckboxes="True" />
            </StackPanel>
        </Border>

But I don't understand how to add RenderableSeries.DataSeries data to LegendData object. All legend examples not used IRenderableSeriesViewModel and LineRenderableSeriesViewModel, it used IRenderableSeries and FastLineRenderableSeries. But I think it is possible because it works if make it as in example (move legend in one module with chart).

What I doing wrong? How can I fix it? Looks like it not hard but how?


Solution

  • Answer added to SciChart forum https://www.scichart.com/questions/wpf/move-settings-from-legend-to-separate-menu