简体   繁体   English

C#WinForms应用程序:堆积图中的双色列

[英]C# WinForms application: dual-color column in stacked chart

I am an hobbyist .NET developer. 我是业余爱好者.NET开发人员。 I am developing a Windows Forms app and this picture shows want I want to use a chart control for: 我正在开发Windows窗体应用程序,此图所示,我希望将图表控件用于: 图表

Basically, I want to change the upper part of every column which is taller than a certain threshold (400 in the example above). 基本上,我想更改每列的上半部分,该部分的高度大于某个阈值(在上面的示例中为400)。 I have searched around a bit, but no joy yet. 我搜索了一下,但还没有发现喜悦。 Any ideas? 有任何想法吗?

EDIT: I have a graceful workaround, but it's still frustrating not to have something available in the control itself. 编辑:我有一个不错的解决方法,但仍然令人沮丧的是,控件本身中没有可用的东西。 I have created two series, red and blue. 我创建了两个系列,红色和蓝色。 When I add a point I check if the height is bigger than the threshold. 添加点时,我检查高度是否大于阈值。 If yes, I add the point to the red series, and I also add a point of threshold height to the blue series. 如果是,则将点添加到红色序列中,还将阈值高度的点添加到蓝色序列中。 If not, I add it to the blue series as is. 如果没有,我将其原样添加到蓝色系列中。 The code can explain better than me: 该代码可以比我更好地解释:

    private void AddPointToChart(Chart chart, int x, int y)
    {
        if (this.threshold < y)
        {
            chart.Series[1].Points.AddXY(x, y);
            y = this.threshold;
        }

        chart.Series[0].Points.AddXY(x, y);
    }

As per the original question, StackedColumn is the way to go! 按照最初的问题,StackedColumn是必经之路!

And for your edit, on option (not an easy one) is to override virtual methods of Chart to add your own behaviour. 对于您的编辑,on选项(不是一个简单的选择)是重写Chart的虚拟方法以添加您自己的行为。 I came up with an example after some experimentation: 经过一些试验,我想出了一个例子:

public class ThresholdColumnChart : Chart
{
    private double _threshold = 50d;

    public double Threshold
    {
        get { return _threshold; }
        set { _threshold = value; Invalidate(); }
    }

    public ThresholdColumnChart() : base() { }

    protected override void OnCustomize()
    {
        base.OnCustomize();

        if (Series.Count != 1)
            return;

        Series.Add(new Series());

        foreach (var dataPoint in Series[0].Points)
        {
            var newDataPoint = new DataPoint();

            newDataPoint.XValue = dataPoint.XValue;
            newDataPoint.YValues[0] = (dataPoint.YValues[0] > _threshold ? 
                 dataPoint.YValues[0] - _threshold : 0);

            Series[1].Points.Add(newDataPoint);

            if (dataPoint.YValues[0] > _threshold)
                dataPoint.YValues[0] = _threshold;
        }

        Series[0].ChartType = SeriesChartType.StackedColumn;
        Series[1].ChartType = SeriesChartType.StackedColumn;
        Series[1].Color = Color.Red;
    }

    protected override void OnPostPaint(ChartPaintEventArgs e)
    {
        base.OnPostPaint(e);

        if (!(e.ChartElement is ThresholdBarChart))
            return;

        if (Series.Count != 2)
            return;

        for (int i = 0; i < Series[0].Points.Count; i++)
            Series[0].Points[i].YValues[0] += Series[1].Points[i].YValues[0];

        Series.Remove(Series[1]);
    }
}

In short the OnCustomize(...) method is called just before the chart is drawn (before OnPrePaint(...) ) at which point it creates a second series to be used for drawing. 简而言之,就在绘制图表之前(在OnPrePaint(...)之前OnCustomize(...)调用OnCustomize(...)方法,此时它将创建第二个用于绘制的系列。 The new series is constructed with the threshold in mind, and the first series is reduced not to exceed the threshold just like the example in your edit. 构造新系列时要牢记阈值,并且减少第一个系列以使其不超过阈值,就像您编辑中的示例一样。

After the chart is done painting OnPostPaint(...) will be called and the first series will be restored to it's original values, and the "extra" series is removed. 图表绘制完成后,将调用OnPostPaint(...)绘画,第一个系列将恢复为其原始值,然后删除“多余”系列。

Both OnPrePaint(...) and OnPostPaint are actually called multiple times when a chart is drawn, hence why I had to put if (!(e.ChartElement is ThresholdBarChart)) return; 实际上,绘制图表时会多次调用OnPrePaint(...)OnPostPaint ,因此为什么我必须放置if (!(e.ChartElement is ThresholdBarChart)) return; in; 在; to make sure we only remove the series once the chart has finnished painting. 以确保我们仅在图表完成绘画后才删除该系列。

After adding the code and compiling once you will get a new usercontrol added to the design toolbox called "ThresholdColumnChart". 添加代码并进行编译后,您将获得一个名为“ ThresholdColumnChart”的新用户控件,添加到设计工具箱中。 You can set the threshold from the Property "Threshold" (also in design). 您可以从属性“阈值”(也在设计中)设置阈值。 I wouldnt trust this code with my life but it should serve as a starting point. 我一生都不会相信此代码,但是它应该作为起点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM