问:
OxyPlot: how to add background according to axis range
In recent c# wpf application, I used the oxyplot for trending. It's a great tool with high performance on volume datum. I moved from LiveChart to Oxyplot. How to realize the section background depending on the axis range?
TargetEffect

I have tried the modified the ThreeColorLineSeries and now I can render the line according to set Hi and Low Limit. But for the backgound, it doesn't work.

```<code>using System.Collections.Generic;

/// <summary>
/// Represents a two-color line series.
/// </summary>
public class FourColorLineSeries : LineSeries
{
    /// <summary>
    /// The default low color.
    /// </summary>
    private OxyColor defaultColorLoPre;

    /// <summary>
    /// The default low color.
    /// </summary>
    private OxyColor defaultColorLo;

    /// <summary>
    /// The default hi color.
    /// </summary>
    private OxyColor defaultColorLoLo;

    /// <summary>
    /// The default low color.
    /// </summary>
    private OxyColor defaultColorHiPre;

    /// <summary>
    /// The default low color.
    /// </summary>
    private OxyColor defaultColorHi;

    /// <summary>
    /// The default hi color.
    /// </summary>
    private OxyColor defaultColorHiHi;

    /// <summary>
    /// Initializes a new instance of the <see cref = "FourColorLineSeries" /> class.
    /// </summary>
    public FourColorLineSeries()
    {
        this.LimitHiPre = 1.0;
        this.ColorHiPre = OxyColors.Green;
        this.LineStyleHiPre = LineStyle.Solid;

        this.LimitHi = 2.0;
        this.ColorHi = OxyColors.Yellow;
        this.LineStyleHi = LineStyle.Solid;

        this.LimitHiHi = 5.0;
        this.ColorHiHi = OxyColors.Red;
        this.LineStyleHiHi = LineStyle.Solid;

        this.LimitLoPre = -1.0;
        this.ColorLoPre = OxyColors.Green;
        this.LineStyleLoPre = LineStyle.Solid;

        this.LimitLo = -2.0;
        this.ColorLo = OxyColors.Yellow;
        this.LineStyleLo = LineStyle.Solid;

        this.LimitLoLo = -5.0;
        this.ColorLoLo = OxyColors.Red;
        this.LineStyleLoLo = LineStyle.Solid;
    }

    /// <summary>
    /// Gets or sets the color for the part of the line that is below the limit.
    /// </summary>
    public OxyColor ColorLoPre { get; set; }

    /// <summary>
    /// Gets or sets the color for the part of the line that is below the limit.
    /// </summary>
    public OxyColor ColorLo { get; set; }

    /// <summary>
    /// Gets or sets the color for the part of the line that is above the limit.
    /// </summary>
    public OxyColor ColorLoLo { get; set; }

    /// <summary>
    /// Gets or sets the color for the part of the line that is below the limit.
    /// </summary>
    public OxyColor ColorHiPre { get; set; }

    /// <summary>
    /// Gets or sets the color for the part of the line that is below the limit.
    /// </summary>
    public OxyColor ColorHi { get; set; }

    /// <summary>
    /// Gets or sets the color for the part of the line that is above the limit.
    /// </summary>
    public OxyColor ColorHiHi { get; set; }

    /// <summary>
    /// Gets the actual low pre color.
    /// </summary>
    /// <value>The actual color.</value>
    public OxyColor ActualColorLoPre
    {
        get { return this.ColorLoPre.GetActualColor(this.defaultColorLoPre); }
    }

    /// <summary>
    /// Gets the actual low color.
    /// </summary>
    /// <value>The actual color.</value>
    public OxyColor ActualColorLo
    {
        get { return this.ColorLo.GetActualColor(this.defaultColorLo); }
    }

    /// <summary>
    /// Gets the actual low low color.
    /// </summary>
    /// <value>The actual color.</value>
    public OxyColor ActualColorLoLo
    {
        get { return this.ColorLoLo.GetActualColor(this.defaultColorLoLo); }
    }

    /// <summary>
    /// Gets the actual hi pre color.
    /// </summary>
    /// <value>The actual color.</value>
    public OxyColor ActualColorHiPre
    {
        get { return this.ColorHiPre.GetActualColor(this.defaultColorHiPre); }
    }

    /// <summary>
    /// Gets the actual hi color.
    /// </summary>
    /// <value>The actual color.</value>
    public OxyColor ActualColorHi
    {
        get { return this.ColorHi.GetActualColor(this.defaultColorHi); }
    }

    /// <summary>
    /// Gets the actual low color.
    /// </summary>
    /// <value>The actual color.</value>
    public OxyColor ActualColorHiHi
    {
        get { return this.ColorHiHi.GetActualColor(this.defaultColorHiHi); }
    }

    /// <summary>
    /// Gets or sets the high limit.
    /// </summary>
    /// <remarks>The parts of the line that is below this limit will be rendered with ColorHi.
    /// The parts of the line that is above the limit will be rendered with Color.</remarks>
    public double LimitLoPre { get; set; }

    /// <summary>
    /// Gets or sets the low limit.
    /// </summary>
    /// <remarks>The parts of the line that is below this limit will be rendered with ColorLo.
    /// The parts of the line that is above the limit will be rendered with Color.</remarks>
    public double LimitLo { get; set; }

    /// <summary>
    /// Gets or sets the pre limit.
    /// </summary>
    /// <remarks>The parts of the line that is below this limit will be rendered with ColorPre.
    /// The parts of the line that is above the limit will be rendered with Color.</remarks>
    public double LimitLoLo { get; set; }

    /// <summary>
    /// Gets or sets the high limit.
    /// </summary>
    /// <remarks>The parts of the line that is below this limit will be rendered with ColorHi.
    /// The parts of the line that is above the limit will be rendered with Color.</remarks>
    public double LimitHiPre { get; set; }

    /// <summary>
    /// Gets or sets the low limit.
    /// </summary>
    /// <remarks>The parts of the line that is below this limit will be rendered with ColorLo.
    /// The parts of the line that is above the limit will be rendered with Color.</remarks>
    public double LimitHi { get; set; }

    /// <summary>
    /// Gets or sets the pre limit.
    /// </summary>
    /// <remarks>The parts of the line that is below this limit will be rendered with ColorPre.
    /// The parts of the line that is above the limit will be rendered with Color.</remarks>
    public double LimitHiHi { get; set; }

    /// <summary>
    /// Gets or sets the dash array for the rendered line that is above the limit (overrides <see cref="LineStyle" />).
    /// </summary>
    /// <value>The dash array.</value>
    /// <remarks>If this is not <c>null</c> it overrides the <see cref="LineStyle" /> property.</remarks>
    public double[] DashesHi { get; set; }

    /// <summary>
    /// Gets or sets the dash array for the rendered line that is below the limit (overrides <see cref="LineStyle" />).
    /// </summary>
    /// <value>The dash array.</value>
    /// <remarks>If this is not <c>null</c> it overrides the <see cref="LineStyle" /> property.</remarks>
    public double[] DashesLo { get; set; }

    /// <summary>
    /// Gets or sets the dash array for the rendered line that is below the limit (overrides <see cref="LineStyle" />).
    /// </summary>
    /// <value>The dash array.</value>
    /// <remarks>If this is not <c>null</c> it overrides the <see cref="LineStyle" /> property.</remarks>
    public double[] DashesLoPre { get; set; }

    /// <summary>
    /// Gets or sets the dash array for the rendered line that is above the limit (overrides <see cref="LineStyle" />).
    /// </summary>
    /// <value>The dash array.</value>
    /// <remarks>If this is not <c>null</c> it overrides the <see cref="LineStyle" /> property.</remarks>
    public double[] DashesLoLo { get; set; }

    /// <summary>
    /// Gets or sets the dash array for the rendered line that is below the limit (overrides <see cref="LineStyle" />).
    /// </summary>
    /// <value>The dash array.</value>
    /// <remarks>If this is not <c>null</c> it overrides the <see cref="LineStyle" /> property.</remarks>
    public double[] DashesHiPre { get; set; }

    /// <summary>
    /// Gets or sets the dash array for the rendered line that is below the limit (overrides <see cref="LineStyle" />).
    /// </summary>
    /// <value>The dash array.</value>
    /// <remarks>If this is not <c>null</c> it overrides the <see cref="LineStyle" /> property.</remarks>
    public double[] DashesHiHi { get; set; }

    /// <summary>
    /// Gets or sets the line style for the part of the line that is above the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle LineStyleLoPre { get; set; }

    /// <summary>
    /// Gets or sets the line style for the part of the line that is below the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle LineStyleLo { get; set; }

    /// <summary>
    /// Gets or sets the line style for the part of the line that is below the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle LineStyleLoLo { get; set; }

    /// <summary>
    /// Gets or sets the line style for the part of the line that is above the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle LineStyleHiPre { get; set; }

    /// <summary>
    /// Gets or sets the line style for the part of the line that is below the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle LineStyleHi { get; set; }

    /// <summary>
    /// Gets or sets the line style for the part of the line that is below the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle LineStyleHiHi { get; set; }

    /// <summary>
    /// Gets the actual line style for the part of the line that is above the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle ActualLineStyleHi
    {
        get
        {
            return this.LineStyleHi != LineStyle.Automatic ? this.LineStyleHi : LineStyle.Solid;
        }
    }

    /// <summary>
    /// Gets the actual line style for the part of the line that is above the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle ActualLineStyleHiHi
    {
        get
        {
            return this.LineStyleHiHi != LineStyle.Automatic ? this.LineStyleHiHi : LineStyle.Solid;
        }
    }

    /// <summary>
    /// Gets the actual line style for the part of the line that is above the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle ActualLineStyleHiPre
    {
        get
        {
            return this.LineStyleHiPre != LineStyle.Automatic ? this.LineStyleHiPre : LineStyle.Solid;
        }
    }

    /// <summary>
    /// Gets the actual line style for the part of the line that is above the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle ActualLineStyleLoPre
    {
        get
        {
            return this.LineStyleLoPre != LineStyle.Automatic ? this.LineStyleLoPre : LineStyle.Solid;
        }
    }

    /// <summary>
    /// Gets the actual line style for the part of the line that is below the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle ActualLineStyleLo
    {
        get
        {
            return this.LineStyleLo != LineStyle.Automatic ? this.LineStyleLo : LineStyle.Solid;
        }
    }

    /// <summary>
    /// Gets the actual line style for the part of the line that is below the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle ActualLineStyleLoLo
    {
        get
        {
            return this.LineStyleLoLo != LineStyle.Automatic ? this.LineStyleLoLo : LineStyle.Solid;
        }
    }

    /// <summary>
    /// Gets the actual dash array for the line that is above the limit.
    /// </summary>
    protected double[] ActualDashArrayHi
    {
        get
        {
            return this.DashesHi ?? this.ActualLineStyleHi.GetDashArray();
        }
    }

    /// <summary>
    /// Gets the actual dash array for the line that is below the limit.
    /// </summary>
    protected double[] ActualDashArrayLo
    {
        get
        {
            return this.DashesLo ?? this.ActualLineStyleLo.GetDashArray();
        }
    }

    /// <summary>
    /// Gets the actual dash array for the line that is below the limit.
    /// </summary>
    protected double[] ActualDashArrayLoPre
    {
        get
        {
            return this.DashesLoPre ?? this.ActualLineStyleLoPre.GetDashArray();
        }
    }

    /// <summary>
    /// Gets the actual dash array for the line that is above the limit.
    /// </summary>
    protected double[] ActualDashArrayHiHi
    {
        get
        {
            return this.DashesHiHi ?? this.ActualLineStyleHiHi.GetDashArray();
        }
    }

    /// <summary>
    /// Gets the actual dash array for the line that is below the limit.
    /// </summary>
    protected double[] ActualDashArrayLoLo
    {
        get
        {
            return this.DashesLoLo ?? this.ActualLineStyleLoLo.GetDashArray();
        }
    }

    /// <summary>
    /// Gets the actual dash array for the line that is below the limit.
    /// </summary>
    protected double[] ActualDashArrayHiPre
    {
        get
        {
            return this.DashesHiPre ?? this.ActualLineStyleHiPre.GetDashArray();
        }
    }

    /// <summary>
    /// Sets the default values.
    /// </summary>
    protected internal override void SetDefaultValues()
    {
        base.SetDefaultValues();

        if (this.ColorLoPre.IsAutomatic())
        {
            this.defaultColorLoPre = this.PlotModel.GetDefaultColor();
        }

        if (this.LineStyleLoPre == LineStyle.Automatic)
        {
            this.LineStyleLoPre = this.PlotModel.GetDefaultLineStyle();
        }

        if (this.ColorHiPre.IsAutomatic())
        {
            this.defaultColorHiPre = this.PlotModel.GetDefaultColor();
        }

        if (this.LineStyleHiPre == LineStyle.Automatic)
        {
            this.LineStyleHiPre = this.PlotModel.GetDefaultLineStyle();
        }

        if (this.ColorLo.IsAutomatic())
        {
            this.defaultColorLo = this.PlotModel.GetDefaultColor();
        }

        if (this.LineStyleLo == LineStyle.Automatic)
        {
            this.LineStyleLo = this.PlotModel.GetDefaultLineStyle();
        }

        if (this.ColorLoLo.IsAutomatic())
        {
            this.defaultColorLoLo = this.PlotModel.GetDefaultColor();
        }

        if (this.LineStyleLoLo == LineStyle.Automatic)
        {
            this.LineStyleLoLo = this.PlotModel.GetDefaultLineStyle();
        }

        if (this.ColorHi.IsAutomatic())
        {
            this.defaultColorHi = this.PlotModel.GetDefaultColor();
        }

        if (this.LineStyleHi == LineStyle.Automatic)
        {
            this.LineStyleHi = this.PlotModel.GetDefaultLineStyle();
        }

        if (this.ColorHiHi.IsAutomatic())
        {
            this.defaultColorHiHi = this.PlotModel.GetDefaultColor();
        }

        if (this.LineStyleHiHi == LineStyle.Automatic)
        {
            this.LineStyleHiHi = this.PlotModel.GetDefaultLineStyle();
        }
    }

    /// <summary>
    /// Renders the smoothed line.
    /// </summary>
    /// <param name="rc">The render context.</param>
    /// <param name="clippingRect">The clipping rectangle.</param>
    /// <param name="pointsToRender">The points.</param>
    protected override void RenderLine(IRenderContext rc, OxyRect clippingRect, IList<ScreenPoint> pointsToRender)
    {
        var bottom = clippingRect.Bottom;
        var top = clippingRect.Top;

        // todo: this does not work when y axis is reversed
        var yLoPre = this.YAxis.Transform(this.LimitLoPre);
        var yLo = this.YAxis.Transform(this.LimitLo);
        var yLoLo = this.YAxis.Transform(this.LimitLoLo);
        var yHiPre = this.YAxis.Transform(this.LimitHiPre);
        var yHi = this.YAxis.Transform(this.LimitHi);
        var yHiHi = this.YAxis.Transform(this.LimitHiHi);

        if (yLoPre< clippingRect.Top)
        {
            yLoPre = clippingRect.Top;
        }

        if (yLoPre > clippingRect.Bottom)
        {
            yLoPre = clippingRect.Bottom;
        }

        if (yHiPre < clippingRect.Top)
        {
            yHiPre = clippingRect.Top;
        }

        if (yHiPre > clippingRect.Bottom)
        {
            yHiPre = clippingRect.Bottom;
        }

        if (yLo < clippingRect.Top)
        {
            yLo = clippingRect.Top;
        }

        if (yLo > clippingRect.Bottom)
        {
            yLo = clippingRect.Bottom;
        }

        if (yLoLo < clippingRect.Top)
        {
            yLoLo = clippingRect.Top;
        }

        if (yLoLo > clippingRect.Bottom)
        {
            yLoLo = clippingRect.Bottom;
        }

        if (yHi < clippingRect.Top)
        {
            yHi = clippingRect.Top;
        }

        if (yHi > clippingRect.Bottom)
        {
            yHi = clippingRect.Bottom;
        }

        if (yHiHi < clippingRect.Top)
        {
            yHiHi = clippingRect.Top;
        }

        if (yHiHi > clippingRect.Bottom)
        {
            yHiHi = clippingRect.Bottom;
        }

        clippingRect = new OxyRect(clippingRect.Left, top, clippingRect.Width, yHiHi - top);

        rc.DrawClippedLine(
            clippingRect,
            pointsToRender,
            this.MinimumSegmentLength * this.MinimumSegmentLength,
            this.GetSelectableColor(this.ActualColorHiHi),
            this.StrokeThickness,
            this.ActualDashArrayHiHi,
            this.LineJoin,
            false);

        clippingRect = new OxyRect(clippingRect.Left, yHiHi, clippingRect.Width, yHi - yHiHi);

        rc.DrawClippedLine(
            clippingRect,
            pointsToRender,
            this.MinimumSegmentLength * this.MinimumSegmentLength,
            this.GetSelectableColor(this.ActualColorHi),
            this.StrokeThickness,
            this.ActualDashArrayHi,
            this.LineJoin,
            false);

        clippingRect = new OxyRect(clippingRect.Left, yHi, clippingRect.Width, yHiPre - yHi);

        rc.DrawClippedLine(
            clippingRect,
            pointsToRender,
            this.MinimumSegmentLength * this.MinimumSegmentLength,
            this.GetSelectableColor(this.ActualColorHiPre),
            this.StrokeThickness,
            this.ActualDashArrayHiPre,
            this.LineJoin,
            false);

        clippingRect = new OxyRect(clippingRect.Left, yHiPre, clippingRect.Width, yLoPre - yHiPre);

        rc.DrawClippedLine(
            clippingRect,
            pointsToRender,
            this.MinimumSegmentLength * this.MinimumSegmentLength,
            this.GetSelectableColor(this.ActualColor),
            this.StrokeThickness,
            this.ActualDashArray,
            this.LineJoin,
            false);

        clippingRect = new OxyRect(clippingRect.Left, yLoPre, clippingRect.Width, yLo - yLoPre);

        rc.DrawClippedLine(
            clippingRect,
            pointsToRender,
            this.MinimumSegmentLength * this.MinimumSegmentLength,
            this.GetSelectableColor(this.ActualColorLoPre),
            this.StrokeThickness,
            this.ActualDashArrayLoPre,
            this.LineJoin,
            false);

        clippingRect = new OxyRect(clippingRect.Left, yLo, clippingRect.Width, yLoLo - yLo);

        rc.DrawClippedLine(
            clippingRect,
            pointsToRender,
            this.MinimumSegmentLength * this.MinimumSegmentLength,
            this.GetSelectableColor(this.ActualColorLo),
            this.StrokeThickness,
            this.ActualDashArrayLo,
            this.LineJoin,
            false);

        clippingRect = new OxyRect(clippingRect.Left, yLoLo, clippingRect.Width, bottom - yLoLo);

        rc.DrawClippedLine(
            clippingRect,
            pointsToRender,
            this.MinimumSegmentLength * this.MinimumSegmentLength,
            this.GetSelectableColor(this.ActualColorLoLo),
            this.StrokeThickness,
            this.ActualDashArrayLoLo,
            this.LineJoin,
            false);
     }
}
</code>```

}

