CartesianChart3D must bind to reference type. Is there an alternative?

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

    Posted 28 Mar Link to this post

    I use RadCartesianChart3d to display a surface map with a lot of points.  Hundreds of thousands.  And it displays well but as you might imagine, it takes a long time for me to generate all of those points.   So I had an idea (what turned out to be a bad idea) that I would make things more efficient by changing my pixel type -- my class to which the chart binds --  from a class into a struct.  

    Obviously, that failed.  The RadCartesianChart3D threw an exception with the text "Dynamic getter is not supported for value types.".  

    And I get this.  Makes sense given how the chart works.  But it leads me to wonder:  Is there an alternative approach in Telerik world that would give me the efficiency I'm looking for?

    It just seems that if there were some simpler version of the chart that could work with some a stock struct type with X,Y,Z double values, it would have to be a lot faster.  Not forcing the GC to track 200,000 garbage-collectible references seems like it would have to be a boost, no?

    So is there such an alternative?  And if not, is this something that might even be on Telerik's radar for the future?

    Or is my thinking wrong here and would such a chart *not* give m the performance improvement I expect (and if so, why not?)

    Thanks,
  2. Martin Ivanov
    Admin
    Martin Ivanov avatar
    2237 posts

    Posted 02 Apr Link to this post

    Hello Joe,

    The exception is thrown because, when set in XAM, the X/Z/YValueBinding properties of the chart work with the PropertyNameDataPointBinding class. The class uses reflections internally in order to get the property of the underlying object, by the provided name. 

    To achieve your requirement, and use the 'struct' model, you can use the GenericaDataPointBinding<TElement, TResut> class in code. You can see this demonstrated in the Data Binding article of the  RadChartView3D documentation.

    However, I am not sure if this approach will bring a better performance. If it doesn't can you share some runnable code showing your chart set up and data generation?

    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 02 Apr in reply to Martin Ivanov Link to this post

    Thank you.  My experimentation showed that your guess was correct.  It did not help performance by any measurable amount.

    However One oddity I noticed in trying to evaluate performance was in the binding of the  SurfaceSeries3D::ItemsSource property.

    My viewmodel exposes this property as IEnumerable<Pixel3d> (where "Pixel3d" is my struct holding the data).  I implement this property with a manual enumerator function.   However Telerik seems to require me to supply an actual List<Pixel3d> even though the property type of ItemsSource is IEnumerable

    public IEnumerable<Pixel3d> GetPoints()
    {
        for (int x = 0; x < _maxX; x++)
        {
            for (int y = 0; y < _maxY; y++ )
                yield return new Pixel3d(x, y, GetData(x, y));
     
        }
    }
     
    public IEnumerable<Pixel3d> Points => GetPoints().ToList(); // MUST HAVE ToList() here


    If I remove the call to "ToList()", then the chart will never show any points.

    Why am I required to convert the IEnumerable to a List?  Shouldn't the chart be enumerating the points itself?  If it requires an actual list, why is the property "ItemsSource" of type IEnumerable?

    Or am I doing something else wrong?

  4. Martin Ivanov
    Admin
    Martin Ivanov avatar
    2237 posts

    Posted 04 Apr Link to this post

    Hello Joe,

    I've tested this on my side, but I couldn't reproduce the issue. The chart should work with any enumerable provided. It is not restricted to Lists only. Can you please check the attached project and let me know if I am missing something? You can also noticed that the project plots 200,000 data points. On my side the performance is pretty smooth. 

    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 04 Apr in reply to Martin Ivanov Link to this post

    Hi Martin,

    I took your example and you are right.  No problems.  So I started trying to gradually make your example like mine and I found the problem.  It's certainly not Telerik (no surprise) but as you took the time for me, I feel I at least owe you the explanation.  It is an incredibly sneaky WPF problem that yields no warnings, not even binding warning messages in the output window.

    In short, my binding used a converter for the pixels.  My app has to show them in either metric or imperial so my converter takes a list of pixels, converts them appropriately and returns them.  Here is a completely gutted, skeleton, do-nothing implementation of what my converter looks like:

     
    namespace WpfApp40
    {
        [ValueConversion(typeof(List<Pixel3d>), typeof(List<Pixel3d>))]
        [MarkupExtensionReturnType(typeof(PixelUnitConverter))]
        public class PixelUnitConverter
            : IValueConverter
        {
            public object Convert    (object v, Type t, object p, CultureInfo c) => v;
            public object ConvertBack(object v, Type t, object p, CultureInfo c) => Binding.DoNothing;
        }
    }

    Note the [ValueConversion] markup extension up top.  It states that the converter takes and returns List<Pixel3d>.  Not an IEnumerable<Pixel3d>.  (I wrote this a long time ago when I was using List for everything.)

    And of course, my binding was like this:

    <telerik:SurfaceSeries3D ItemsSource="{Binding Points, Converter={StaticResource PixelConverter}}" x:Name="series">

    If you change your example to do that (as I did) and it will no longer work.  Not Telerik's fault of course.  Mine.

    Of course it all works fine when the item you supply actually is a list.   Even if the item you supply is a list but you return it as IEnumerable<Pixel3d>, it still works.

    But when the Property you are binding to actually uses yield return what is returned is no longer a list at all, it is an enumerator only that traverses a list.  So it stops working.  Apparently WPF examines enumerator and realizes it doesn't jibe with the [ValueConversion] markup tag and just makes it all fail silently.  It didn't even give me a WPF binding warning.

    All I had to do whas change the ValueConversion tag to take and return IEnumerable<Pixel3d> and everything started working again.

    Anyway I am all set.  Thank you for your time.


  6. Martin Ivanov
    Admin
    Martin Ivanov avatar
    2237 posts

    Posted 05 Apr Link to this post

    Hello Joe,

    Thank you for the explanation. I've learned something new today.

    Wish you luck with your project.

    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