【问题标题】:Subclassing .NET Chart Control子类化 .NET 图表控件
【发布时间】:2016-08-23 12:03:14
【问题描述】:

我创建了 System.Windows.Forms.DataVisualization.Charting.Chart 的子类。在构造函数中,我设置了默认图表区域和系列:

System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series();

chartArea1.AxisX.Title = "Time (s)";
chartArea1.AxisY.Title = "Value(%)";
chartArea1.Name = "MainChartArea";
series1.ChartArea = "MainChartArea";
series1.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.FastLine;
series1.Name = "Series1";
Series.Add(series1);

我在子类中添加了一组函数以使用 ChartAreas[0]。这一切都很好。

现在在 VS2010 中我创建了一个新控件,转到工具箱并添加我的自定义图表控件。似乎发生的是 VS 将我的默认图表区域和系列复制到父控件的 InitializeComponent 函数。

当我执行代码时,父控件的 InitializeComponent 函数内部出现异常,表示图表的子类已经有一个名为“MainChartArea”的图表区域,并且已经有一个名为“Series1”的系列。

如果我现在编辑父控件 InitializeComponent 代码以更改其构建和运行的名称就可以了。

但是,如果我现在返回并对父控件进行任何更改,VS 会再次重新复制默认图表区域和系列设置,导致同样的问题。

我知道我可以简单地从父控件的 InitializeComponent 函数中删除代码,但是我在图表控件的设计器中没有得到可视化的表示,并且手动编辑它似乎是一种不好的做法。

对 Chart 控件进行子类化以便在子类上设置区域和系列的正确方法是什么?

【问题讨论】:

  • 具有花哨设计的控件,如 Chart,当您从它们派生时往往会出现行为不端。他们的设计师无法区分您在构造函数中添加的系列与您使用设计师添加的任何系列之间的区别。因此,它也会尽职地序列化您在构造函数中创建的那个。当您在设计器中创建一个系列时,您不太可能希望这样做。更糟糕的是,您的构造函数 also 在运行时运行,现在您有 两个 您不想要的系列。解决这个问题需要与设计师一起修补。完全不切实际,它没有记录并且非常复杂。别再帮忙了。
  • 谢谢。我也很害怕。

标签: c# .net winforms


【解决方案1】:

为了实现您的目标,您需要定义一个派生自System.Windows.Forms.Design.ControlDesigner 的类,并将其指定为您的自定义图表类的设计器。所有初始ChartAreaSeriesLegend 的创建都应在ControlDesigner 类方法InitializeNewComponent 中执行,而不是在自定义图表的构造函数中执行。

using System;
using System.Threading.Tasks;
using System.Windows.Forms.DataVisualization.Charting;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
    [System.ComponentModel.Designer(typeof(MyChartDesigner))]
    public class MyChart : Chart
    {
    }

    // Add Project Ref:  System.Design
    internal class MyChartDesigner : System.Windows.Forms.Design.ControlDesigner
    {
        public override void InitializeNewComponent(System.Collections.IDictionary defaultValues)
        {
            if ((this.Control != null) && this.Control is Chart)
            {
                Chart control = (Chart)this.Control;
                if ((control.ChartAreas.Count == 0) && (control.Series.Count == 0))
                {
                    ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
                    Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series();

                    chartArea1.AxisX.Title = "Time (s)";
                    chartArea1.AxisY.Title = "Value(%)";
                    chartArea1.Name = "MainChartArea";
                    series1.ChartArea = "MainChartArea";
                    series1.ChartType = SeriesChartType.FastLine;
                    series1.Name = "Series1";

                    control.ChartAreas.Add(chartArea1);
                    control.Series.Add(series1);
                }
            }
            base.InitializeNewComponent(defaultValues);
        }
    }
}

【讨论】:

    【解决方案2】:

    如果您只想更改一些属性,解决方法可能是创建一个包含图表的UserControl,然后将一些属性添加到该控件以根据需要修改图表。在实践中,只有当您有很多常见更改但很少有特定更改时,这才有用。

    或者,您可能有一个辅助类,您可以在加载表单时调用它,并在运行时应用一些更改。设计器不会显示图表的实际外观。

    正如评论中提到的,当您从它们派生时,并非所有控件(在设计器中)都按预期运行。通过编写大量代码来处理设计时编辑和序列化可能可以解决一些问题,但我基本上没有这方面的经验。

    通常,如果控件必须管理子控件或列表,则从该控件派生可能会导致问题...对于简单的控件,通常它可能只是不太理想,因为某些属性可能会设置两次...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-26
      • 1970-01-01
      • 2013-06-17
      • 2015-11-16
      • 2015-05-01
      相关资源
      最近更新 更多