LabelTemplate Updates not resizing

6 posts, 0 answers
  1. Louis
    Louis avatar
    83 posts
    Member since:
    Aug 2013

    Posted 16 Jun 2014 Link to this post

    I have a problem where using a multi-binding to format axis labels correctly updates the labels, but does not resize correctly when the size of the labels change.

    You can see the problem with this small example:
    <Window x:Class="LabelTemplate_MultiBinding.MainWindow"
                    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
                    xmlns:local="clr-namespace:LabelTemplate_MultiBinding"
                    Title="MainWindow" Height="768" Width="1024">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <telerik:RadCartesianChart x:Name="PropertyChart">
                <telerik:RadCartesianChart.Resources>
                    <local:ChartNumberFormatter x:Key="NumberFormatter"/>
                    <DataTemplate x:Key="FormattedNumericAxisTemplate">
                        <TextBlock>
                            <TextBlock.Text>
                                <MultiBinding Converter="{StaticResource NumberFormatter}">
                                    <Binding />
                                    <Binding ElementName="PropertyChart"
                                             Path="DataContext.NumericFormat"/>
                                </MultiBinding>
                            </TextBlock.Text>
                        </TextBlock>
                    </DataTemplate>
                </telerik:RadCartesianChart.Resources>
                <telerik:RadCartesianChart.HorizontalAxis>
                    <telerik:DateTimeCategoricalAxis/>
                </telerik:RadCartesianChart.HorizontalAxis>
                <telerik:RadCartesianChart.VerticalAxis>
                    <telerik:LinearAxis LabelTemplate="{StaticResource FormattedNumericAxisTemplate}" />
                </telerik:RadCartesianChart.VerticalAxis>
                <telerik:RadCartesianChart.Series>
                    <telerik:LineSeries
                           CategoryBinding="Date"
                           ValueBinding="Value"
                           ItemsSource="{Binding Path=Series1}">
                    </telerik:LineSeries>
                </telerik:RadCartesianChart.Series>
            </telerik:RadCartesianChart>
            <StackPanel Grid.Row="1" Orientation="Horizontal">
                <Label>Y Axis Format:</Label>
                <TextBox Text="{Binding NumericFormat}" Width="200" />
            </StackPanel>
        </Grid>
    </Window>

    Code Behind:
    public class MyPoint
    {
        public DateTime Date { get; set; }
        public Double Value { get; set; }
    }
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public List<MyPoint> Series1 { get; private set; }
     
        private string _NumericFormat;
        public string NumericFormat
        {
            get { return _NumericFormat; }
            set
            {
                if (_NumericFormat != value)
                {
                    _NumericFormat = value;
                    OnPropertyChanged("NumericFormat");
                }
            }
        }
     
        public MainWindow()
        {
            Series1 = new List<MyPoint>();
            for (int i = 0; i < 5; i++)
            {
                DateTime date = DateTime.Today.AddDays(i);
                Series1.Add(new MyPoint() { Date = date, Value = i * 1000 });
            }
            InitializeComponent();
            DataContext = this;
        }
     
        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }
    public class ChartNumberFormatter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            double number = System.Convert.ToDouble(values[0]);
            string format = values[1] as string;
            if (string.IsNullOrEmpty(format))
            {
                return number.ToString();
            }
            return number.ToString(format);
        }
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    If you run this example, and in the Y-axis format box enter "e" then press tab to activate, you can see the numbers correctly change to scientific notation, but now they overlap the chart!

    Can you recommend something to trigger the axis to be redrawn correctly?

    Thanks,
    Louis
  2. Martin
    Admin
    Martin avatar
    1099 posts

    Posted 19 Jun 2014 Link to this post

    Hello Louis,

    Thank you for the provided code.

    This behavior is a known limitation of the chart component. It is caused by the runtime change of the labels. When the chart start to draw itself it will go through the LabelTemplate of the axis and it will calculate how much space will be necessary for the labels. This will happen only once when the chart is loaded, which means that if you alter the text inside the labels they will use the space that was allocated earlier and they will overlap the plot area (like in your case).

    I can suggest you another approach that I think can me more appropriate in your scenario. Basically you can use the LabelFormat property of the axis. You can remove the IMultiValueConverter in the LabelTemplate and just bind the Text property like in the following code snippet:

    <TextBlock HorizontalAlignment="Right" Text="{Binding}" />

    Then you can bind the NumericFormat property of your view model to the LabelFormat property of the vertical axis. This property determines the format for the text in the labels and also will ensure that the chart will recalculate the space for the labels.

    <telerik:LinearAxis LabelFormat="{Binding NumericFormat}" LabelTemplate="{StaticResource FormattedNumericAxisTemplate}" />

    In addition I prepared a sample project that demonstrates this approach. Please give it a try and let me know if it helps.

    Regards,
    Martin
    Telerik
     
    Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
     
  3. UI for WPF is Visual Studio 2017 Ready
  4. Louis
    Louis avatar
    83 posts
    Member since:
    Aug 2013

    Posted 19 Jun 2014 in reply to Martin Link to this post

    Thank you Martin, but I'm afraid my example was simplified just to show the issue. I can't just apply the format via LabelFormat as the logic behind the Converter is more complex. It does things like converts large numbers from 5,000,000 to 5.00 M, etc., and to be consistent, it does so based on the maximum value currently shown on the chart. So it's not just a change in the LabelFormat that needs to cause a re-layout.

    In further testing, I've encountered more issues with this as well. As I zoom in, the new labels drawn are drawn at different locations than the original. See ZoomingIn.PNG. As I zoom out, only the new labels needed are drawn, which leads to an inconsistent format. See ZoomingOut.PNG. Is there a way to force the axis to redraw ALL the labels when zoom changes instead of just adding the new?

    Thanks again,
    Louis
  5. Martin
    Admin
    Martin avatar
    1099 posts

    Posted 24 Jun 2014 Link to this post

    Hello Louis,

    The chart uses size-caching for the axis visuals (performance optimization) and does not observe for changes in its templates. In order to resize the labels at runtime you will need to reset the LabelTemplate property (set new data template).

    However, we just hit a bug in the chart that concerns this approach. We logged it in our feedback portal where you can track its status. We also updated your Telerik points as a small compensation. Unfortunately, you won't be able to use the approach until the Q2 2014 SP1 release when a fix is planned to be introduced.

    Please excuse us for any inconvenienced caused.

    Regards,
    Martin
    Telerik
     
    Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
     
  6. Louis
    Louis avatar
    83 posts
    Member since:
    Aug 2013

    Posted 24 Jun 2014 in reply to Martin Link to this post

    Hi Martin,

    Thanks for the reply. I understand about changing templates. However, the screenshots attached showing the newly drawn labels overlapping the axis aren't even from changing templates, but just adjusting the zoom with an existing template. Since refreshing the template binding isn't currently an option, is there a way to force a redraw of the axis? I tried just replacing the axis, and it works when resizing the window although the refresh is quite visible, but doing so while zoom is being adjusted breaks the zoom process.

    I'll try to find time to recreate the overlapping zoom issue in a small example in case that would help.

    Thanks again for your help,
    Louis
  7. Martin
    Admin
    Martin avatar
    1099 posts

    Posted 26 Jun 2014 Link to this post

    Hi Louis,

    I succeed in reproducing the zooming issue. This seems to be caused by the caching mechanism. In general, at some point when you zoom, the axis will create extra labels for the zoomed range and it will allocate enough space to render them correctly. The original labels that were created (and cached) before the zooming will be positioned wrong and they will overlap the plot area. This will cause a dislocation of the labels.

    However, if you are not changing the template in any way and this issue appears, can you please prepare a project with the latest version of our assemblies and if the issue still occurs can you send me over the project so that we can test it and decide if this is a bug? Thank you in advance for the effort.

    As for the axis' refreshing, currently this is not possible. The only workaround for the overlapping issue that we are aware of, is to set fixed width for your LabelTemplate. This will ensure that the labels will have enough space.
    <DataTemplate>
        <TextBlock Width="300" TextWrapping="Wrap" HorizontalAlignment="Right" Text="...." >
            .....
        </TextBlock>
    </DataTemplate>

    In addition, the fix for the bug with the runtime changing of the LabelTemplate will be available in our next latest internal build which will be live next week. Please give it a try when the LIB is out and let me know if it helps.

    Regards,
    Martin
    Telerik
     
    Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
     
Back to Top
UI for WPF is Visual Studio 2017 Ready