答:
After reading and struggling with the oxyplot source code in two days, I finally modify the existing oxyplot RangeColorAxis.cs and also make a wpf wrapper. After these actions I can get following images by using the 2 rebuilt dll(OxyPlot.dll and Oxyplot.Wpf.dll) files.

LineSeries with axis value based range colors

Modified RangeColorAxis.cs

```<code>namespace OxyPlot.Axes
{
    using System;
    using System.Collections.Generic;

    /// <summary>
    /// Represents a color axis that contains colors for specified ranges.
    /// </summary>
    public class RangeColorAxis : LinearAxis, IColorAxis
    {
        /// <summary>
        /// The ranges
        /// </summary>
        private readonly List<ColorRange> ranges = new List<ColorRange>();

        /// <summary>
        /// Initializes a new instance of the <see cref="RangeColorAxis" /> class.
        /// </summary>
        public RangeColorAxis()
        {
            this.Position = AxisPosition.None;
            this.AxisDistance = 20;

            this.LowColor = OxyColors.Undefined;
            this.HighColor = OxyColors.Undefined;
            this.InvalidNumberColor = OxyColors.Gray;

            this.IsPanEnabled = false;
            this.IsZoomEnabled = false;
        }

        /// <summary>
        /// Gets or sets the color used to represent NaN values.
        /// </summary>
        /// <value>A <see cref="OxyColor" /> that defines the color. The default value is <c>OxyColors.Gray</c>.</value>
        public OxyColor InvalidNumberColor { get; set; }

        /// <summary>
        /// Gets or sets the color of values above the maximum value.
        /// </summary>
        /// <value>The color of the high values.</value>
        public OxyColor HighColor { get; set; }

        /// <summary>
        /// Gets or sets the color of values below the minimum value.
        /// </summary>
        /// <value>The color of the low values.</value>
        public OxyColor LowColor { get; set; }

        /// <summary>
        /// Adds a range.
        /// </summary>
        /// <param name="lowerBound">The lower bound.</param>
        /// <param name="upperBound">The upper bound.</param>
        /// <param name="color">The color.</param>
        public void AddRange(double lowerBound, double upperBound, OxyColor color)
        {
            this.ranges.Add(new ColorRange { LowerBound = lowerBound, UpperBound = upperBound, Color = color });
        }

        /// <summary>
        /// Clears the ranges.
        /// </summary>
        public void ClearRanges()
        {
            this.ranges.Clear();
        }

        /// <summary>
        /// Gets the palette index of the specified value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>The palette index.</returns>
        /// <remarks>If the value is less than minimum, 0 is returned. If the value is greater than maximum, Palette.Colors.Count+1 is returned.</remarks>
        public int GetPaletteIndex(double value)
        {
            if (!this.LowColor.IsUndefined() && value < this.ranges[0].LowerBound)
            {
                return -1;
            }

            if (!this.HighColor.IsUndefined() && value > this.ranges[this.ranges.Count - 1].UpperBound)
            {
                return this.ranges.Count;
            }

            // TODO: change to binary search?
            for (int i = 0; i < this.ranges.Count; i++)
            {
                var range = this.ranges[i];
                if (range.LowerBound <= value && range.UpperBound > value)
                {
                    return i;
                }
            }

            return int.MinValue;
        }

        /// <summary>
        /// Gets the color.
        /// </summary>
        /// <param name="paletteIndex">The color map index.</param>
        /// <returns>The color.</returns>
        public OxyColor GetColor(int paletteIndex)
        {
            if (paletteIndex == int.MinValue)
            {
                return this.InvalidNumberColor;
            }

            if (paletteIndex == -1)
            {
                return this.LowColor;
            }

            if (paletteIndex == this.ranges.Count)
            {
                return this.HighColor;
            }

            return this.ranges[paletteIndex].Color;
        }

        /// <summary>
        /// Renders the axis on the specified render context.
        /// </summary>
        /// <param name="rc">The render context.</param>
        /// <param name="pass">The render pass.</param>
        public override void Render(IRenderContext rc, int pass)
        {
            if (this.Position == AxisPosition.None)
            {
                return;
            }

            if (pass == 0)
            {
                double distance = this.AxisDistance;
                double left = this.PlotModel.PlotArea.Left;
                double top = this.PlotModel.PlotArea.Top;
                double width = this.MajorTickSize - 2;
                double height = this.MajorTickSize - 2;
                double plotwidth = this.PlotModel.PlotArea.Width;
                double plotheight = this.PlotModel.PlotArea.Height;

                const int TierShift = 0;

                switch (this.Position)
                {
                    case AxisPosition.Left:
                        left = this.PlotModel.PlotArea.Left - TierShift - width - distance;
                        top = this.PlotModel.PlotArea.Top;
                        break;
                    case AxisPosition.Right:
                        left = this.PlotModel.PlotArea.Right + TierShift + distance;
                        top = this.PlotModel.PlotArea.Top;
                        break;
                    case AxisPosition.Top:
                        left = this.PlotModel.PlotArea.Left;
                        top = this.PlotModel.PlotArea.Top - TierShift - height - distance;
                        break;
                    case AxisPosition.Bottom:
                        left = this.PlotModel.PlotArea.Left;
                        top = this.PlotModel.PlotArea.Bottom + TierShift + distance;
                        break;
                }

                Action<double, double, OxyColor> drawColorRect = (ylow, yhigh, color) =>
                {
                    double ymin = Math.Min(ylow, yhigh);
                    double ymax = Math.Max(ylow, yhigh);
                    rc.DrawRectangle(
                        this.IsHorizontal()
                            ? new OxyRect(ymin, top, ymax - ymin, plotheight)
                            : new OxyRect(left, ymin, plotwidth, ymax - ymin),
                        color,
                        OxyColors.Undefined);
                };

                // if the axis is reversed then the min and max values need to be swapped.
                double effectiveMaxY = this.Transform(this.IsReversed ? this.ActualMinimum : this.ActualMaximum);
                double effectiveMinY = this.Transform(this.IsReversed ? this.ActualMaximum : this.ActualMinimum);

                foreach (ColorRange range in this.ranges)
                {
                    double ylow = this.Transform(range.LowerBound);
                    double yhigh = this.Transform(range.UpperBound);

                    if (this.IsHorizontal())
                    {
                        if (ylow < effectiveMinY)
                        {
                            ylow = effectiveMinY;
                        }

                        if (yhigh > effectiveMaxY)
                        {
                            yhigh = effectiveMaxY;
                        }
                    }
                    else
                    {
                        if (ylow > effectiveMinY)
                        {
                            ylow = effectiveMinY;
                        }

                        if (yhigh < effectiveMaxY)
                        {
                            yhigh = effectiveMaxY;
                        }
                    }

                    drawColorRect(ylow, yhigh, range.Color);
                }

                double highLowLength = 10;
                if (this.IsHorizontal())
                {
                    highLowLength *= -1;
                }

                if (!this.LowColor.IsUndefined())
                {
                    double ylow = this.Transform(this.ActualMinimum);
                    drawColorRect(ylow, ylow + highLowLength, this.LowColor);
                }

                if (!this.HighColor.IsUndefined())
                {
                    double yhigh = this.Transform(this.ActualMaximum);
                    drawColorRect(yhigh, yhigh - highLowLength, this.HighColor);
                }
            }

            var r = new HorizontalAndVerticalAxisRenderer(rc, this.PlotModel);
            r.Render(this, pass);
        }

        /// <summary>
        /// Defines a range.
        /// </summary>
        private class ColorRange
        {
            /// <summary>
            /// Gets or sets the color.
            /// </summary>
            /// <value>The color.</value>
            public OxyColor Color { get; set; }

            /// <summary>
            /// Gets or sets the lower bound.
            /// </summary>
            /// <value>The lower bound.</value>
            public double LowerBound { get; set; }

            /// <summary>
            /// Gets or sets the upper bound.
            /// </summary>
            /// <value>The upper bound.</value>
            public double UpperBound { get; set; }
        }
    }
}
</code>```

