void IRequireDataSourceUpdates.Add(IChartRenderContext icrc, int startAt, IList items) { if (CategoryAxis == null || ValueAxis == null) { return; } if (BindPaths == null || !BindPaths.IsValid) { return; } var recycler = new Recycler <Path, ItemState <Path> >(CreatePath); var reproc = IncrementalAdd <ItemState <Path> >(startAt, items, ItemState, (ix, item) => { var valuey = BindPaths.ValueFor(item); // short-circuit if it's NaN if (double.IsNaN(valuey)) { return(null); } var valuex = BindPaths.CategoryFor(item, ix); // add requested item var istate = ElementPipeline(ix, valuex, valuey, item, recycler, BindPaths); return(istate); }, (rpc, istate) => { istate.Shift(rpc, BindPaths, CategoryAxis, null); // NO geometry update; done in later stages of render pipeline }); ReconfigureLimits(); // finish up Layer.Add(recycler.Created); Dirty = false; RaiseItemsUpdated(ItemUpdates, icrc, NotifyCollectionChangedAction.Add, startAt, reproc); }
void IRequireDataSourceUpdates.Add(IChartRenderContext icrc, int startAt, IList items) { if (CategoryAxis == null || ValueAxis == null) { return; } if (BindPaths == null || !BindPaths.IsValid) { return; } var recycler = new Recycler <Path, SeriesItemState>(new List <Path>(), CreatePath); var reproc = IncrementalAdd <SeriesItemState>(startAt, items, ItemState, (ix, item) => { var valuex = BindPaths.CategoryFor(item, ix); // add requested item var istate = ElementPipeline(ix, valuex, item, recycler, BindPaths); return(istate); }, (rpc, istate) => { istate.Shift(rpc, BindPaths, CategoryAxis, UpdateGeometry); }); ReconfigureLimits(); // finish up Layer.Add(recycler.Created); Dirty = false; RaiseItemsUpdated(ItemUpdates, icrc, NotifyCollectionChangedAction.Add, startAt, reproc); }
ItemState CreateSubtick(IChartRenderContext icrc, Recycler <Path, ItemState> recycler, SubtickState tick) { if (tick.Value <= ValueAxis.Minimum || tick.Value >= ValueAxis.Maximum) { return(null); } var state = new ItemState() { Tick = tick }; var current = recycler.Next(state); if (!current.Item1) { // restore binding if (MinorGridPathStyle != null) { BindTo(this, nameof(MinorGridPathStyle), current.Item2, FrameworkElement.StyleProperty); TransferFromStyle(current.Item2, MinorGridPathStyle); } else if (PathStyle != null) { BindTo(this, nameof(PathStyle), current.Item2, FrameworkElement.StyleProperty); TransferFromStyle(current.Item2, PathStyle); } } state.Element = current.Item2; ApplyBinding(this, nameof(Visibility), state.Element, UIElement.VisibilityProperty); state.SetLocation(icrc.Area.Left, tick.Value); return(state); }
void IRequireDataSourceUpdates.Add(IChartRenderContext icrc, int startAt, IList items) { if (CategoryAxis == null || ValueAxis == null) { return; } if (BindPaths == null || !BindPaths.IsValid) { return; } var recycler = new Recycler <Path, ItemState <Path> >(new List <Path>(), CreatePath); var reproc = IncrementalAdd <ItemState <Path> >(startAt, items, ItemState, (ix, item) => { var valueO = BindPaths.OpenFor(item); var valueH = BindPaths.HighFor(item); var valueL = BindPaths.LowFor(item); var valueC = BindPaths.CloseFor(item); // short-circuit if it's NaN if (double.IsNaN(valueO) || double.IsNaN(valueH) || double.IsNaN(valueL) || double.IsNaN(valueC)) { return(null); } var valuex = BindPaths.CategoryFor(item, ix); // add requested item var istate = ElementPipeline(ix, valuex, valueO, valueH, valueL, valueC, item, recycler, BindPaths.bvl); return(istate); }, (rpc, istate) => { istate.Shift(rpc, BindPaths, CategoryAxis, UpdateGeometry); }); ReconfigureLimits(); // finish up Layer.Add(recycler.Created); Dirty = false; RaiseItemsUpdated(ItemUpdates, icrc, NotifyCollectionChangedAction.Add, startAt, reproc); }
/// <summary> /// Ctor. /// </summary> /// <param name="state">Starting state; SHOULD be empty.</param> /// <param name="rc">The recycler.</param> /// <param name="evs">Evaluators.</param> internal RenderState_ValueAndLabel(List <SIS> state, Recycler <EL, SIS> rc, Evaluators evs) : base(state, rc) { #pragma warning disable IDE0016 // Use 'throw' expression if (evs == null) { throw new ArgumentNullException(nameof(evs)); } if (evs.by == null) { throw new ArgumentNullException(nameof(evs.by)); } #pragma warning restore IDE0016 // Use 'throw' expression this.evs = evs; }
object IDataSourceRenderer.Preamble(IChartRenderContext icrc) { if (CategoryAxis1 == null || CategoryAxis2 == null) { return(null); } if (BindPaths == null || !BindPaths.IsValid) { return(null); } ResetLimits(); var paths = ItemState.Select(ms => ms.Element).Where(el => el != null); var recycler = new Recycler <Path, ItemState <Path> >(paths, CreatePath); return(new RenderState_Heatmap <ItemState <Path>, Path>(new List <ItemState <Path> >(), recycler, BindPaths)); }
object IDataSourceRenderer.Preamble(IChartRenderContext icrc) { if (ValueAxis == null || CategoryAxis == null) { return(null); } if (BindPaths == null || !BindPaths.IsValid) { return(null); } ResetLimits(); var paths = ItemState.Select(ms => ms.Elements).SelectMany(el => el).Select(el => el.Item2); var recycler = new Recycler <Path, SeriesItemState>(paths, CreatePath); return(new State(new List <SeriesItemState>(), recycler, BindPaths)); }
object IDataSourceRenderer.Preamble(IChartRenderContext icrc) { if (ValueAxis == null || CategoryAxis == null) { return(null); } if (BindPaths == null || !BindPaths.IsValid) { return(null); } ResetLimits(); var paths = ItemState.Select(ms => ms.Element); var recycler = new Recycler <Image, ItemState <Image> >(paths, CreateElement); return(new RenderState_ValueAndLabel <ItemState <Image>, Image>(new List <ItemState <Image> >(), recycler, BindPaths)); }
object IDataSourceRenderer.Preamble(IChartRenderContext icrc) { if (String.IsNullOrEmpty(ValuePath)) { return(null); } var by = new BindingEvaluator(ValuePath); var paths = ItemState.Select(ms => ms.Element); var recycler = new Recycler <Path, ItemState <Path> >(paths, CreatePath); Generator.Reset(); return(new State(new List <ItemState <Path> >(), recycler, null, !String.IsNullOrEmpty(ValueLabelPath) ? new BindingEvaluator(ValueLabelPath) : null, by, !String.IsNullOrEmpty(ValueLabelPath) ? new BindingEvaluator(ValueLabelPath) : null )); }
/// <summary> /// Create the next series state. /// </summary> /// <param name="index"></param> /// <param name="valuex"></param> /// <param name="item"></param> /// <param name="recycler"></param> /// <param name="evs"></param> /// <returns>New instance or NULL.</returns> SeriesItemState ElementPipeline(int index, double valuex, object item, Recycler <Path, SeriesItemState> recycler, Evaluators evs) { var leftx = CategoryAxis.For(valuex); var barx = BarOffset; var rightx = barx + BarWidth; var sis = evs.byl == null ? new SeriesItemState(index, leftx, BarOffset) : new SeriesItemState_Custom(index, leftx, BarOffset, evs.byl.For(item)); for (int ix = 0; ix < evs.bys.Length; ix++) { var valuey = CoerceValue(item, evs.bys[ix]); if (double.IsNaN(valuey)) { continue; } var colbase = valuey >= 0 ? sis.Max : sis.Min; var colend = colbase + valuey; var y1 = ValueAxis.For(colend); var y2 = ValueAxis.For(colbase); var topy = Math.Max(y1, y2); var bottomy = Math.Min(y1, y2); sis.UpdateLimits(y1); _trace.Verbose($"{Name}[{index},{ix}] {valuey} ({barx},{topy}) ({rightx},{bottomy}) sis ({sis.Min},{sis.Max})"); var path = recycler.Next(null); if (path == null) { return(null); } var shim = new GeometryWithOffsetShim <RectangleGeometry>() { PathData = new RectangleGeometry() { Rect = new Rect(new Point(barx, topy), new Point(rightx, bottomy)) } }; path.Item2.DataContext = shim; BindTo(ColumnStack[ix], "PathStyle", path.Item2, FrameworkElement.StyleProperty); // bind offset BindTo(shim, nameof(shim.Offset), path.Item2, Canvas.LeftProperty); UpdateLimits(valuex, sis.Min, sis.Max); sis.Elements.Add(new Tuple <double, Path>(valuey, path.Item2)); } return(sis); }
void IRequireDataSourceUpdates.Add(IChartRenderContext icrc, int startAt, IList items) { // mimic the DSRP sequence var widx = LabelStyle?.Find(FrameworkElement.WidthProperty); var bl = new BindingEvaluator(LabelPath); // keep a separate list; easier at the end var reproc = new List <ItemState>(); for (int ix = 0; ix < items.Count; ix++) { // add requested item var label = bl.For(items[ix]); var istate = makeit(startAt + ix, label, widx == null); AxisLabels.Insert(startAt + ix, istate); reproc.Add(istate); } // re-sequence remaining items for (int ix = startAt + reproc.Count; ix < AxisLabels.Count; ix++) { AxisLabels[ix].index = ix; AxisLabels[ix].value = ix; } // render new items // run the element pipeline on the added items var recycler = new Recycler <FrameworkElement, ItemState>(CreateElement); var labels = new List <ICategoryLabelState>(AxisLabels); var sc = new SelectorContext(this, icrc.SeriesArea, labels); foreach (var istate in reproc) { ElementPipeline(sc, istate, recycler); } // configure axis limits; just based on count-of-elements UpdateLimits(0); UpdateLimits(AxisLabels.Count); // finish up Layer.Add(recycler.Created); RebuildAxisGeometry(); Dirty = false; }
object IDataSourceRenderer.Preamble(IChartRenderContext icrc) { if (Theme?.TextBlockTemplate == null) { // already reported an error so this should be no surprise return(null); } if (String.IsNullOrEmpty(LabelPath)) { return(null); } var bl = new BindingEvaluator(LabelPath); if (bl == null) { return(null); } var recycler = new Recycler <FrameworkElement, ItemState>(AxisLabels.Where(tl => tl.element != null).Select(tl => tl.element), CreateElement); ResetLimits(); var widx = LabelStyle?.Find(FrameworkElement.WidthProperty); return(new State(new List <ItemState>(), recycler, icrc, widx == null, bl)); }
internal State(List <ItemState> state, Recycler <FrameworkElement, ItemState> rc, IChartRenderContext icrc, bool xau, BindingEvaluator bl) : base(state, rc) { this.icrc = icrc; usexau = xau; this.bl = bl; }
/// <summary> /// Main flow of the render pipeline. /// </summary> /// <param name="sc"></param> /// <param name="ist"></param> /// <param name="recycler"></param> void ElementPipeline(SelectorContext sc, ItemState ist, Recycler <FrameworkElement, ItemState> recycler) { sc.SetTick(ist.index); var createit = true; if (LabelSelector != null) { var ox = LabelSelector.Convert(sc, typeof(bool), null, System.Globalization.CultureInfo.CurrentUICulture.Name); if (ox is bool bx) { createit = bx; } else { createit = ox != null; } } if (!createit) { return; } var current = recycler.Next(ist); if (current == null) { return; } if (!current.Item1) { // recycled: restore binding if we are using a LabelFormatter if (LabelFormatter != null && LabelStyle != null) { BindTo(this, nameof(LabelStyle), current.Item2, FrameworkElement.StyleProperty); } } // default text var text = ist.label == null ? String.Empty : (String.IsNullOrEmpty(LabelFormatString) ? ist.label.ToString() : String.Format(LabelFormatString, ist.label) ); if (LabelFormatter != null) { // call for Style, String override var format = LabelFormatter.Convert(sc, typeof(Tuple <Style, String>), null, System.Globalization.CultureInfo.CurrentUICulture.Name); if (format is Tuple <Style, String> ovx) { if (ovx.Item1 != null) { current.Item2.Style = ovx.Item1; } if (ovx.Item2 != null) { text = ovx.Item2; } } } // back-fill values var shim = new TextShim() { Text = text }; current.Item2.DataContext = shim; BindTo(shim, nameof(Visibility), current.Item2, UIElement.VisibilityProperty); ist.element = current.Item2; sc.Generated(ist); }
internal State(List <SeriesItemState> sis, Recycler <Path, SeriesItemState> rc, Evaluators evs) : base(sis, rc) { this.evs = evs; }
/// <summary> /// The recycler's iterator to generate the elements. /// </summary> /// <summary> /// Ctor. /// </summary> /// <param name="state">Starting state; SHOULD be empty.</param> /// <param name="rc">The recycler.</param> internal RenderStateCore(List <SIS> state, Recycler <EL, SIS> rc) { itemstate = state; recycler = rc; }
/// <summary> /// Grid coordinates: /// x: "normalized" [0..1] and scaled to the area-width /// y: "axis" scale /// </summary> /// <param name="icrc"></param> void IRequireRender.Render(IChartRenderContext icrc) { if (ValueAxis == null) { return; } if (double.IsNaN(ValueAxis.Maximum) || double.IsNaN(ValueAxis.Minimum)) { return; } // grid lines var tc = new TickCalculator(ValueAxis.Minimum, ValueAxis.Maximum); var recycler = new Recycler <Path, ItemState>(GridLines.Where(tl => tl.Element != null).Select(tl => tl.Element), (ist) => { return(CreateElement(ist)); }); var mrecycler = new Recycler <Path, ItemState>(MinorGridLines.Where(tl => tl.Element != null).Select(tl => tl.Element), (ist) => { return(CreateSubElement(ist)); }); var itemstate = new List <ItemState>(); var mitemstate = new List <ItemState>(); //_trace.Verbose($"grid range:{tc.Range} tintv:{tc.TickInterval}"); var tixarray = tc.GetTicks().ToArray(); var sc = new ValueAxisSelectorContext(ValueAxis, icrc.SeriesArea, tixarray, tc.TickInterval); for (int ix = 0; ix < tixarray.Length; ix++) { var tick = tixarray[ix]; //_trace.Verbose($"grid vx:{tick}"); var state = new ItemState() { Tick = tick }; var current = recycler.Next(state); if (!current.Item1) { // restore binding if (PathStyle != null) { BindTo(this, nameof(PathStyle), current.Item2, FrameworkElement.StyleProperty); } } state.Element = current.Item2; ApplyBinding(this, nameof(Visibility), state.Element, UIElement.VisibilityProperty); if (PathFormatter != null) { sc.SetTick(ix); // call for Style, String override var format = PathFormatter.Convert(sc, typeof(Tuple <Style, String>), null, System.Globalization.CultureInfo.CurrentUICulture.Name); if (format is Tuple <Style, String> ovx) { if (ovx.Item1 != null) { current.Item2.Style = ovx.Item1; } } } state.SetLocation(icrc.Area.Left, tick.Value); sc.Generated(tick); itemstate.Add(state); if (MinorGridLineCount != 0) { // lay out minor divisions var mintv = tc.TickInterval / (double)(MinorGridLineCount + 1); var diry = Math.Sign(tick.Index); if (diry == 0) { // special case: zero for (int mx = 1; mx <= MinorGridLineCount; mx++) { var mtick = new SubtickState(tick.Index, mx, tick.Value + (double)mx * mintv); var mstate = CreateSubtick(icrc, mrecycler, mtick); if (mstate != null) { mitemstate.Add(mstate); } var mtick2 = new SubtickState(tick.Index, -mx, tick.Value + (double)(-mx) * mintv); var mstate2 = CreateSubtick(icrc, mrecycler, mtick2); if (mstate2 != null) { mitemstate.Add(mstate2); } } } else { for (int mx = 1; mx <= MinorGridLineCount; mx++) { var mtick = new SubtickState(tick.Index, diry * mx, tick.Value + (double)(diry * mx) * mintv); var mstate = CreateSubtick(icrc, mrecycler, mtick); if (mstate != null) { mitemstate.Add(mstate); } } } } } // VT and internal bookkeeping MinorGridLines = mitemstate; GridLines = itemstate; Layer.Remove(mrecycler.Unused); Layer.Remove(recycler.Unused); Layer.Add(recycler.Created); Layer.Add(mrecycler.Created); Dirty = false; }
internal State(List <ItemState <Path> > sis, Recycler <Path, ItemState <Path> > rc, params BindingEvaluator[] bes) : base(sis, rc, new Evaluators(bes[0], bes[2], bes[3])) { bl = bes[1]; }
/// <summary> /// Core element processing. /// The <see cref="RectangleGeometry"/> inside the <see cref="Path"/> is now location-invariant wrt x-axis. /// This means that during incremental updates, no re-calculation is required, only adjusting the <see cref="Canvas.LeftProperty"/>. /// </summary> /// <param name="index"></param> /// <param name="valuex"></param> /// <param name="valuey"></param> /// <param name="item"></param> /// <param name="recycler"></param> /// <param name="byl"></param> /// <returns></returns> ItemState <Path> ElementPipeline(int index, double valuex, double valuey, object item, Recycler <Path, ItemState <Path> > recycler, BindingEvaluator byl) { var y1 = ValueAxis.For(valuey); var y2 = ValueAxis.For(0); var topy = Math.Max(y1, y2); var bottomy = Math.Min(y1, y2); var leftx = CategoryAxis.For(valuex); var barx = BarOffset; var rightx = barx + BarWidth; _trace.Verbose($"{Name}[{index}] {valuey} ({barx},{topy}) ({rightx},{bottomy})"); var path = recycler.Next(null); if (path == null) { return(null); } var shim = new GeometryWithOffsetShim <RectangleGeometry>() { PathData = new RectangleGeometry() { Rect = new Rect(new Point(barx, topy), new Point(rightx, bottomy)) } }; path.Item2.DataContext = shim; // connect the shim to template root element's Visibility BindTo(shim, nameof(shim.Visibility), path.Item2, UIElement.VisibilityProperty); BindTo(shim, nameof(shim.Offset), path.Item2, Canvas.LeftProperty); if (byl == null) { return(new SeriesItemState_Double(index, leftx, BarOffset, y1, path.Item2)); } else { var cs = byl.For(item); return(new SeriesItemState_Custom(index, leftx, BarOffset, y1, cs, path.Item2)); } }
/// <summary> /// Core element processing. /// The <see cref="RectangleGeometry"/> inside the <see cref="Path"/> is now location-invariant wrt x-axis. /// This means that during incremental updates, no re-calculation is required, only adjusting the <see cref="Canvas.LeftProperty"/>. /// </summary> /// <param name="index">Data index.</param> /// <param name="valuec1">C1 (x-axis) index.</param> /// <param name="valuec2">C2 (y-axis) index.</param> /// <param name="value">Cell value.</param> /// <param name="item"></param> /// <param name="recycler"></param> /// <param name="byl"></param> /// <returns></returns> ItemState <Path> ElementPipeline(int index, int valuec1, int valuec2, double value, object item, Recycler <Path, ItemState <Path> > recycler, BindingEvaluator byl) { var path = recycler.Next(null); if (path == null) { return(null); } var shim = new GeometryWith2OffsetShim <RectangleGeometry>() { // MUST use invariant geometry here so it can translate. PathData = new RectangleGeometry() { Rect = new Rect(new Point(0, 0), new Point(1, 1)) } }; path.Item2.DataContext = shim; // connect the shim to template root element's Visibility BindTo(shim, nameof(shim.Visibility), path.Item2, UIElement.VisibilityProperty); BindTo(shim, nameof(shim.Offset), path.Item2, Canvas.LeftProperty); BindTo(shim, nameof(shim.Offset2), path.Item2, Canvas.TopProperty); if (byl == null) { return(new SeriesItemState_Double(index, valuec1, 0, valuec2, value, path.Item2)); } else { var cs = byl.For(item); return(new SeriesItemState_Custom(index, valuec1, 0, valuec2, value, cs, path.Item2)); } }
internal State(List <ItemState <Path> > sis, Recycler <Path, ItemState <Path> > rc, Evaluators evs) : base(sis, rc) { this.evs = evs; }
ItemState <Path> ElementPipeline( int index, double valuex, double valueO, double valueH, double valueL, double valueC, object item, Recycler <Path, ItemState <Path> > recycler, BindingEvaluator bvl ) { // map through axes var y1 = ValueAxis.For(valueO); var y2 = ValueAxis.For(valueC); var y3 = ValueAxis.For(valueH); var y4 = ValueAxis.For(valueL); var leftx = CategoryAxis.For(valuex); var offsetx = BarOffset; var rightx = offsetx + BarWidth; // force them to be a min/max var topy = Math.Max(y1, y2); var bottomy = Math.Min(y1, y2); var highy = Math.Max(y3, y4); var lowy = Math.Min(y3, y4); _trace.Verbose($"{Name}[{index}] {valueO}/{valueH}/{valueL}/{valueC} ({offsetx},{topy}) ({rightx},{bottomy})"); // create geometry var path = recycler.Next(null); if (path == null) { return(null); } var pg = new PathGeometry(); // body (open/close) var body = PathHelper.Rectangle(offsetx, topy, rightx, bottomy); pg.Figures.Add(body); // upper shadow (high) var centerx = offsetx + (rightx - offsetx) / 2; var upper = PathHelper.Line(centerx, topy, centerx, highy); pg.Figures.Add(upper); // lower shadow (low) var lower = PathHelper.Line(centerx, bottomy, centerx, lowy); pg.Figures.Add(lower); var shim = new GeometryWithOffsetShim <PathGeometry>() { PathData = pg }; path.Item2.DataContext = shim; // establish the style for "forward" or "reverse" polarity BindTo(this, valueO < valueC ? nameof(PathStyle) : nameof(ReversePathStyle), path.Item2, Path.StyleProperty); // bind offset BindTo(shim, nameof(shim.Offset), path.Item2, Canvas.LeftProperty); var figs = new Tuple <double, PathFigure> [4]; figs[0] = new Tuple <double, PathFigure>(y1, body); figs[1] = new Tuple <double, PathFigure>(y2, body); figs[2] = new Tuple <double, PathFigure>(y3, upper); figs[3] = new Tuple <double, PathFigure>(y4, lower); if (bvl == null) { return(new SeriesItemState(index, leftx, BarOffset, y1, path.Item2, figs)); } else { var cs = bvl.For(item); return(new SeriesItemState_Custom(index, leftx, BarOffset, y1, cs, path.Item2, figs)); } }
/// <summary> /// Core element creation. /// </summary> /// <param name="index"></param> /// <param name="valuex"></param> /// <param name="valuey"></param> /// <param name="item"></param> /// <param name="recycler"></param> /// <param name="evs"></param> /// <returns></returns> ItemState <Path> ElementPipeline(int index, double valuex, double valuey, object item, Recycler <Path, ItemState <Path> > recycler, Evaluators evs) { var mappedy = ValueAxis.For(valuey); var mappedx = CategoryAxis.For(valuex); var markerx = mappedx + MarkerOffset; _trace.Verbose($"[{index}] {valuey} ({markerx},{mappedy})"); var mk = MarkerTemplate.LoadContent() as Geometry; // TODO allow MK to be other things like (Path or Image). // TODO allow a MarkerTemplateSelector and a value Selector/Formatter // no path yet var el = recycler.Next(null); if (el == null) { return(null); } var shim = new GeometryWithOffsetShim <Geometry>() { PathData = mk }; el.Item2.DataContext = shim; BindTo(shim, nameof(shim.Offset), el.Item2, Canvas.LeftProperty); var cs = evs.LabelFor(item); if (cs == null) { return(new ItemState_Matrix <Path>(index, mappedx, MarkerOffset, mappedy, el.Item2)); } else { return(new ItemStateCustom_Matrix <Path>(index, mappedx, MarkerOffset, mappedy, cs, el.Item2)); } }
/// <summary> /// Core element creation. /// </summary> /// <param name="index"></param> /// <param name="valuex"></param> /// <param name="valuey"></param> /// <param name="item"></param> /// <param name="recycler"></param> /// <param name="evs"></param> /// <returns></returns> ItemState <Image> ElementPipeline(int index, double valuex, double valuey, object item, Recycler <Image, ItemState <Image> > recycler, Evaluators evs) { var mappedy = ValueAxis.For(valuey); var mappedx = CategoryAxis.For(valuex); var markerx = mappedx + MarkerOffset; _trace.Verbose($"[{index}] {valuey} ({markerx},{mappedy})"); // TODO allow a MarkerTemplateSelector and a value Selector/Formatter // no path yet var el = recycler.Next(null); if (el == null) { return(null); } var cs = evs.LabelFor(item); if (cs == null) { return(new ItemState_Matrix <Image>(index, mappedx, MarkerOffset, mappedy, el.Item2)); } else { return(new ItemStateCustom_Matrix <Image>(index, mappedx, MarkerOffset, mappedy, cs, el.Item2)); } }