Page 1 of 1

Problem in switching dynamically the colorTheme property

Posted: Mon Nov 02, 2020 9:09 am
by cchrc
In my application users can switch theme between dark and light at runtime. So I would like that also the charts follow the same behavior, however I'm struggling in achieving this.
I'm using the semi-bindable API, so I have a xaml like this:

Code: Select all

<lcusb:LightningChartUltimate 
		ColorTheme="{Binding Theme.Value}"
                Title="{Binding ChartTitle.Value}"
                ActiveView="{Binding ViewType.Value}">
                ... 
</lcusb:LightningChartUltimate>
However this approach do not work. When ColorTheme binding is present I get a null reference exception:
System.NullReferenceException: Object reference not set to an instance of an object.
at Arction.Wpf.SemibindableCharting.LightningChartUltimate.AQC(ColorTheme A)
at Arction.Wpf.SemibindableCharting.LightningChartUltimate.ColorThemeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
at System.Windows.DependencyObject.InvalidateProperty(DependencyProperty dp, Boolean preserveCurrentValue)
at System.Windows.Data.BindingExpressionBase.Invalidate(Boolean isASubPropertyChange)
at System.Windows.Data.BindingExpression.TransferValue(Object newValue, Boolean isASubPropertyChange)
at System.Windows.Data.BindingExpression.Activate(Object item)
at System.Windows.Data.BindingExpression.AttachToContext(AttachAttempt attempt)
at System.Windows.Data.BindingExpression.MS.Internal.Data.IDataBindEngineClient.AttachToContext(Boolean lastChance)
at MS.Internal.Data.DataBindEngine.Task.Run(Boolean lastChance)
at MS.Internal.Data.DataBindEngine.Run(Object arg)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)

A more complete stacktrace produced by ChartChartMessage event can be found at: https://pastebin.com/ZQMq5qnG


So I then followed the approach described in this topic: viewtopic.php?f=16&t=653&p=2439&hilit=colorTheme#p2439
However it does not work very well as the result is a partial theme change as you can see in the attached screenshot. It seems that some part of the chart are not rendered with the correct theme.

Thanks in advance.

Re: Problem in switching dynamically the colorTheme property

Posted: Mon Nov 02, 2020 9:58 am
by Arction_LasseP
Hello,

This is a known issue. Currently, you can't set ColorTheme properly in xaml because of the creation order of chart components. Views such as ViewXY are created with default color settings after the chart itself has been created in the xaml. Therefore the ColorTheme is overridden by the default colors. This is something we will fix in a future release.

The workaround is to set the theme in the code behind as is suggested in the thread you mentioned. Why it affects only partially in your app is unclear. Are you modifying some colors after this? Or maybe the binding affects this somehow.
You could also change the ColorTheme inside Loaded or even AfterRendering event to make sure the chart has been loaded first. At least in my tests these worked.

Code: Select all

_chart.Loaded += _chart_Loaded;

        private void _chart_Loaded(object sender, RoutedEventArgs e)
        {
            _chart.ColorTheme = ColorTheme.LightGray;
        }
        
// or alternatively

_chart.AfterRendering += _chart_AfterRendering;

        private void _chart_AfterRendering(object sender, AfterRenderingEventArgs e)
        {
            _chart.AfterRendering -= _chart_AfterRendering; // To make the event run only once.
            _chart.ColorTheme = ColorTheme.LightGray;
        }
Hope this helps.
Best regards,
Lasse

Re: Problem in switching dynamically the colorTheme property

Posted: Wed Jan 13, 2021 12:46 pm
by cchrc
Dear Lasse,
thank you for your reply.
I've tried your approach, but still I'm having problems.
As my users can switch theme at runtime, I use a subscription to a theme observable, as shown in the screen to follow.

Apparently it works fine. Charts are rendered with the selected theme, and also switching it at runtime re-renders correctly both the chart and the rest of the app.
However, if I keep switching theme back and forth (for testing purpose), at a certain point I get an ArgumentNullException as shown in the attached screen:
2021-01-13 10_48_36-USWPrism (Debugging) - Microsoft Visual Studio (Administrator).png
2021-01-13 10_48_36-USWPrism (Debugging) - Microsoft Visual Studio (Administrator).png (22.24 KiB) Viewed 15053 times
My guess is that when the throw occurs, on that chart instance a render process is already running (most likely called from the library itself as my app is idle, apart from the theme change).
However I have to use Begin/End Update, otherwise the chart theme would not render correctly (like on my first post).

here the complete stacktrace https://pastebin.com/GFdmF86T
The project uses LightningChart 10.0.1

Re: Problem in switching dynamically the colorTheme property

Posted: Wed Jan 13, 2021 3:04 pm
by ArctionKestutis
Dear Claudio,

Your image and stack trace suggest that LightningChart instance at the moment of exception is Null. That is confusing part to understand, because ch could not be LightningChart and Null at the same time. If my assumptions are correct, then somewhere in the course of few lines ch was nulled.
Chart is NOT nulled during update, resize or something similar. It is set to null only if it is disposed. Do you dispose Charts explicitly, or you close the window where chart resides?
Somewhat relevant question, why Loaded event was called? Is it because you switch TabControl, or because Windows OS theme was changed or you indeed reinitialize application/window?
Notification about Windows OS theme change come through Message loop in MW. One of mysterious part of Message loop handling what event may have different priorities, and therefore, jump the queue. Maybe for such reason chart disposing come wrongly timed.
Please make sure what all chart manipulation happens in Main UI Thread. That could also be the reason of wrong event timing.

Hope this helps.
All the best.