WPF wrapper for RangeColorAxis.cs

```<code>namespace OxyPlot.Wpf
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Windows;
    using System.Windows.Markup;
    using System.Windows.Media;

    /// <summary>
    /// This is a WPF wrapper for the <see cref="OxyPlot.Axes.RangeColorAxis"/>
    /// </summary>
    public class RangeColorAxis : Axis
    {
        /// <summary>
        /// Identifies the <see cref="InvalidNumberColor"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty InvalidNumberColorProperty =
            DependencyProperty.Register(
                "InvalidNumberColor",
                typeof(Color),
                typeof(RangeColorAxis),
                new PropertyMetadata(Colors.Orange, AppearanceChanged));

        /// <summary>
        /// Identifies the <see cref="HighColor"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty HighColorProperty = DependencyProperty.Register(
            "HighColor", typeof(Color), typeof(RangeColorAxis), new PropertyMetadata(Colors.White, AppearanceChanged));

        /// <summary>
        /// Identifies the <see cref="LowColor"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty LowColorProperty = DependencyProperty.Register(
            "LowColor", typeof(Color), typeof(RangeColorAxis), new PropertyMetadata(Colors.Black, AppearanceChanged));

        /// <summary>
        /// Identifies the <see cref="Ranges"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty RangesProperty = DependencyProperty.Register(
            "Ranges", typeof(IList<Tuple<double, double, Color>>), typeof(RangeColorAxis), new PropertyMetadata(new List<Tuple<double,double,Color>>(), DataChanged));

        /// <summary>
        /// Initializes a new instance of the <see cref="RangeColorAxis"/> class.
        /// </summary>
        public RangeColorAxis()
        {
            this.InternalAxis = new Axes.RangeColorAxis();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="InvalidNumberColor"/> class.
        /// </summary>
        public Color InvalidNumberColor
        {
            get
            {
                return (Color)this.GetValue(InvalidNumberColorProperty);
            }

            set
            {
                this.SetValue(InvalidNumberColorProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the high color.
        /// </summary>
        public Color HighColor
        {
            get
            {
                return (Color)this.GetValue(HighColorProperty);
            }

            set
            {
                this.SetValue(HighColorProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the low color.
        /// </summary>
        public Color LowColor
        {
            get
            {
                return (Color)this.GetValue(LowColorProperty);
            }

            set
            {
                this.SetValue(LowColorProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets Labels.
        /// </summary>
        public IList<Tuple<double, double, Color>> Ranges
        {
            get
            {
                return (IList<Tuple<double, double, Color>>)this.GetValue(RangesProperty);
            }

            set
            {
                this.SetValue(RangesProperty, value);
            }
        }

        /// <summary>
        /// Creates the model.
        /// </summary>
        /// <returns>
        /// An axis object.
        /// </returns>
        public override Axes.Axis CreateModel()
        {
            this.SynchronizeProperties();
            return this.InternalAxis;
        }

        /// <summary>
        /// Synchronizes the properties.
        /// </summary>
        protected override void SynchronizeProperties()
        {
            base.SynchronizeProperties();
            var axis = this.InternalAxis as Axes.RangeColorAxis;
            Trace.Assert(axis != null);
            //if (this.GradientStops != null)
            //{
            //    axis.Palette = this.GradientStops.Count > 2
            //                       ? Interpolate(this.GradientStops.ToList(), this.PaletteSize)
            //                       : new OxyPalette();
            //}

            axis.HighColor = this.HighColor.ToOxyColor();
            axis.LowColor = this.LowColor.ToOxyColor();
            axis.InvalidNumberColor = this.InvalidNumberColor.ToOxyColor();
            axis.Minimum = this.Minimum;
            axis.Maximum = this.Maximum;
            if (Ranges != null)
            {
                axis.ClearRanges();
                foreach (var range in Ranges)
                {
                    axis.AddRange(range.Item1, range.Item2, range.Item3.ToOxyColor());
                }
            }
        }

    }
}
</code>```

XAML file:

```<code><oxyPlot:Plot.Axes>
    <oxyPlot:DateTimeAxis StringFormat="HH:mm:ss"></oxyPlot:DateTimeAxis>
    <oxyPlot:RangeColorAxis
         Ranges="{Binding ColorRanges}"
         Unit="{Binding Unit}"
         AbsoluteMinimum="{Binding DisplayMin}"
         AbsoluteMaximum="{Binding DisplayMax}"
         MinimumRange="{Binding DisplayMax}"/>
</oxyPlot:Plot.Axes>
</code>```

View Model

```<code>...
/// <summary>
/// The <see cref="ColorRanges" /> property's name.
/// </summary>
public const string ColorRangesPropertyName = "ColorRanges";

private List<Tuple<double, double, System.Windows.Media.Color>> _colorRanges = new List<Tuple<double, double, System.Windows.Media.Color>>();

/// <summary>
/// Sets and gets the ColorRanges property.
/// Changes to that property's value raise the PropertyChanged event.
/// </summary>
public List<Tuple<double, double, System.Windows.Media.Color>> ColorRanges
{
    get
    {
        return _colorRanges;
    }

    set
    {
        if (_colorRanges == value)
        {
            return;
        }

        _colorRanges = value;
        RaisePropertyChanged(ColorRangesPropertyName);
    }
}
...
//usage
ColorRanges.Clear();
if (DisplayMin < LevelThresholdLoLo)
{
    ColorRanges.Add(new Tuple<double, double, Color>(DisplayMin, LevelThresholdLoLo, Color.FromArgb(127,255,68,0)));
}
if (LevelThresholdLoLo < LevelThresholdLo)
{
    ColorRanges.Add(new Tuple<double, double, Color>(LevelThresholdLoLo, LevelThresholdLo, Color.FromArgb(127, 255, 140, 0)));
}
if (LevelThresholdLo < LevelThresholdLoPre)
{
    ColorRanges.Add(new Tuple<double, double, Color>(LevelThresholdLo, LevelThresholdLoPre, Color.FromArgb(127, 65,105,225)));
}
if (LevelThresholdLoPre < LevelThresholdHiPre)
{
    ColorRanges.Add(new Tuple<double, double, Color>(LevelThresholdLoPre, LevelThresholdHiPre, Color.FromArgb(127, 50, 205, 50)));
}
if (LevelThresholdHiPre < LevelThresholdHi)
{
    ColorRanges.Add(new Tuple<double, double, Color>(LevelThresholdHiPre, LevelThresholdHi, Color.FromArgb(127, 65, 105, 225)));
}
if (LevelThresholdHi < LevelThresholdHiHi)
{
    ColorRanges.Add(new Tuple<double, double, Color>(LevelThresholdHi, LevelThresholdHiHi, Color.FromArgb(127,255,140,0)));
}
if (LevelThresholdHiHi < DisplayMax)
{
    ColorRanges.Add(new Tuple<double, double, Color>(LevelThresholdHiHi, DisplayMax, Color.FromArgb(127, 255, 68, 0)));
}
</code>```

