Knowledgebase
Axis.VisibleRange - a Note about Dependency Property Precedence
Posted by Andrew BT on 05 February 2019 04:00 PM

A Note about DependencyProperty Precedence

AxisBase.VisibleRange is a DependencyProperty, it is therefore subject to Dependency Property Precedence in WPF. See the MSDN Documentation for more details.

Dependency Property Setting Precedence List

The following is the definitive order that the property system uses when assigning the run-time values of dependency properties. Highest precedence is listed first. This list expands on some of the generalizations made in Dependency Properties Overview.

  1. Active animations, or animations with a Hold behavior. In order to have any practical effect, an animation of a property must be able to have precedence over the base (unanimated) value, even if that value was set locally. For details, see Animations and Base Value later in this topic. In order to be animated, the dependency property must be a property type that the existing animation classes will support.

  2. Local value. A local value might be set through the convenience of the CLR wrapper property, which also equates to setting as an attribute or property element in XAML, or by a call to the SetValue method using a property of a specific instance. If you set a local value by using a binding or a static resource, these each act in the precedence as if a local value was set.

  3. Templated properties. An element has these if it was created as part of a template (a ControlTemplate or DataTemplate).

  4. Style setters. Values from a Setter within styles from page or application resources.

  5. Default value. Any given dependency property may have a default value. For details, see Default Values later in this topic.

Internally, SciChart sets the AxisBase.VisibleRange property using the Local Value precedence in some places. We must do this as ChartModifiers, and AutoRange need to update the AxisBase.VisibleRange

This means that in some cases, style setters and templated properties setting Axis.VisibleRange will not appear to work. For this reason we recommend that any bindings to VisibleRange are a TwoWay binding to a ViewModel property:

e.g.

<!-- Assumes a ViewModel property called AxisVisibleRange -->
<!-- TwoWay Binding is required to avoid DependencyProperty Precedence issues -->
<s:NumericAxis VisibleRange="{Binding AxisVisibleRange, Mode=TwoWay}"/>

Triggers and DependencyProperty Precedence

In some cases, Triggers will also not work on the AxisBase.VisibleRange, e.g. the following code will fail:

<Style x:Key="YAxisStyle" TargetType="s:NumericAxis">
	<Setter Property="VisibleRange" Value="0, 5"></Setter>
	<Setter Property="AutoRange" Value="Never"></Setter>
	<Style.Triggers>
		<Trigger Property="Tag" Value="1">
			<!-- Removing AutoRange=Always setter and uncommenting this next VisibleRange setter shows how the timer changes states  -->
			<!--<Setter Property="VisibleRange" Value="0, 7"></Setter>-->
			<Setter Property="AutoRange" Value="Always"></Setter>
		</Trigger>
		<Trigger Property="Tag" Value="2">
			<Setter Property="AutoRange" Value="Never"></Setter>
			<Setter Property="VisibleRange" Value="0, 10"></Setter>
		</Trigger>
	</Style.Triggers>
</Style>

... 

<s:NumericAxis Style="{StaticResource YAxisStyle}"/>

In the above code, which was submitted to us by a customer of SciChart, the AxisBase.AutoRange property is used to switch between AutoRange.Always and AutoRange.Never and a predefined range. 

This code does not work, as once AutoRange.Always is set on the Axis, and SciChart then sets the AxisBase.VisibleRange property via local value precedence, and the trigger (with lower precedence) will not work. 

We suggest instead one of the following solutions instead:

Binding BOTH to AutoRange and VisibleRange in a ViewModel

The following method uses a TwoWay binding for the VisibleRange property, and will allow updating of both AutoRange and VisibleRange from the ViewModel.

<Style x:Key="YAxisStyle" TargetType="s:NumericAxis">
	<Setter Property="VisibleRange" Value="{Binding ViewmodelVisibleRange, Mode=TwoWay}"></Setter>
	<Setter Property="AutoRange" Value="{Binding ViewModelAutoRange, Mode=TwoWay}"></Setter>	
</Style>

...
<s:NumericAxis Style="{StaticResource YAxisStyle}"/>

...
// then in ViewModel 
public DoubleRange VisibleRange 
{
   get { return _range; }
   set 
   {
      _range = value;
	  OnPropertyChanged("VisibleRange");
   }
}

public AutoRange AutoRange 
{
   get { return _autoRange; }
   set 
   {
      _autoRange = value;
	  OnPropertyChanged("AutoRange");
   }
}

 

Using an Animation to set values in a Trigger

Another idea is to use ObjectAnimationUsingKeyFrames with 0 duration to set values in a trigger. Animations have the highest precedence for a DependencyProperty and always trump local values.

 

ItemTemplates and DependencyProperty Precedence

In some cases VisibleRange bindings inside a style, inside an ItemTemplate will have a lower DependencyProperty Precedence than the local value set by SciChart AutoRange and modifiers. The following code is taken from our Create Multi Pane Stock Charts demo:

<!-- Databinds a SciChartGroup to a list of ChartPaneViewModels -->
<!-- Child chart panes are generated using the ItemTemplate below -->
<s:SciChartGroup Grid.Row="1" 
					ItemsSource="{Binding ChartPaneViewModels}"
					s:ThemeManager.Theme="{Binding ElementName=ThemeCombo, Path=SelectedItem}"
					ItemContainerStyle="{StaticResource ChartPaneStyle}">
	<s:SciChartGroup.ItemTemplate>
		<DataTemplate>
			<Grid>
				<!--  Axis Properties, like s:StockChartXAxis.VisibleRange are databound to CreateMultiPaneStockChartsViewModel.XVisibleRange -->
				<s:SciStockChart x:Name="PART_ChartPaneView" 
							...>

					<!-- Override any properties of the built-in CategoryDateTimeAxis -->
					<s:SciStockChart.XAxisStyle>
						<Style TargetType="s:CategoryDateTimeAxis">
							...
							<Setter Property="VisibleRange" Value="{Binding ParentViewModel.XVisibleRange, Mode=TwoWay}"/>
							...
						</Style>
					</s:SciStockChart.XAxisStyle>

					... 

				</s:SciStockChart>
				
			...
			</Grid>
		<DataTemplate>
	</s:SciChartGroup.ItemTemplate>
</s:SciChartGroup>

 

The above code works because of the TwoWay binding between VisibleRange and a common ViewModel property, however without the TwoWay binding it would not work, because bindings inside a template a at a lower precedence than local values set. 

If you have any problems with VisibleRange and DependencyProperty Precedence

Contact us! Give us your code sample and what you expect to happen, and we will modify this article and post a solution for you. 

 

 

 

 

(0 vote(s))
Helpful
Not helpful

CONTACT US

Not sure where to start? Contact us, we are happy to help!


CONTACT US

SciChart Ltd, 16 Beaufort Court, Admirals Way, Docklands, London, E14 9XL. Email: Legal Company Number: 07430048, VAT Number: 101957725