Difficulty applying a color to elements of a LinearAxis3D

9 posts, 0 answers
  1. Joe
    Joe avatar
    65 posts
    Member since:
    Nov 2017

    Posted 14 Nov Link to this post

    I was surprised to find that assigning a foreground color to a LinearAxis3D does not automatically make the axis line, title or labels take on that color.  That was the behavior I would expect.  But it does not. 

    Ok, no problem, I figured I would get around it by defining a style resource for LinearAxis3D that individually binds the color to its logical children to the parent LinearAxis3D.    So I did that and it works just fine for the text title and labels.  But it does not work for the axis line

    Are a LinearAxis3D object's axis lines not logical children of that axis?  And if not, is there any way to generically find the LinearAxis3D object for (binding purposes) from within the style?

    To illustrate, here's a the Z axis on my chart.  (I've nested the style here for simplicity but in my app it needs to be a separate static resource for re-use.)

    <tk:RadCartesianChart3D.ZAxis>
        <tk:LinearAxis3D
            x:Name="ZAxis"
            LabelFormat="0.00"
            SmartLabelsMode="SmartStep"
            Minimum="{Binding ZAxisMin}"
            Maximum="{Binding ZAxisMax}"
            Foreground="Yellow"
            >
            <tk:LinearAxis3D.Style>
                <Style TargetType="{x:Type tk:LinearAxis3D}">
                    <Setter Property="LabelStyle">
                        <Setter.Value>
                            <Style TargetType="{x:Type TextBlock}">
                                <Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type tk:LinearAxis3D}}, Path=Foreground}"/>
                            </Style>
                        </Setter.Value>
                    </Setter>
                    <Setter Property="LineStyle">
                        <Setter.Value>
                            <Style TargetType="{x:Type Path}">
                                <Setter Property="Stroke" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type tk:LinearAxis3D}}, Path=Foreground}"/>
                                <Setter Property="StrokeThickness" Value="2"/>
                            </Style>
                        </Setter.Value>
                    </Setter>
                </Style>
            </tk:LinearAxis3D.Style>
        </tk:LinearAxis3D>
    </tk:RadCartesianChart3D.ZAxis>

    Since I assigned "Yellow" to the LinearAxis3D.Foreground, my label text blocks manage to find the parent LinearAxis3D and bind to this property to show the correct label color.  But the axis lines never show up.  That binding never finds the LinearAxis3D and so never gets any color. 

    If I change this setter to just use a hard coded color then it setter works fine.  But obviously, that's not going to work for me.

    Surprisingly, when I tried -- just as a test -- to bind by ElementName to "ZAxis", that didn't work either.  It's not an option for me if I want this Style to be a StaticResource but still I was surprised it did not work.

    So do I have any other option here?  Is the Path object used to draw the axis line a logical child of the LinearAxis3D?  And if not, is there any way to achieve what I want?  Or do I need to just  individually nest the line style for each axis?


     

  2. Martin Ivanov
    Admin
    Martin Ivanov avatar
    2245 posts

    Posted 18 Nov Link to this post

    Hello Joe,

    Thank you for the detailed description. I've used your code to assemble a test project, but I wasn't able to reproduce the issue. Can you please check the attachment and let me know if I am missing anything?

    Regards,
    Martin Ivanov
    Progress Telerik

    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
  3. Joe
    Joe avatar
    65 posts
    Member since:
    Nov 2017

    Posted 21 Nov in reply to Martin Ivanov Link to this post

    Hi Martin,

    I've spent the past 2 days trying to see why your app works and mine doesn't.

    When I run your example, it works perfectly.

    When I take my Axis styles and put them into your application, they work perfectly.  Both line styles and labels

    But when I run my application with the exact same styles, the LineStyle binding for stroke does not work. All of the other bindings work just fine.  But the axis line is NOT colorized as I would want.   The debugger output window gives me a runtime binding error.

    System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='Telerik.Windows.Controls.ChartView.LinearAxis3D', AncestorLevel='1''. BindingExpression:Path=Foreground; DataItem=null; target element is 'Path' (Name=''); target property is 'Stroke' (type 'Brush')

    Here is the exact XAML I am using:

    <tk:RadCartesianChart3D.ZAxis>
        <tk:LinearAxis3D
            x:Name="ZAxis"
            LabelFormat="0.00"
            SmartLabelsMode="SmartStep"
            Foreground="GreenYellow"
            >
            <tk:LinearAxis3D.LineStyle>
                <Style TargetType="{x:Type Path}">
                <Setter Property="Stroke" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type tk:LinearAxis3D}}, Path=Foreground}"/>
                <Setter Property="StrokeThickness" Value="4"/>
                </Style>
            </tk:LinearAxis3D.LineStyle>
            <tk:LinearAxis3D.LabelStyle>
                <Style TargetType="{x:Type Label}">
                    <Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type tk:LinearAxis3D}}, Path=Foreground}"/>
                </Style>
     
            </tk:LinearAxis3D.LabelStyle>
     
        </tk:LinearAxis3D>
    </tk:RadCartesianChart3D.ZAxis>

    I have attached a photo to show the result ("BadVersion.png")

    But if I hard-code the line color value to "GreenYellow" (same as axis foreground), then it works (see "GoodVersion.png")

     <Setter Property="Stroke" Value="GreenYellow"

     

    As an experiment, I tried several other bindings, none of which worked

    I tried binding (by ancestor type) to the RadCartesianChart3D itself.  It couldn't find that either

                                <Setter Property="Stroke" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type tk:RadCartesianChart3D}}, Path=Foreground}"/>

    I tried explicitly specifying (and increasing) the AncestorLevel value (1, 2, 3, and 4).  None of those helped.

    I tried using "ElementName" syntax

        <Setter Property="Stroke" Value="{Binding ElementName=ZAxis, Path=Foreground}"/>

    It changed nothing.  It can't even find the "ZAxis" by name.  I got this runtime binding error

    System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=ZAxis'. BindingExpression:Path=Foreground; DataItem=null; target element is 'Path' (Name=''); target property is 'Stroke' (type 'Brush')

    I have verified that both of our applications are using the exact same version of the 3 Telerik Assemblies you reference

    I do not apply any implicit styles to LinearAxis3D or RadCartesianChart anywhere in my code

    I've removed all my chart behaviors and even plugged in your same exact "canned" data.  Same problem.
    I've verified that my "tk" namespace is the proper one (although I don't call it "telerik"

     

    The fact that even an ElementName binding doesn't work completely baffles me.

    Any ideas where I could look next?

     

  4. Martin Ivanov
    Admin
    Martin Ivanov avatar
    2245 posts

    Posted 22 Nov Link to this post

    Hello Joe,

    Can you test with the latest version of Telerik UI for WPF, if you are not using it already? Also, you can open a new support ticket from your Telerik account and attach your project there. This way the support team can test it and investigate what happens.

    Regards,
    Martin Ivanov
    Progress Telerik

    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
  5. Joe
    Joe avatar
    65 posts
    Member since:
    Nov 2017

    Posted 22 Nov in reply to Joe Link to this post

    The more I think about this, the more I realize there has got to be something fundamentally wrong with my code somewhere else that I am just not seeing and I cannot reasonably expect you to figure out without seeing all of it.

    Since, I can work around this problem - whatever it is -- by explicitly specifying each axis' color, I think at this point, you should just mark this as "closed" so you will not waste any more of your time on what has got to be my bug

    Thank you, Martin
  6. Joe
    Joe avatar
    65 posts
    Member since:
    Nov 2017

    Posted 22 Nov in reply to Martin Ivanov Link to this post

    Hi Martin,

    Appreciate the reply.

    I am using the very latest version of UI for WPF  (2019.3). 

    Unfortunately, there is no way I could possibly post this project.  It is just one Module (a Prism Module) in a much larger application consisting of many modules which also relies on our custom C++/CLI wrapper on a C++ DLL and numerous third party libraries.

    Of all the difficulties I've encountered in WPF (and they have been legion), nothing baffles me like this one.
  7. Joe
    Joe avatar
    65 posts
    Member since:
    Nov 2017

    Posted 22 Nov in reply to Martin Ivanov Link to this post

    OK, Martin I finally found it what causes it.   

    If the RadCartesianChart is not visible when it is loaded (I had its visibility set to "Collapsed"), then the binding fails as I described.  If the chart is visible when it is loaded, the binding works just fine

    I even made this happen in your test application.  I bound the chart to a Visibility property (in code-behind) that defaulted to "Collapsed"  Then I added a button that - when you push it - sets that visibility to "Visible". 

    I push the button and the chart appears and the labels are colored properly but the lines are not.  Also the binding errors show up in the debug output window

  8. Joe
    Joe avatar
    65 posts
    Member since:
    Nov 2017

    Posted 22 Nov in reply to Joe Link to this post

    As a final note, I should say that now that I know what is causing it, I have managed to work around it by waiting until chart becomes visible for the first time before applying the LineStyle to the 3 axes.  

    So now, I still define the LineStyle in XAML but unlike all the rest of the other properties I do not apply it to the axes then, in XAML

    <Style x:Key="AxisLineStyle" TargetType="{x:Type Path}" >
        <Setter Property="StrokeThickness" Value="2"/>
        <Setter Property="Stroke" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type tk:LinearAxis3D}}, Path=Foreground}"/>
    </Style>


     Instead, I set a handler for the RadCartesianChart's IsVisibleChanged event.   When the chart becomes visible the very first time, I set them then, in code-behind to the named RadLinearAxis3D elements (named "XAxis", "YAxis" and "ZAxis").  As long as I do it like this, the bindings work just fine.


    private bool _hasBeenVisibleBefore = false;
    private void MyCartesianChart3D_OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        // First, sanity checking:
     
        if (!(e.NewValue is bool visible))
            return;
     
        if (!(sender is SurfaceView sv))
            return;
     
        // If we did not just become visible, nothing to do.
     
        if (!visible)
            return;
     
        //  If we became visible for the first time., apply line styles now
     
        if (_hasBeenVisibleBefore)
            return;
     
        _hasBeenVisibleBefore = true;
     
        if (!(TryFindResource("AxisLineStyle") is Style ls))
            return;
     
        XAxis.LineStyle = ls;
        YAxis.LineStyle = ls;
        ZAxis.LineStyle = ls;
    }
  9. Martin Ivanov
    Admin
    Martin Ivanov avatar
    2245 posts

    Posted 26 Nov Link to this post

    Hello Joe,

    I am glad to hear that you managed to resolve the issue on your side. And also thank you for sharing your solution here. I am sure that this will be useful for other people too.

    Regards,
    Martin Ivanov
    Progress Telerik

    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
Back to Top