/// <summary>
 /// Transforms for single component.
 /// </summary>
 /// <param name="ls">Layout state.</param>
 /// <param name="rrea">Refresh request.</param>
 protected void ComponentTransforms(LayoutState ls, RefreshRequestEventArgs rrea)
 {
     if (rrea.Component is IRequireTransforms irt)
     {
         var rect = ls.Layout.For(rrea.Component);
         _trace.Verbose($"component-transforms {rrea.Component} {rrea.Axis} {rect}");
         var ctx = new DefaultRenderContext(Surface, Components, ls.LayoutDimensions, rect, ls.Layout.RemainingRect, DataContext)
         {
             Type = RenderType.TransformsOnly
         };
         irt.Transforms(ctx);
     }
 }
 /// <summary>
 /// Component is requesting a refresh.
 /// Mark the chart's data source dirty and render chart.
 /// TODO get the DS to just refresh this CC.
 /// This method is invoke-safe; it MAY be called from a different thread.
 /// </summary>
 /// <param name="cc">Component requesting refresh.</param>
 /// <param name="rrea">The request parameter.</param>
 private async void ChartComponent_RefreshRequest(ChartComponent cc, RefreshRequestEventArgs rrea)
 {
     _trace.Verbose($"refresh-request-cc '{cc.Name}' {cc} r:{rrea.Request} a:{rrea.Axis}");
     await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => {
         if (Surface == null)
         {
             return;
         }
         try {
             if (cc is IProvideDataSourceRenderer ipdsr)
             {
                 var ds = DataSources.SingleOrDefault(dds => dds.Name == ipdsr.Renderer.DataSourceName);
                 if (ds != null)
                 {
                     ds.IsDirty = true;
                 }
                 RenderComponents(CurrentLayout);
             }
             else if (cc is IDataSourceRenderer idsr)
             {
                 var ds = DataSources.SingleOrDefault(dds => dds.Name == idsr.DataSourceName);
                 if (ds != null)
                 {
                     ds.IsDirty = true;
                 }
                 RenderComponents(CurrentLayout);
             }
             else
             {
                 // dispatch other kinds of refresh requests
                 if (rrea.Request == RefreshRequestType.LayoutDirty && rrea.Component is IRequireLayout)
                 {
                     ComponentRender(CurrentLayout, rrea);
                 }
                 else if (rrea.Request == RefreshRequestType.ValueDirty && rrea.Component is IRequireRender)
                 {
                     ComponentRender(CurrentLayout, rrea);
                 }
                 else if (rrea.Request == RefreshRequestType.TransformsDirty && cc is IRequireTransforms)
                 {
                     ComponentTransforms(CurrentLayout, rrea);
                 }
             }
         }
         catch (Exception ex) {
             _trace.Verbose($"{Name} ChartComponent_RefreshRequest.unhandled: {ex}");
         }
     });
 }
 /// <summary>
 /// Render for single component.
 /// </summary>
 /// <param name="ls">Layout state.</param>
 /// <param name="rrea">Refresh request.</param>
 protected void ComponentRender(LayoutState ls, RefreshRequestEventArgs rrea)
 {
     if (rrea.Component is IRequireRender irr)
     {
         var rect = ls.Layout.For(rrea.Component);
         _trace.Verbose($"component-render {rrea.Component} {rrea.Axis} {rect}");
         if (rrea.Axis != AxisUpdateState.None)
         {
             // put axis limits into correct state for IRequireRender components
             Phase_ResetAxes();
             //Phase_AxisLimits((cc2) => cc2 is DataSeries && (cc2 is IProvideValueExtents));
             Phase_AxisLimits(ValueExtents_DataSeries.Items);
         }
         var ctx = new DefaultRenderContext(Surface, Components, ls.LayoutDimensions, rect, ls.Layout.RemainingRect, DataContext)
         {
             Type = RenderType.Component
         };
         irr.Render(ctx);
         if (rrea.Axis != AxisUpdateState.None)
         {
             // axes MUST be re-evaluated because this thing changed.
             //Phase_AxisLimits((cc2) => !(cc2 is DataSeries) && (cc2 is IProvideValueExtents));
             Phase_AxisLimits(ValueExtents_NotDataSeries.Items);
             Phase_AxesFinalized(ls);
             Phase_RenderPostAxesFinalized(ls);
             Phase_RenderAxes(ls);
             Phase_Transforms(ls);
         }
         else
         {
             if (rrea.Component is IRequireTransforms irt)
             {
                 irt.Transforms(ctx);
             }
         }
     }
 }