Body:
In recent c# wpf application, I used the oxyplot for trending. It's a great tool with high performance on volume datum. I moved from LiveChart to Oxyplot. How to realize the section background depending on the axis range?
TargetEffect

I have tried the modified the ThreeColorLineSeries and now I can render the line according to set Hi and Low Limit. But for the backgound, it doesn't work.

using System.Collections.Generic;

///
/// Represents a two-color line series.
///
public class FourColorLineSeries : LineSeries
{
    ///
    /// The default low color.
    ///
    private OxyColor defaultColorLoPre;

    ///
    /// The default low color.
    ///
    private OxyColor defaultColorLo;

    ///
    /// The default hi color.
    ///
    private OxyColor defaultColorLoLo;

    ///
    /// The default low color.
    ///
    private OxyColor defaultColorHiPre;

    ///
    /// The default low color.
    ///
    private OxyColor defaultColorHi;

    ///
    /// The default hi color.
    ///
    private OxyColor defaultColorHiHi;

    ///
    /// Initializes a new instance of the <see cref = "FourColorLineSeries" /> class.
    ///
    public FourColorLineSeries()
    {
        this.LimitHiPre = 1.0;
        this.ColorHiPre = OxyColors.Green;
        this.LineStyleHiPre = LineStyle.Solid;

        this.LimitHi = 2.0;
        this.ColorHi = OxyColors.Yellow;
        this.LineStyleHi = LineStyle.Solid;

        this.LimitHiHi = 5.0;
        this.ColorHiHi = OxyColors.Red;
        this.LineStyleHiHi = LineStyle.Solid;

        this.LimitLoPre = -1.0;
        this.ColorLoPre = OxyColors.Green;
        this.LineStyleLoPre = LineStyle.Solid;

        this.LimitLo = -2.0;
        this.ColorLo = OxyColors.Yellow;
        this.LineStyleLo = LineStyle.Solid;

        this.LimitLoLo = -5.0;
        this.ColorLoLo = OxyColors.Red;
        this.LineStyleLoLo = LineStyle.Solid;
    }

    ///
    /// Gets or sets the color for the part of the line that is below the limit.
    ///
    public OxyColor ColorLoPre { get; set; }

    ///
    /// Gets or sets the color for the part of the line that is below the limit.
    ///
    public OxyColor ColorLo { get; set; }

    ///
    /// Gets or sets the color for the part of the line that is above the limit.
    ///
    public OxyColor ColorLoLo { get; set; }

    ///
    /// Gets or sets the color for the part of the line that is below the limit.
    ///
    public OxyColor ColorHiPre { get; set; }

    ///
    /// Gets or sets the color for the part of the line that is below the limit.
    ///
    public OxyColor ColorHi { get; set; }

    ///
    /// Gets or sets the color for the part of the line that is above the limit.
    ///
    public OxyColor ColorHiHi { get; set; }

    ///
    /// Gets the actual low pre color.
    ///
    /// <value>The actual color.</value>
    public OxyColor ActualColorLoPre
    {
        get { return this.ColorLoPre.GetActualColor(this.defaultColorLoPre); }
    }

    ///
    /// Gets the actual low color.
    ///
    /// <value>The actual color.</value>
    public OxyColor ActualColorLo
    {
        get { return this.ColorLo.GetActualColor(this.defaultColorLo); }
    }

    ///
    /// Gets the actual low low color.
    ///
    /// <value>The actual color.</value>
    public OxyColor ActualColorLoLo
    {
        get { return this.ColorLoLo.GetActualColor(this.defaultColorLoLo); }
    }

    ///
    /// Gets the actual hi pre color.
    ///
    /// <value>The actual color.</value>
    public OxyColor ActualColorHiPre
    {
        get { return this.ColorHiPre.GetActualColor(this.defaultColorHiPre); }
    }

    ///
    /// Gets the actual hi color.
    ///
    /// <value>The actual color.</value>
    public OxyColor ActualColorHi
    {
        get { return this.ColorHi.GetActualColor(this.defaultColorHi); }
    }

    ///
    /// Gets the actual low color.
    ///
    /// <value>The actual color.</value>
    public OxyColor ActualColorHiHi
    {
        get { return this.ColorHiHi.GetActualColor(this.defaultColorHiHi); }
    }

    ///
    /// Gets or sets the high limit.
    ///
    /// <remarks>The parts of the line that is below this limit will be rendered with ColorHi.
    /// The parts of the line that is above the limit will be rendered with Color.</remarks>
    public double LimitLoPre { get; set; }

    ///
    /// Gets or sets the low limit.
    ///
    /// <remarks>The parts of the line that is below this limit will be rendered with ColorLo.
    /// The parts of the line that is above the limit will be rendered with Color.</remarks>
    public double LimitLo { get; set; }

    ///
    /// Gets or sets the pre limit.
    ///
    /// <remarks>The parts of the line that is below this limit will be rendered with ColorPre.
    /// The parts of the line that is above the limit will be rendered with Color.</remarks>
    public double LimitLoLo { get; set; }

    ///
    /// Gets or sets the high limit.
    ///
    /// <remarks>The parts of the line that is below this limit will be rendered with ColorHi.
    /// The parts of the line that is above the limit will be rendered with Color.</remarks>
    public double LimitHiPre { get; set; }

    ///
    /// Gets or sets the low limit.
    ///
    /// <remarks>The parts of the line that is below this limit will be rendered with ColorLo.
    /// The parts of the line that is above the limit will be rendered with Color.</remarks>
    public double LimitHi { get; set; }

    ///
    /// Gets or sets the pre limit.
    ///
    /// <remarks>The parts of the line that is below this limit will be rendered with ColorPre.
    /// The parts of the line that is above the limit will be rendered with Color.</remarks>
    public double LimitHiHi { get; set; }

    ///
    /// Gets or sets the dash array for the rendered line that is above the limit (overrides <see cref="LineStyle" />).
    ///
    /// <value>The dash array.</value>
    /// <remarks>If this is not <c>null</c> it overrides the <see cref="LineStyle" /> property.</remarks>
    public double[] DashesHi { get; set; }

    ///
    /// Gets or sets the dash array for the rendered line that is below the limit (overrides <see cref="LineStyle" />).
    ///
    /// <value>The dash array.</value>
    /// <remarks>If this is not <c>null</c> it overrides the <see cref="LineStyle" /> property.</remarks>
    public double[] DashesLo { get; set; }

    ///
    /// Gets or sets the dash array for the rendered line that is below the limit (overrides <see cref="LineStyle" />).
    ///
    /// <value>The dash array.</value>
    /// <remarks>If this is not <c>null</c> it overrides the <see cref="LineStyle" /> property.</remarks>
    public double[] DashesLoPre { get; set; }

    ///
    /// Gets or sets the dash array for the rendered line that is above the limit (overrides <see cref="LineStyle" />).
    ///
    /// <value>The dash array.</value>
    /// <remarks>If this is not <c>null</c> it overrides the <see cref="LineStyle" /> property.</remarks>
    public double[] DashesLoLo { get; set; }

    ///
    /// Gets or sets the dash array for the rendered line that is below the limit (overrides <see cref="LineStyle" />).
    ///
    /// <value>The dash array.</value>
    /// <remarks>If this is not <c>null</c> it overrides the <see cref="LineStyle" /> property.</remarks>
    public double[] DashesHiPre { get; set; }

    ///
    /// Gets or sets the dash array for the rendered line that is below the limit (overrides <see cref="LineStyle" />).
    ///
    /// <value>The dash array.</value>
    /// <remarks>If this is not <c>null</c> it overrides the <see cref="LineStyle" /> property.</remarks>
    public double[] DashesHiHi { get; set; }

    ///
    /// Gets or sets the line style for the part of the line that is above the limit.
    ///
    /// <value>The line style.</value>
    public LineStyle LineStyleLoPre { get; set; }

    ///
    /// Gets or sets the line style for the part of the line that is below the limit.
    ///
    /// <value>The line style.</value>
    public LineStyle LineStyleLo { get; set; }

    ///
    /// Gets or sets the line style for the part of the line that is below the limit.
    ///
    /// <value>The line style.</value>
    public LineStyle LineStyleLoLo { get; set; }

    ///
    /// Gets or sets the line style for the part of the line that is above the limit.
    ///
    /// <value>The line style.</value>
    public LineStyle LineStyleHiPre { get; set; }

    ///
    /// Gets or sets the line style for the part of the line that is below the limit.
    ///
    /// <value>The line style.</value>
    public LineStyle LineStyleHi { get; set; }

    ///
    /// Gets or sets the line style for the part of the line that is below the limit.
    ///
    /// <value>The line style.</value>
    public LineStyle LineStyleHiHi { get; set; }

    ///
    /// Gets the actual line style for the part of the line that is above the limit.
    ///
    /// <value>The line style.</value>
    public LineStyle ActualLineStyleHi
    {
        get
        {
            return this.LineStyleHi != LineStyle.Automatic ? this.LineStyleHi : LineStyle.Solid;
        }
    }

    ///
    /// Gets the actual line style for the part of the line that is above the limit.
    ///
    /// <value>The line style.</value>
    public LineStyle ActualLineStyleHiHi
    {
        get
        {
            return this.LineStyleHiHi != LineStyle.Automatic ? this.LineStyleHiHi : LineStyle.Solid;
        }
    }

    ///
    /// Gets the actual line style for the part of the line that is above the limit.
    ///
    /// <value>The line style.</value>
    public LineStyle ActualLineStyleHiPre
    {
        get
        {
            return this.LineStyleHiPre != LineStyle.Automatic ? this.LineStyleHiPre : LineStyle.Solid;
        }
    }

    ///
    /// Gets the actual line style for the part of the line that is above the limit.
    ///
    /// <value>The line style.</value>
    public LineStyle ActualLineStyleLoPre
    {
        get
        {
            return this.LineStyleLoPre != LineStyle.Automatic ? this.LineStyleLoPre : LineStyle.Solid;
        }
    }

    ///
    /// Gets the actual line style for the part of the line that is below the limit.
    ///
    /// <value>The line style.</value>
    public LineStyle ActualLineStyleLo
    {
        get
        {
            return this.LineStyleLo != LineStyle.Automatic ? this.LineStyleLo : LineStyle.Solid;
        }
    }

    ///
    /// Gets the actual line style for the part of the line that is below the limit.
    ///
    /// <value>The line style.</value>
    public LineStyle ActualLineStyleLoLo
    {
        get
        {
            return this.LineStyleLoLo != LineStyle.Automatic ? this.LineStyleLoLo : LineStyle.Solid;
        }
    }

    ///
    /// Gets the actual dash array for the line that is above the limit.
    ///
    protected double[] ActualDashArrayHi
    {
        get
        {
            return this.DashesHi ?? this.ActualLineStyleHi.GetDashArray();
        }
    }

    ///
    /// Gets the actual dash array for the line that is below the limit.
    ///
    protected double[] ActualDashArrayLo
    {
        get
        {
            return this.DashesLo ?? this.ActualLineStyleLo.GetDashArray();
        }
    }

    ///
    /// Gets the actual dash array for the line that is below the limit.
    ///
    protected double[] ActualDashArrayLoPre
    {
        get
        {
            return this.DashesLoPre ?? this.ActualLineStyleLoPre.GetDashArray();
        }
    }

    ///
    /// Gets the actual dash array for the line that is above the limit.
    ///
    protected double[] ActualDashArrayHiHi
    {
        get
        {
            return this.DashesHiHi ?? this.ActualLineStyleHiHi.GetDashArray();
        }
    }

    ///
    /// Gets the actual dash array for the line that is below the limit.
    ///
    protected double[] ActualDashArrayLoLo
    {
        get
        {
            return this.DashesLoLo ?? this.ActualLineStyleLoLo.GetDashArray();
        }
    }

    ///
    /// Gets the actual dash array for the line that is below the limit.
    ///
    protected double[] ActualDashArrayHiPre
    {
        get
        {
            return this.DashesHiPre ?? this.ActualLineStyleHiPre.GetDashArray();
        }
    }

    ///
    /// Sets the default values.
    ///
    protected internal override void SetDefaultValues()
    {
        base.SetDefaultValues();

        if (this.ColorLoPre.IsAutomatic())
        {
            this.defaultColorLoPre = this.PlotModel.GetDefaultColor();
        }

        if (this.LineStyleLoPre == LineStyle.Automatic)
        {
            this.LineStyleLoPre = this.PlotModel.GetDefaultLineStyle();
        }

        if (this.ColorHiPre.IsAutomatic())
        {
            this.defaultColorHiPre = this.PlotModel.GetDefaultColor();
        }

        if (this.LineStyleHiPre == LineStyle.Automatic)
        {
            this.LineStyleHiPre = this.PlotModel.GetDefaultLineStyle();
        }

        if (this.ColorLo.IsAutomatic())
        {
            this.defaultColorLo = this.PlotModel.GetDefaultColor();
        }

        if (this.LineStyleLo == LineStyle.Automatic)
        {
            this.LineStyleLo = this.PlotModel.GetDefaultLineStyle();
        }

        if (this.ColorLoLo.IsAutomatic())
        {
            this.defaultColorLoLo = this.PlotModel.GetDefaultColor();
        }

        if (this.LineStyleLoLo == LineStyle.Automatic)
        {
            this.LineStyleLoLo = this.PlotModel.GetDefaultLineStyle();
        }

        if (this.ColorHi.IsAutomatic())
        {
            this.defaultColorHi = this.PlotModel.GetDefaultColor();
        }

        if (this.LineStyleHi == LineStyle.Automatic)
        {
            this.LineStyleHi = this.PlotModel.GetDefaultLineStyle();
        }

        if (this.ColorHiHi.IsAutomatic())
        {
            this.defaultColorHiHi = this.PlotModel.GetDefaultColor();
        }

        if (this.LineStyleHiHi == LineStyle.Automatic)
        {
            this.LineStyleHiHi = this.PlotModel.GetDefaultLineStyle();
        }
    }

    ///
    /// Renders the smoothed line.
    ///
    /// <param name="rc">The render context.</param>
    /// <param name="clippingRect">The clipping rectangle.</param>
    /// <param name="pointsToRender">The points.</param>
    protected override void RenderLine(IRenderContext rc, OxyRect clippingRect, IList<ScreenPoint> pointsToRender)
    {
        var bottom = clippingRect.Bottom;
        var top = clippingRect.Top;

        // todo: this does not work when y axis is reversed
        var yLoPre = this.YAxis.Transform(this.LimitLoPre);
        var yLo = this.YAxis.Transform(this.LimitLo);
        var yLoLo = this.YAxis.Transform(this.LimitLoLo);
        var yHiPre = this.YAxis.Transform(this.LimitHiPre);
        var yHi = this.YAxis.Transform(this.LimitHi);
        var yHiHi = this.YAxis.Transform(this.LimitHiHi);

        if (yLoPre< clippingRect.Top)
        {
            yLoPre = clippingRect.Top;
        }

        if (yLoPre > clippingRect.Bottom)
        {
            yLoPre = clippingRect.Bottom;
        }

        if (yHiPre < clippingRect.Top)
        {
            yHiPre = clippingRect.Top;
        }

        if (yHiPre > clippingRect.Bottom)
        {
            yHiPre = clippingRect.Bottom;
        }

        if (yLo < clippingRect.Top)
        {
            yLo = clippingRect.Top;
        }

        if (yLo > clippingRect.Bottom)
        {
            yLo = clippingRect.Bottom;
        }

        if (yLoLo < clippingRect.Top)
        {
            yLoLo = clippingRect.Top;
        }

        if (yLoLo > clippingRect.Bottom)
        {
            yLoLo = clippingRect.Bottom;
        }

        if (yHi < clippingRect.Top)
        {
            yHi = clippingRect.Top;
        }

        if (yHi > clippingRect.Bottom)
        {
            yHi = clippingRect.Bottom;
        }

        if (yHiHi < clippingRect.Top)
        {
            yHiHi = clippingRect.Top;
        }

        if (yHiHi > clippingRect.Bottom)
        {
            yHiHi = clippingRect.Bottom;
        }

        clippingRect = new OxyRect(clippingRect.Left, top, clippingRect.Width, yHiHi - top);

        rc.DrawClippedLine(
            clippingRect,
            pointsToRender,
            this.MinimumSegmentLength * this.MinimumSegmentLength,
            this.GetSelectableColor(this.ActualColorHiHi),
            this.StrokeThickness,
            this.ActualDashArrayHiHi,
            this.LineJoin,
            false);

        clippingRect = new OxyRect(clippingRect.Left, yHiHi, clippingRect.Width, yHi - yHiHi);

        rc.DrawClippedLine(
            clippingRect,
            pointsToRender,
            this.MinimumSegmentLength * this.MinimumSegmentLength,
            this.GetSelectableColor(this.ActualColorHi),
            this.StrokeThickness,
            this.ActualDashArrayHi,
            this.LineJoin,
            false);

        clippingRect = new OxyRect(clippingRect.Left, yHi, clippingRect.Width, yHiPre - yHi);

        rc.DrawClippedLine(
            clippingRect,
            pointsToRender,
            this.MinimumSegmentLength * this.MinimumSegmentLength,
            this.GetSelectableColor(this.ActualColorHiPre),
            this.StrokeThickness,
            this.ActualDashArrayHiPre,
            this.LineJoin,
            false);

        clippingRect = new OxyRect(clippingRect.Left, yHiPre, clippingRect.Width, yLoPre - yHiPre);

        rc.DrawClippedLine(
            clippingRect,
            pointsToRender,
            this.MinimumSegmentLength * this.MinimumSegmentLength,
            this.GetSelectableColor(this.ActualColor),
            this.StrokeThickness,
            this.ActualDashArray,
            this.LineJoin,
            false);

        clippingRect = new OxyRect(clippingRect.Left, yLoPre, clippingRect.Width, yLo - yLoPre);

        rc.DrawClippedLine(
            clippingRect,
            pointsToRender,
            this.MinimumSegmentLength * this.MinimumSegmentLength,
            this.GetSelectableColor(this.ActualColorLoPre),
            this.StrokeThickness,
            this.ActualDashArrayLoPre,
            this.LineJoin,
            false);

        clippingRect = new OxyRect(clippingRect.Left, yLo, clippingRect.Width, yLoLo - yLo);

        rc.DrawClippedLine(
            clippingRect,
            pointsToRender,
            this.MinimumSegmentLength * this.MinimumSegmentLength,
            this.GetSelectableColor(this.ActualColorLo),
            this.StrokeThickness,
            this.ActualDashArrayLo,
            this.LineJoin,
            false);

        clippingRect = new OxyRect(clippingRect.Left, yLoLo, clippingRect.Width, bottom - yLoLo);

        rc.DrawClippedLine(
            clippingRect,
            pointsToRender,
            this.MinimumSegmentLength * this.MinimumSegmentLength,
            this.GetSelectableColor(this.ActualColorLoLo),
            this.StrokeThickness,
            this.ActualDashArrayLoLo,
            this.LineJoin,
            false);
     }
}

}

Body:
After reading and struggling with the oxyplot source code in two days, I finally modify the existing oxyplot RangeColorAxis.cs and also make a wpf wrapper. After these actions I can get following images by using the 2 rebuilt dll(OxyPlot.dll and Oxyplot.Wpf.dll) files.

LineSeries with axis value based range colors

Modified RangeColorAxis.cs

namespace OxyPlot.Axes
{
    using System;
    using System.Collections.Generic;

    /// <summary>
    /// Represents a color axis that contains colors for specified ranges.
    /// </summary>
    public class RangeColorAxis : LinearAxis, IColorAxis
    {
        /// <summary>
        /// The ranges
        /// </summary>
        private readonly List<ColorRange> ranges = new List<ColorRange>();

        /// <summary>
        /// Initializes a new instance of the <see cref="RangeColorAxis" /> class.
        /// </summary>
        public RangeColorAxis()
        {
            this.Position = AxisPosition.None;
            this.AxisDistance = 20;

            this.LowColor = OxyColors.Undefined;
            this.HighColor = OxyColors.Undefined;
            this.InvalidNumberColor = OxyColors.Gray;

            this.IsPanEnabled = false;
            this.IsZoomEnabled = false;
        }

        /// <summary>
        /// Gets or sets the color used to represent NaN values.
        /// </summary>
        /// <value>A <see cref="OxyColor" /> that defines the color. The default value is <c>OxyColors.Gray</c>.</value>
        public OxyColor InvalidNumberColor { get; set; }

        /// <summary>
        /// Gets or sets the color of values above the maximum value.
        /// </summary>
        /// <value>The color of the high values.</value>
        public OxyColor HighColor { get; set; }

        /// <summary>
        /// Gets or sets the color of values below the minimum value.
        /// </summary>
        /// <value>The color of the low values.</value>
        public OxyColor LowColor { get; set; }

        /// <summary>
        /// Adds a range.
        /// </summary>
        /// <param name="lowerBound">The lower bound.</param>
        /// <param name="upperBound">The upper bound.</param>
        /// <param name="color">The color.</param>
        public void AddRange(double lowerBound, double upperBound, OxyColor color)
        {
            this.ranges.Add(new ColorRange { LowerBound = lowerBound, UpperBound = upperBound, Color = color });
        }

        /// <summary>
        /// Clears the ranges.
        /// </summary>
        public void ClearRanges()
        {
            this.ranges.Clear();
        }

        /// <summary>
        /// Gets the palette index of the specified value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>The palette index.</returns>
        /// <remarks>If the value is less than minimum, 0 is returned. If the value is greater than maximum, Palette.Colors.Count+1 is returned.</remarks>
        public int GetPaletteIndex(double value)
        {
            if (!this.LowColor.IsUndefined() && value < this.ranges[0].LowerBound)
            {
                return -1;
            }

            if (!this.HighColor.IsUndefined() && value > this.ranges[this.ranges.Count - 1].UpperBound)
            {
                return this.ranges.Count;
            }

            // TODO: change to binary search?
            for (int i = 0; i < this.ranges.Count; i++)
            {
                var range = this.ranges[i];
                if (range.LowerBound <= value && range.UpperBound > value)
                {
                    return i;
                }
            }

            return int.MinValue;
        }

        /// <summary>
        /// Gets the color.
        /// </summary>
        /// <param name="paletteIndex">The color map index.</param>
        /// <returns>The color.</returns>
        public OxyColor GetColor(int paletteIndex)
        {
            if (paletteIndex == int.MinValue)
            {
                return this.InvalidNumberColor;
            }

            if (paletteIndex == -1)
            {
                return this.LowColor;
            }

            if (paletteIndex == this.ranges.Count)
            {
                return this.HighColor;
            }

            return this.ranges[paletteIndex].Color;
        }

        /// <summary>
        /// Renders the axis on the specified render context.
        /// </summary>
        /// <param name="rc">The render context.</param>
        /// <param name="pass">The render pass.</param>
        public override void Render(IRenderContext rc, int pass)
        {
            if (this.Position == AxisPosition.None)
            {
                return;
            }

            if (pass == 0)
            {
                double distance = this.AxisDistance;
                double left = this.PlotModel.PlotArea.Left;
                double top = this.PlotModel.PlotArea.Top;
                double width = this.MajorTickSize - 2;
                double height = this.MajorTickSize - 2;
                double plotwidth = this.PlotModel.PlotArea.Width;
                double plotheight = this.PlotModel.PlotArea.Height;

                const int TierShift = 0;

                switch (this.Position)
                {
                    case AxisPosition.Left:
                        left = this.PlotModel.PlotArea.Left - TierShift - width - distance;
                        top = this.PlotModel.PlotArea.Top;
                        break;
                    case AxisPosition.Right:
                        left = this.PlotModel.PlotArea.Right + TierShift + distance;
                        top = this.PlotModel.PlotArea.Top;
                        break;
                    case AxisPosition.Top:
                        left = this.PlotModel.PlotArea.Left;
                        top = this.PlotModel.PlotArea.Top - TierShift - height - distance;
                        break;
                    case AxisPosition.Bottom:
                        left = this.PlotModel.PlotArea.Left;
                        top = this.PlotModel.PlotArea.Bottom + TierShift + distance;
                        break;
                }

                Action<double, double, OxyColor> drawColorRect = (ylow, yhigh, color) =>
                {
                    double ymin = Math.Min(ylow, yhigh);
                    double ymax = Math.Max(ylow, yhigh);
                    rc.DrawRectangle(
                        this.IsHorizontal()
                            ? new OxyRect(ymin, top, ymax - ymin, plotheight)
                            : new OxyRect(left, ymin, plotwidth, ymax - ymin),
                        color,
                        OxyColors.Undefined);
                };

                // if the axis is reversed then the min and max values need to be swapped.
                double effectiveMaxY = this.Transform(this.IsReversed ? this.ActualMinimum : this.ActualMaximum);
                double effectiveMinY = this.Transform(this.IsReversed ? this.ActualMaximum : this.ActualMinimum);

                foreach (ColorRange range in this.ranges)
                {
                    double ylow = this.Transform(range.LowerBound);
                    double yhigh = this.Transform(range.UpperBound);

                    if (this.IsHorizontal())
                    {
                        if (ylow < effectiveMinY)
                        {
                            ylow = effectiveMinY;
                        }

                        if (yhigh > effectiveMaxY)
                        {
                            yhigh = effectiveMaxY;
                        }
                    }
                    else
                    {
                        if (ylow > effectiveMinY)
                        {
                            ylow = effectiveMinY;
                        }

                        if (yhigh < effectiveMaxY)
                        {
                            yhigh = effectiveMaxY;
                        }
                    }

                    drawColorRect(ylow, yhigh, range.Color);
                }

                double highLowLength = 10;
                if (this.IsHorizontal())
                {
                    highLowLength *= -1;
                }

                if (!this.LowColor.IsUndefined())
                {
                    double ylow = this.Transform(this.ActualMinimum);
                    drawColorRect(ylow, ylow + highLowLength, this.LowColor);
                }

                if (!this.HighColor.IsUndefined())
                {
                    double yhigh = this.Transform(this.ActualMaximum);
                    drawColorRect(yhigh, yhigh - highLowLength, this.HighColor);
                }
            }

            var r = new HorizontalAndVerticalAxisRenderer(rc, this.PlotModel);
            r.Render(this, pass);
        }

        /// <summary>
        /// Defines a range.
        /// </summary>
        private class ColorRange
        {
            /// <summary>
            /// Gets or sets the color.
            /// </summary>
            /// <value>The color.</value>
            public OxyColor Color { get; set; }

            /// <summary>
            /// Gets or sets the lower bound.
            /// </summary>
            /// <value>The lower bound.</value>
            public double LowerBound { get; set; }

            /// <summary>
            /// Gets or sets the upper bound.
            /// </summary>
            /// <value>The upper bound.</value>
            public double UpperBound { get; set; }
        }
    }
}

WPF wrapper for RangeColorAxis.cs

namespace OxyPlot.Wpf
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Windows;
    using System.Windows.Markup;
    using System.Windows.Media;

    /// <summary>
    /// This is a WPF wrapper for the <see cref="OxyPlot.Axes.RangeColorAxis"/>
    /// </summary>
    public class RangeColorAxis : Axis
    {
        /// <summary>
        /// Identifies the <see cref="InvalidNumberColor"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty InvalidNumberColorProperty =
            DependencyProperty.Register(
                "InvalidNumberColor",
                typeof(Color),
                typeof(RangeColorAxis),
                new PropertyMetadata(Colors.Orange, AppearanceChanged));

        /// <summary>
        /// Identifies the <see cref="HighColor"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty HighColorProperty = DependencyProperty.Register(
            "HighColor", typeof(Color), typeof(RangeColorAxis), new PropertyMetadata(Colors.White, AppearanceChanged));

        /// <summary>
        /// Identifies the <see cref="LowColor"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty LowColorProperty = DependencyProperty.Register(
            "LowColor", typeof(Color), typeof(RangeColorAxis), new PropertyMetadata(Colors.Black, AppearanceChanged));

        /// <summary>
        /// Identifies the <see cref="Ranges"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty RangesProperty = DependencyProperty.Register(
            "Ranges", typeof(IList<Tuple<double, double, Color>>), typeof(RangeColorAxis), new PropertyMetadata(new List<Tuple<double,double,Color>>(), DataChanged));

        /// <summary>
        /// Initializes a new instance of the <see cref="RangeColorAxis"/> class.
        /// </summary>
        public RangeColorAxis()
        {
            this.InternalAxis = new Axes.RangeColorAxis();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="InvalidNumberColor"/> class.
        /// </summary>
        public Color InvalidNumberColor
        {
            get
            {
                return (Color)this.GetValue(InvalidNumberColorProperty);
            }

            set
            {
                this.SetValue(InvalidNumberColorProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the high color.
        /// </summary>
        public Color HighColor
        {
            get
            {
                return (Color)this.GetValue(HighColorProperty);
            }

            set
            {
                this.SetValue(HighColorProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the low color.
        /// </summary>
        public Color LowColor
        {
            get
            {
                return (Color)this.GetValue(LowColorProperty);
            }

            set
            {
                this.SetValue(LowColorProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets Labels.
        /// </summary>
        public IList<Tuple<double, double, Color>> Ranges
        {
            get
            {
                return (IList<Tuple<double, double, Color>>)this.GetValue(RangesProperty);
            }

            set
            {
                this.SetValue(RangesProperty, value);
            }
        }

        /// <summary>
        /// Creates the model.
        /// </summary>
        /// <returns>
        /// An axis object.
        /// </returns>
        public override Axes.Axis CreateModel()
        {
            this.SynchronizeProperties();
            return this.InternalAxis;
        }

        /// <summary>
        /// Synchronizes the properties.
        /// </summary>
        protected override void SynchronizeProperties()
        {
            base.SynchronizeProperties();
            var axis = this.InternalAxis as Axes.RangeColorAxis;
            Trace.Assert(axis != null);
            //if (this.GradientStops != null)
            //{
            //    axis.Palette = this.GradientStops.Count > 2
            //                       ? Interpolate(this.GradientStops.ToList(), this.PaletteSize)
            //                       : new OxyPalette();
            //}

            axis.HighColor = this.HighColor.ToOxyColor();
            axis.LowColor = this.LowColor.ToOxyColor();
            axis.InvalidNumberColor = this.InvalidNumberColor.ToOxyColor();
            axis.Minimum = this.Minimum;
            axis.Maximum = this.Maximum;
            if (Ranges != null)
            {
                axis.ClearRanges();
                foreach (var range in Ranges)
                {
                    axis.AddRange(range.Item1, range.Item2, range.Item3.ToOxyColor());
                }
            }
        }

    }
}

XAML file:

<oxyPlot:Plot.Axes>
    <oxyPlot:DateTimeAxis StringFormat="HH:mm:ss"></oxyPlot:DateTimeAxis>
    <oxyPlot:RangeColorAxis
         Ranges="{Binding ColorRanges}"
         Unit="{Binding Unit}"
         AbsoluteMinimum="{Binding DisplayMin}"
         AbsoluteMaximum="{Binding DisplayMax}"
         MinimumRange="{Binding DisplayMax}"/>
</oxyPlot:Plot.Axes>

View Model

...
/// <summary>
/// The <see cref="ColorRanges" /> property's name.
/// </summary>
public const string ColorRangesPropertyName = "ColorRanges";

private List<Tuple<double, double, System.Windows.Media.Color>> _colorRanges = new List<Tuple<double, double, System.Windows.Media.Color>>();

/// <summary>
/// Sets and gets the ColorRanges property.
/// Changes to that property's value raise the PropertyChanged event.
/// </summary>
public List<Tuple<double, double, System.Windows.Media.Color>> ColorRanges
{
    get
    {
        return _colorRanges;
    }

    set
    {
        if (_colorRanges == value)
        {
            return;
        }

        _colorRanges = value;
        RaisePropertyChanged(ColorRangesPropertyName);
    }
}
...
//usage
ColorRanges.Clear();
if (DisplayMin < LevelThresholdLoLo)
{
    ColorRanges.Add(new Tuple<double, double, Color>(DisplayMin, LevelThresholdLoLo, Color.FromArgb(127,255,68,0)));
}
if (LevelThresholdLoLo < LevelThresholdLo)
{
    ColorRanges.Add(new Tuple<double, double, Color>(LevelThresholdLoLo, LevelThresholdLo, Color.FromArgb(127, 255, 140, 0)));
}
if (LevelThresholdLo < LevelThresholdLoPre)
{
    ColorRanges.Add(new Tuple<double, double, Color>(LevelThresholdLo, LevelThresholdLoPre, Color.FromArgb(127, 65,105,225)));
}
if (LevelThresholdLoPre < LevelThresholdHiPre)
{
    ColorRanges.Add(new Tuple<double, double, Color>(LevelThresholdLoPre, LevelThresholdHiPre, Color.FromArgb(127, 50, 205, 50)));
}
if (LevelThresholdHiPre < LevelThresholdHi)
{
    ColorRanges.Add(new Tuple<double, double, Color>(LevelThresholdHiPre, LevelThresholdHi, Color.FromArgb(127, 65, 105, 225)));
}
if (LevelThresholdHi < LevelThresholdHiHi)
{
    ColorRanges.Add(new Tuple<double, double, Color>(LevelThresholdHi, LevelThresholdHiHi, Color.FromArgb(127,255,140,0)));
}
if (LevelThresholdHiHi < DisplayMax)
{
    ColorRanges.Add(new Tuple<double, double, Color>(LevelThresholdHiHi, DisplayMax, Color.FromArgb(127, 255, 68, 0)));
}


来源: stackexchange

问:
Conflicting multiple application.yml on classpath
I have this project setup:

```<code>Spring-Boot-App 1:
src/main/resources/application.yml

Dependency-Spring-Boot-App-2.jar:
src/main/resources/application.yml
</code>```

but the second application.yml gets ignored! Am I doing something wrong or is this default spring behaviour? How do I load the second application.yml so that all properties are avaiable to my app 1 ?

答: Two resources with exactly the same name on classpath. ClassLoader loads the first one so the behavior is expected.</p>

ContentLicense: CC BY-SA 3.0

Body:
I have this project setup:

Spring-Boot-App 1:
src/main/resources/application.yml

Dependency-Spring-Boot-App-2.jar:
src/main/resources/application.yml

but the second application.yml gets ignored! Am I doing something wrong or is this default spring behaviour? How do I load the second application.yml so that all properties are avaiable to my app 1 ?


问:
Can I define a macro using a macro in C?
I have a set of #defines like these:

```<code>#define MODULE1_PINMASK 0x1
#define MODULE2_PINMASK 0x2
#define MODULE3_PINMASK 0x3
</code>```

where the value of the pinmask depends on the second argument of:

```<code>#define MODULE1_PORT_PIN A,1
#define MODULE2_PORT_PIN A,2
#define MODULE3_PORT_PIN A,3
</code>```

If at any point in future, I make a change, e.g:

```<code>#define MODULE1_PORT_PIN A,1 /* changes to #define MODULE1_PORT_PIN A,4 */
</code>```

I need to also change the pinmask:

```<code>#define MODULE1_PINMASK 0x1 /* then becomes #define MODULE1_PINMASK 0x4 */
</code>```

I'm trying to automate the process by not having to manually change the pinmask. So far I've got these macros to extract the second argument of MODULEX_PORT_PIN (I don't care about the first argument in this case):

```<code>#define GET_SECOND(X, Y) Y
#define GET_PIN(PORT_PIN) GET_SECOND(PORT_PIN)
</code>```

If i use them in functions, I get the correct result, for instance:

```<code>uint8_t pinmask=0x0;

switch (GET_PIN(MODULE2_PORT_PIN))
{
    case 1:
        pinmask = 0x1;
        break;
    case 2:
        pinmask = 0x2;
        break;
    case 3:
        pinmask = 0x3;
        break;
    default:
        break;
}

printf ("%#x", pinmask); /* prints "0x2" */
</code>```

but I want to keep the pinmasks as #defines. Is there a way to implement a #define GET_PINMASK macro which uses the switch case to define the pinmask? I'm aiming for something like:

```<code>#define MODULE1_PINMASK ASSIGN_PINMASK(GET_PIN(MODULE1_PORT_PIN))
</code>```

which in this case would define MODULE1_PINMASK as 0x1.

EDIT: The second argument in #define MODULE1_PORT_PIN A,1 is an uint8_t and not a hex value and so I can't pass it directly.

答:
Have you considered using x-macros?

You start by creating an abstract #define for the list of entries:

```<code>#define CREATE_LIST() \
    ENTRY(1, A, 0x1) \
    ENTRY(2, A, 0x2) \
    ENTRY(3, A, 0x3)
</code>```

And then invoke the list for different definitions of ENTRY:

```<code>// Get the number of entries. Creates something like:
//   const uint8_t PIN_COUNT = 0 + 1 + 1 + 1;
#define ENTRY(number, x, y) + 1
const uint8_t PIN_COUNT = \
    CREATE_LIST()
;
#undef ENTRY

// Array of first parameters
#define ENTRY(number, x, y) #x ,
const char * Pin_names[PIN_COUNT] =
{
    CREATE_LIST()
};
#undef ENTRY

// Array of second parameters
#define ENTRY(number, x, y) y,
const uint8_t Pin_masks[PIN_COUNT] =
{
    CREATE_LIST()
};
#undef ENTRY

// Array of module names
#define ENTRY(number, x, y) STRINGIFY(MODULE ## number) ,
const char * Module_names[PIN_COUNT] =
{
    CREATE_LIST()
};
#undef ENTRY
</code>```

The preprocessor will expand this to something like:

```<code>const uint8_t PIN_COUNT =
    + 1 + 1 + 1
;

const char * Pin_names[PIN_COUNT] =
{
    "A" , "A" , "A" ,
};

const uint8_t Pin_masks[PIN_COUNT] =
{
    0x1, 0x2, 0x3,
};

const char * Module_names[PIN_COUNT] =
{
    "MODULE1", "MODULE2", "MODULE3"
};
</code>```

The possibilities are endless. It's less readable, but perhaps slightly more maintainable.

Body:
I have a set of #defines like these:

#define MODULE1_PINMASK 0x1
#define MODULE2_PINMASK 0x2
#define MODULE3_PINMASK 0x3

where the value of the pinmask depends on the second argument of:

#define MODULE1_PORT_PIN A,1
#define MODULE2_PORT_PIN A,2
#define MODULE3_PORT_PIN A,3

If at any point in future, I make a change, e.g:

#define MODULE1_PORT_PIN A,1 /* changes to #define MODULE1_PORT_PIN A,4 */

I need to also change the pinmask:

#define MODULE1_PINMASK 0x1 /* then becomes #define MODULE1_PINMASK 0x4 */

I'm trying to automate the process by not having to manually change the pinmask. So far I've got these macros to extract the second argument of MODULEX_PORT_PIN (I don't care about the first argument in this case):

#define GET_SECOND(X, Y) Y
#define GET_PIN(PORT_PIN) GET_SECOND(PORT_PIN)

If i use them in functions, I get the correct result, for instance:

uint8_t pinmask=0x0;

switch (GET_PIN(MODULE2_PORT_PIN))
{
    case 1:
        pinmask = 0x1;
        break;
    case 2:
        pinmask = 0x2;
        break;
    case 3:
        pinmask = 0x3;
        break;
    default:
        break;
}

printf ("%#x", pinmask); /* prints "0x2" */

but I want to keep the pinmasks as #defines. Is there a way to implement a #define GET_PINMASK macro which uses the switch case to define the pinmask? I'm aiming for something like:

#define MODULE1_PINMASK ASSIGN_PINMASK(GET_PIN(MODULE1_PORT_PIN))

which in this case would define MODULE1_PINMASK as 0x1.

EDIT: The second argument in #define MODULE1_PORT_PIN A,1 is an uint8_t and not a hex value and so I can't pass it directly.

Body:
Have you considered using x-macros?

You start by creating an abstract #define for the list of entries:

#define CREATE_LIST() \
    ENTRY(1, A, 0x1) \
    ENTRY(2, A, 0x2) \
    ENTRY(3, A, 0x3)

And then invoke the list for different definitions of ENTRY:

// Get the number of entries. Creates something like:
//   const uint8_t PIN_COUNT = 0 + 1 + 1 + 1;
#define ENTRY(number, x, y) + 1
const uint8_t PIN_COUNT = \
    CREATE_LIST()
;
#undef ENTRY

// Array of first parameters
#define ENTRY(number, x, y) #x ,
const char * Pin_names[PIN_COUNT] =
{
    CREATE_LIST()
};
#undef ENTRY

// Array of second parameters
#define ENTRY(number, x, y) y,
const uint8_t Pin_masks[PIN_COUNT] =
{
    CREATE_LIST()
};
#undef ENTRY

// Array of module names
#define ENTRY(number, x, y) STRINGIFY(MODULE ## number) ,
const char * Module_names[PIN_COUNT] =
{
    CREATE_LIST()
};
#undef ENTRY

The preprocessor will expand this to something like:

const uint8_t PIN_COUNT =
    + 1 + 1 + 1
;

const char * Pin_names[PIN_COUNT] =
{
    "A" , "A" , "A" ,
};

const uint8_t Pin_masks[PIN_COUNT] =
{
    0x1, 0x2, 0x3,
};

const char * Module_names[PIN_COUNT] =
{
    "MODULE1", "MODULE2", "MODULE3"
};

The possibilities are endless. It's less readable, but perhaps slightly more maintainable.


问:
Linking button to another page
I currently have a button

```<code>class Button extends Component{
    render(){
        return(
            <View>
                onPress= #I need this to return the second page of my app
                <Text style={styles.buttonText}>Next Page</Text>
            </View>
        )
    }
}
</code>```

What should I do to link this button to the second page of my app? Assuming I have already imported the page.

```<code>import SecondPage from './SecondPage'
</code>```

答:
use <Link> from react-router

```<code><Link to ='/href' ></Link>
</code>```

Title: Linking button to another page

Body:
I currently have a button

class Button extends Component{
    render(){
        return(
            <View>
                onPress= #I need this to return the second page of my app
                <Text style={styles.buttonText}>Next Page</Text>
            </View>
        )
    }
}

What should I do to link this button to the second page of my app? Assuming I have already imported the page.

import SecondPage from './SecondPage'

Body:
use <Link> from react-router

<Link to ='/href' ></Link>


问:
can somebody explain me why os.remove doesn't work properly?
There is a repository with folders and images inside these folders. The point is that I cant figure out how this method os.remove works. In some folders it removes unneeded files , in some doesn't, also some folders is shrinking in sizes ( 10-15 images ), some isn't. What am I missing here? </p>

```<code>dirs = next(os.walk(path))[1]

for d in dirs:
    dirPath = path  + d
    os.chdir(dirPath)

    dirPath = path  + d

    files = next(os.walk(dirPath))[2]

    for f in files:
        if f is 'feature.bin': os.remove('feature.bin')
        if f is 'filelist_LBP.txt': os.remove('filelist_LBP.txt')
        if f is 'info.txt': os.remove('info.txt')
</code>```

答: os.remove needs the full path to the file to be deleted, unless it happens to be in the current directory.

Body:
There is a repository with folders and images inside these folders. The point is that I cant figure out how this method os.remove works. In some folders it removes unneeded files , in some doesn't, also some folders is shrinking in sizes ( 10-15 images ), some isn't. What am I missing here?

dirs = next(os.walk(path))[1]

for d in dirs:
    dirPath = path  + d
    os.chdir(dirPath)

    dirPath = path  + d

    files = next(os.walk(dirPath))[2]

    for f in files:
        if f is 'feature.bin': os.remove('feature.bin')
        if f is 'filelist_LBP.txt': os.remove('filelist_LBP.txt')
        if f is 'info.txt': os.remove('info.txt')


问:
How can I write a piece of Java an code that checks if any character of a string is convertible to an integer between 0 and 9?
How can I write a piece of Java code that checks if a string is convertible to an integer, that is if any character of it is convertible to an integer between 0 and 9 ? I thought of something like this:

```<code>String s = "...";

for (int i = 0; i < s.length(); i++)

{

    int h = Integer.parseInt(s.substring(i, i + 1));
    if (h < 0 || h > 9)
        throw new IntegerFormatException();
}

catch (IntegerFormatException e)

{

    System.out.println("This is not an integer");

}
</code>```

where IntegerFormat Exception is something like

```<code>public class IntegerFormatException extends Exception

{

    public IntegerFormatException()
    {
        super ("This string isn't convertible to  an integer");
    }
    public IntegerFormatException(String message)
    {
        super (message);
    }

}
</code>```

But if I then try the code with, say, "8&35" as the string I don't get my message "This is not an integer", but I get and IDE automatic red ink message stating

Exception in thread "main" java.lang.NumberFormatException: For input string: "&"

```<code>at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:569)
at java.lang.Integer.parseInt(Integer.java:615)
at project.pkg9.pkg2.Project92.main(Project92.java:60)
</code>```

Java Result: 1

Is my code wrong ? If yes, how can I fix it ? Many thanks in advance for all your answers.

答:
That's because Integer.parseInt will throw a NumberFormatException exception if you try to parse something that's not an int, and you don't catch that in your try/catch block. You could catch that in your catch block or use a regex to check what the character is at that location before you try to parse (or, as pointed out in the comments, Character.isDigit()).

Also, there's no need to see if a single digit is less than 0 or greater than 9 - how could a single digit possibly be anything but an integer in the range of 0 - 9? This won't really tell you if the character is a valid int or not because, unless you're comparing the ASCII values, it doesn't make sense to talk about whether & is greater than 9, for example.

Body:
How can I write a piece of Java code that checks if a string is convertible to an integer, that is if any character of it is convertible to an integer between 0 and 9 ? I thought of something like this:

String s = "...";

for (int i = 0; i < s.length(); i++)

{

    int h = Integer.parseInt(s.substring(i, i + 1));
    if (h < 0 || h > 9)
        throw new IntegerFormatException();
}

catch (IntegerFormatException e)

{

    System.out.println("This is not an integer");

}

where IntegerFormat Exception is something like

public class IntegerFormatException extends Exception

{

    public IntegerFormatException()
    {
        super ("This string isn't convertible to  an integer");
    }
    public IntegerFormatException(String message)
    {
        super (message);
    }

}

But if I then try the code with, say, "8&35" as the string I don't get my message "This is not an integer", but I get and IDE automatic red ink message stating

Exception in thread "main" java.lang.NumberFormatException: For input string: "&"

at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:569)
at java.lang.Integer.parseInt(Integer.java:615)
at project.pkg9.pkg2.Project92.main(Project92.java:60)

Java Result: 1

Is my code wrong ? If yes, how can I fix it ? Many thanks in advance for all your answers.


问:
Advanced Custom Fields (ACF Pro) + Slick Slider + Wordpress
I am using ACF Pro to make a slider carousel with Slick Slider. I can get it to work with a basic gallery field but I am not even getting it to show when I try to display a repeater field with several sub fields. I am not sure exactly what I am doing wrong but I have been playing with this for a while, and I feel like I am kinda' half there.

Working PHP

```<code><!-- Slider 1 -->

<?php
//Fields
//slider_portfolio = Gallery Field

  $images = get_field('slider_portfolio');

  if( $images ): ?>

  <div class="slider-for">

  <?php foreach( $images as $image ): ?>

  <div class="slick-container">
    <img src="<?php echo $image['url']; ?>" alt="<?php echo $image['alt']; ?>" />
  </div>

  <?php endforeach; ?>

  </div>

<?php endif;  ?>
</code>```

Non-Working PHP

This is the version I am trying to get to work. It is currently one image sub field inside a repeater field.

Fields:

slider_image = field (repeater field)

portfolio_slider = subfield (image field)

```<code><!-- Slider 2 -->

        <?php
        //Image Slider
        //slider_image = field (repeater field)
        //portfolio_slider = subfield (image field)

        function agero_slider() {

          if( have_rows('slider_image') ):
              echo '<div class="slider-for">';
             // loop through the rows of data

          while ( have_rows('slider_image') ) : the_row();

             // display a sub field value
             //vars
             $image = get_sub_field('portfolio_slider');
          ?>

          <div><img src="<?php echo $image['url']; ?>"/></div>

        <?php

          endwhile;
            echo '</div>
             <div class="slider-nav">';
             // loop through the rows of data
          while ( have_rows('slider_image') ) : the_row();
             // display a sub field value
             //vars
          $image = get_sub_field('portfolio_slider');

        ?>

        <div><img src="<?php echo $image['url']; ?>"/></div>

        <?php
          endwhile;
            echo '</div>';
          else :
             // no rows found
          endif;
        }

        ?>
</code>```

JS Code
This works, even though I need to build on it.

```<code>jQuery(document).ready(function($){
$('.slider-for').slick({
   slidesToShow: 1,
   slidesToScroll: 1,
   dots: true,
   arrows: false,
   asNavFor: '.slider-for',
   focusOnSelect: true,
   fade: true,
   autoplay: false
  });
});
</code>```

I'm not sure why the first code is working but the second is not.

Relevant links:

ACF - https://www.advancedcustomfields.com/resources/code-examples/

Slick - http://kenwheeler.github.io/slick/

The Tutorial that I am using as a rough guide to get started -
 http://wpbeaches.com/coding-a-slider-with-slick-and-acf-pro-in-wordpress/

If anyone can suggest what I am doing wrong or maybe suggest a concrete way to display multiple custom fields within a multi slide carousel where the text fields change with each slide image. Once I get this working I can expand it by making each repeater field a slide that can be updated through the UI.

I think maybe I am going about this wrong. Maybe I need to add everything inside a flexible content field or something? Not sure right now, but the second example seems like it should work.

答:
Fields:

slider_image = field (repeater field)

portfolio_slider = subfield (image field)

ACF repeater image Code:

```<code><?php
if( have_rows('slider_image',get_the_ID()) ) {

    if( have_rows('slider_image',get_the_ID()) ):
    while ( have_rows('slider_image',get_the_ID()) ) : the_row();
        ?>
        <img src="<?php echo get_sub_field('portfolio_slider', get_the_ID()); ?>"/>
        <?php
    endwhile;
    endif;

}
?>
</code>```

Body:
I am using ACF Pro to make a slider carousel with Slick Slider. I can get it to work with a basic gallery field but I am not even getting it to show when I try to display a repeater field with several sub fields. I am not sure exactly what I am doing wrong but I have been playing with this for a while, and I feel like I am kinda' half there.

Working PHP

<?php
//Fields
//slider_portfolio = Gallery Field

  $images = get_field('slider_portfolio');

  if( $images ): ?>

  <?php foreach( $images as $image ): ?>

    <img src="<?php echo $image['url']; ?>" alt="<?php echo $image['alt']; ?>" />

  <?php endforeach; ?>

<?php endif;  ?>

Non-Working PHP

This is the version I am trying to get to work. It is currently one image sub field inside a repeater field.

Fields:

slider_image = field (repeater field)

portfolio_slider = subfield (image field)

        <?php
        //Image Slider
        //slider_image = field (repeater field)
        //portfolio_slider = subfield (image field)

        function agero_slider() {

          if( have_rows('slider_image') ):
              echo '
';
             // loop through the rows of data

          while ( have_rows('slider_image') ) : the_row();

             // display a sub field value
             //vars
             $image = get_sub_field('portfolio_slider');
          ?>

<img src="<?php echo $image['url']; ?>"/>

        <?php

          endwhile;
            echo '

';
             // loop through the rows of data
          while ( have_rows('slider_image') ) : the_row();
             // display a sub field value
             //vars
          $image = get_sub_field('portfolio_slider');

        ?>

<img src="<?php echo $image['url']; ?>"/>

        <?php
          endwhile;
            echo '
';
          else :
             // no rows found
          endif;
        }

        ?>

JS Code
This works, even though I need to build on it.

jQuery(document).ready(function($){
$('.slider-for').slick({
   slidesToShow: 1,
   slidesToScroll: 1,
   dots: true,
   arrows: false,
   asNavFor: '.slider-for',
   focusOnSelect: true,
   fade: true,
   autoplay: false
  });
});

I'm not sure why the first code is working but the second is not.

Relevant links:

ACF - https://www.advancedcustomfields.com/resources/code-examples/

Slick - http://kenwheeler.github.io/slick/

The Tutorial that I am using as a rough guide to get started -
 http://wpbeaches.com/coding-a-slider-with-slick-and-acf-pro-in-wordpress/

If anyone can suggest what I am doing wrong or maybe suggest a concrete way to display multiple custom fields within a multi slide carousel where the text fields change with each slide image. Once I get this working I can expand it by making each repeater field a slide that can be updated through the UI.

I think maybe I am going about this wrong. Maybe I need to add everything inside a flexible content field or something? Not sure right now, but the second example seems like it should work.

Body:
Fields:

slider_image = field (repeater field)

portfolio_slider = subfield (image field)

ACF repeater image Code:

<?php
if( have_rows('slider_image',get_the_ID()) ) {

    if( have_rows('slider_image',get_the_ID()) ):
    while ( have_rows('slider_image',get_the_ID()) ) : the_row();
        ?>
        <img src="<?php echo get_sub_field('portfolio_slider', get_the_ID()); ?>"/>
        <?php
    endwhile;
    endif;

}
?>