+ UILineChart:完成曲线图表初版

This commit is contained in:
Sunny 2020-10-04 11:19:55 +08:00
parent 5b3d940da0
commit 552d683df3
32 changed files with 844 additions and 637 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

154
SunnyUI.Demo/Charts/FLineChart.Designer.cs generated Normal file
View File

@ -0,0 +1,154 @@
namespace Sunny.UI.Demo.Charts
{
partial class FLineChart
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.uiSymbolButton1 = new Sunny.UI.UISymbolButton();
this.uiImageButton3 = new Sunny.UI.UIImageButton();
this.uiImageButton2 = new Sunny.UI.UIImageButton();
this.uiImageButton1 = new Sunny.UI.UIImageButton();
this.uiLine1 = new Sunny.UI.UILine();
this.uiLineChart1 = new Sunny.UI.UILineChart();
this.PagePanel.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.uiImageButton3)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.uiImageButton2)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.uiImageButton1)).BeginInit();
this.SuspendLayout();
//
// PagePanel
//
this.PagePanel.Controls.Add(this.uiSymbolButton1);
this.PagePanel.Controls.Add(this.uiImageButton3);
this.PagePanel.Controls.Add(this.uiImageButton2);
this.PagePanel.Controls.Add(this.uiImageButton1);
this.PagePanel.Controls.Add(this.uiLine1);
this.PagePanel.Controls.Add(this.uiLineChart1);
this.PagePanel.Size = new System.Drawing.Size(800, 539);
//
// uiSymbolButton1
//
this.uiSymbolButton1.Cursor = System.Windows.Forms.Cursors.Hand;
this.uiSymbolButton1.Font = new System.Drawing.Font("微软雅黑", 12F);
this.uiSymbolButton1.Location = new System.Drawing.Point(348, 466);
this.uiSymbolButton1.MinimumSize = new System.Drawing.Size(1, 1);
this.uiSymbolButton1.Name = "uiSymbolButton1";
this.uiSymbolButton1.Padding = new System.Windows.Forms.Padding(28, 0, 0, 0);
this.uiSymbolButton1.Size = new System.Drawing.Size(100, 27);
this.uiSymbolButton1.Symbol = 61952;
this.uiSymbolButton1.TabIndex = 34;
this.uiSymbolButton1.Text = "数据";
//
// uiImageButton3
//
this.uiImageButton3.Cursor = System.Windows.Forms.Cursors.Hand;
this.uiImageButton3.Font = new System.Drawing.Font("微软雅黑", 12F);
this.uiImageButton3.Image = global::Sunny.UI.Demo.Properties.Resources.ChartDarkStyle;
this.uiImageButton3.Location = new System.Drawing.Point(242, 466);
this.uiImageButton3.Name = "uiImageButton3";
this.uiImageButton3.Size = new System.Drawing.Size(100, 27);
this.uiImageButton3.TabIndex = 33;
this.uiImageButton3.TabStop = false;
this.uiImageButton3.Text = " Dark";
this.uiImageButton3.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// uiImageButton2
//
this.uiImageButton2.Cursor = System.Windows.Forms.Cursors.Hand;
this.uiImageButton2.Font = new System.Drawing.Font("微软雅黑", 12F);
this.uiImageButton2.Image = global::Sunny.UI.Demo.Properties.Resources.ChartPlainStyle;
this.uiImageButton2.Location = new System.Drawing.Point(136, 466);
this.uiImageButton2.Name = "uiImageButton2";
this.uiImageButton2.Size = new System.Drawing.Size(100, 27);
this.uiImageButton2.TabIndex = 32;
this.uiImageButton2.TabStop = false;
this.uiImageButton2.Text = " Plain";
this.uiImageButton2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// uiImageButton1
//
this.uiImageButton1.Cursor = System.Windows.Forms.Cursors.Hand;
this.uiImageButton1.Font = new System.Drawing.Font("微软雅黑", 12F);
this.uiImageButton1.Image = global::Sunny.UI.Demo.Properties.Resources.ChartDefaultStyle;
this.uiImageButton1.Location = new System.Drawing.Point(30, 466);
this.uiImageButton1.Name = "uiImageButton1";
this.uiImageButton1.Size = new System.Drawing.Size(100, 27);
this.uiImageButton1.TabIndex = 31;
this.uiImageButton1.TabStop = false;
this.uiImageButton1.Text = " Default";
this.uiImageButton1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// uiLine1
//
this.uiLine1.Font = new System.Drawing.Font("微软雅黑", 12F);
this.uiLine1.Location = new System.Drawing.Point(30, 20);
this.uiLine1.MinimumSize = new System.Drawing.Size(16, 16);
this.uiLine1.Name = "uiLine1";
this.uiLine1.Size = new System.Drawing.Size(670, 20);
this.uiLine1.TabIndex = 30;
this.uiLine1.Text = "UIBarChart";
this.uiLine1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// uiLineChart1
//
this.uiLineChart1.FillColor = System.Drawing.Color.FromArgb(((int)(((byte)(244)))), ((int)(((byte)(244)))), ((int)(((byte)(244)))));
this.uiLineChart1.Font = new System.Drawing.Font("微软雅黑", 12F);
this.uiLineChart1.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(54)))), ((int)(((byte)(54)))), ((int)(((byte)(54)))));
this.uiLineChart1.Location = new System.Drawing.Point(30, 48);
this.uiLineChart1.MinimumSize = new System.Drawing.Size(1, 1);
this.uiLineChart1.Name = "uiLineChart1";
this.uiLineChart1.Option = null;
this.uiLineChart1.Size = new System.Drawing.Size(670, 400);
this.uiLineChart1.TabIndex = 35;
this.uiLineChart1.Text = "uiLineChart1";
//
// FLineChart
//
this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 21F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 574);
this.Name = "FLineChart";
this.Symbol = 61953;
this.Text = "LineChart";
this.PagePanel.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.uiImageButton3)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.uiImageButton2)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.uiImageButton1)).EndInit();
this.ResumeLayout(false);
}
#endregion
private UISymbolButton uiSymbolButton1;
private UIImageButton uiImageButton3;
private UIImageButton uiImageButton2;
private UIImageButton uiImageButton1;
private UILine uiLine1;
private UILineChart uiLineChart1;
}
}

View File

@ -0,0 +1,10 @@
namespace Sunny.UI.Demo.Charts
{
public partial class FLineChart : UITitlePage
{
public FLineChart()
{
InitializeComponent();
}
}
}

View File

@ -93,6 +93,7 @@
this.uiLight1.CenterColor = System.Drawing.Color.FromArgb(((int)(((byte)(239)))), ((int)(((byte)(248)))), ((int)(((byte)(232)))));
this.uiLight1.Font = new System.Drawing.Font("微软雅黑", 12F);
this.uiLight1.Location = new System.Drawing.Point(30, 52);
this.uiLight1.MinimumSize = new System.Drawing.Size(1, 1);
this.uiLight1.Name = "uiLight1";
this.uiLight1.Radius = 35;
this.uiLight1.Size = new System.Drawing.Size(35, 35);
@ -115,6 +116,7 @@
this.uiLight2.CenterColor = System.Drawing.Color.FromArgb(((int)(((byte)(239)))), ((int)(((byte)(248)))), ((int)(((byte)(232)))));
this.uiLight2.Font = new System.Drawing.Font("微软雅黑", 12F);
this.uiLight2.Location = new System.Drawing.Point(114, 52);
this.uiLight2.MinimumSize = new System.Drawing.Size(1, 1);
this.uiLight2.Name = "uiLight2";
this.uiLight2.Radius = 35;
this.uiLight2.Size = new System.Drawing.Size(35, 35);
@ -127,6 +129,7 @@
this.uiLight3.CenterColor = System.Drawing.Color.FromArgb(((int)(((byte)(239)))), ((int)(((byte)(248)))), ((int)(((byte)(232)))));
this.uiLight3.Font = new System.Drawing.Font("微软雅黑", 12F);
this.uiLight3.Location = new System.Drawing.Point(156, 52);
this.uiLight3.MinimumSize = new System.Drawing.Size(1, 1);
this.uiLight3.Name = "uiLight3";
this.uiLight3.Radius = 35;
this.uiLight3.Size = new System.Drawing.Size(35, 35);
@ -159,6 +162,7 @@
//
this.uiProgressIndicator1.Font = new System.Drawing.Font("微软雅黑", 12F);
this.uiProgressIndicator1.Location = new System.Drawing.Point(30, 298);
this.uiProgressIndicator1.MinimumSize = new System.Drawing.Size(1, 1);
this.uiProgressIndicator1.Name = "uiProgressIndicator1";
this.uiProgressIndicator1.Size = new System.Drawing.Size(119, 132);
this.uiProgressIndicator1.TabIndex = 26;
@ -180,6 +184,7 @@
this.uiTrackBar1.DisableColor = System.Drawing.Color.Silver;
this.uiTrackBar1.Font = new System.Drawing.Font("微软雅黑", 12F);
this.uiTrackBar1.Location = new System.Drawing.Point(381, 136);
this.uiTrackBar1.MinimumSize = new System.Drawing.Size(1, 1);
this.uiTrackBar1.Name = "uiTrackBar1";
this.uiTrackBar1.Size = new System.Drawing.Size(158, 29);
this.uiTrackBar1.TabIndex = 30;
@ -205,6 +210,7 @@
this.uiLight4.CenterColor = System.Drawing.Color.FromArgb(((int)(((byte)(239)))), ((int)(((byte)(248)))), ((int)(((byte)(232)))));
this.uiLight4.Font = new System.Drawing.Font("微软雅黑", 12F);
this.uiLight4.Location = new System.Drawing.Point(72, 52);
this.uiLight4.MinimumSize = new System.Drawing.Size(1, 1);
this.uiLight4.Name = "uiLight4";
this.uiLight4.OnColor = System.Drawing.Color.FromArgb(((int)(((byte)(230)))), ((int)(((byte)(80)))), ((int)(((byte)(80)))));
this.uiLight4.Radius = 35;
@ -256,7 +262,6 @@
this.uiLedBulb4.BlinkInterval = 500;
this.uiLedBulb4.Location = new System.Drawing.Point(507, 52);
this.uiLedBulb4.Name = "uiLedBulb4";
this.uiLedBulb4.On = false;
this.uiLedBulb4.Size = new System.Drawing.Size(32, 32);
this.uiLedBulb4.TabIndex = 41;
this.uiLedBulb4.Text = "uiLedBulb4";
@ -278,6 +283,7 @@
this.uiScrollingText1.Font = new System.Drawing.Font("微软雅黑", 12F);
this.uiScrollingText1.ForeColor = System.Drawing.Color.Red;
this.uiScrollingText1.Location = new System.Drawing.Point(381, 215);
this.uiScrollingText1.MinimumSize = new System.Drawing.Size(1, 1);
this.uiScrollingText1.Name = "uiScrollingText1";
this.uiScrollingText1.ScrollingType = Sunny.UI.UIScrollingText.UIScrollingType.LeftToRight;
this.uiScrollingText1.Size = new System.Drawing.Size(319, 35);
@ -292,6 +298,7 @@
this.uiScrollingText2.Font = new System.Drawing.Font("微软雅黑", 12F);
this.uiScrollingText2.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(80)))), ((int)(((byte)(160)))), ((int)(((byte)(255)))));
this.uiScrollingText2.Location = new System.Drawing.Point(381, 256);
this.uiScrollingText2.MinimumSize = new System.Drawing.Size(1, 1);
this.uiScrollingText2.Name = "uiScrollingText2";
this.uiScrollingText2.Size = new System.Drawing.Size(319, 35);
this.uiScrollingText2.TabIndex = 49;
@ -369,7 +376,6 @@
this.uiToolTip1.Font = new System.Drawing.Font("微软雅黑", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.uiToolTip1.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(239)))), ((int)(((byte)(239)))), ((int)(((byte)(239)))));
this.uiToolTip1.OwnerDraw = true;
this.uiToolTip1.ToolTipTitle = "ToolTip title";
//
// FOther
//

View File

@ -123,9 +123,6 @@
<metadata name="timer1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="uiToolTip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>107, 17</value>
</metadata>
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>35</value>
</metadata>

View File

@ -57,6 +57,7 @@ namespace Sunny.UI.Demo
Aside.CreateChildNode(parent, AddPage(new FDoughnutChart()));
Aside.CreateChildNode(parent, AddPage(new FBarChart()));
Aside.CreateChildNode(parent, AddPage(new FBarChartEx()));
Aside.CreateChildNode(parent, AddPage(new FLineChart()));
Header.SetNodeSymbol(Header.Nodes[3], 61502);
var styles = UIStyles.PopularStyles();

View File

@ -65,6 +65,12 @@
<Compile Include="Charts\FDoughnutChart.Designer.cs">
<DependentUpon>FDoughnutChart.cs</DependentUpon>
</Compile>
<Compile Include="Charts\FLineChart.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Charts\FLineChart.Designer.cs">
<DependentUpon>FLineChart.cs</DependentUpon>
</Compile>
<Compile Include="Controls\FAvatar.cs">
<SubType>Form</SubType>
</Compile>
@ -310,6 +316,9 @@
<EmbeddedResource Include="Charts\FBarChartEx.resx">
<DependentUpon>FBarChartEx.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Charts\FLineChart.resx">
<DependentUpon>FLineChart.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Controls\FAvatar.resx">
<DependentUpon>FAvatar.cs</DependentUpon>
</EmbeddedResource>

View File

@ -39,46 +39,37 @@ namespace Sunny.UI
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
CalcData(BarOption);
CalcData();
}
protected override void CalcData(UIOption option)
protected override void CalcData()
{
Bars.Clear();
NeedDraw = false;
UIBarOption o = (UIBarOption)option;
if (o == null || o.Series == null || o.SeriesCount == 0) return;
if (BarOption == null || BarOption.Series == null || BarOption.SeriesCount == 0) return;
DrawOrigin = new Point(BarOption.Grid.Left, Height - BarOption.Grid.Bottom);
DrawSize = new Size(Width - BarOption.Grid.Left - BarOption.Grid.Right,
Height - BarOption.Grid.Top - BarOption.Grid.Bottom);
if (DrawSize.Width <= 0 || DrawSize.Height <= 0) return;
if (o.XAxis.Data.Count == 0) return;
if (BarOption.XAxis.Data.Count == 0) return;
NeedDraw = true;
DrawBarWidth = DrawSize.Width * 1.0f / o.XAxis.Data.Count;
DrawBarWidth = DrawSize.Width * 1.0f / BarOption.XAxis.Data.Count;
double min = double.MaxValue;
double max = double.MinValue;
foreach (var series in o.Series)
foreach (var series in BarOption.Series)
{
min = Math.Min(min, series.Data.Min());
max = Math.Max(max, series.Data.Max());
}
if (min > 0 && max > 0 && !o.YAxis.Scale)
{
min = 0;
}
if (min < 0 && max < 0 && !o.YAxis.Scale)
{
max = 0;
}
if (!o.YAxis.MaxAuto) max = o.YAxis.Max;
if (!o.YAxis.MinAuto) min = o.YAxis.Min;
if (min > 0 && max > 0 && !BarOption.YAxis.Scale) min = 0;
if (min < 0 && max < 0 && !BarOption.YAxis.Scale) max = 0;
if (!BarOption.YAxis.MaxAuto) max = BarOption.YAxis.Max;
if (!BarOption.YAxis.MinAuto) min = BarOption.YAxis.Min;
if ((max - min).IsZero())
{
@ -86,20 +77,20 @@ namespace Sunny.UI
min = 0;
}
UIChartHelper.CalcDegreeScale(min, max, o.YAxis.SplitNumber,
UIChartHelper.CalcDegreeScale(min, max, BarOption.YAxis.SplitNumber,
out int start, out int end, out double interval);
YAxisStart = start;
YAxisEnd = end;
YAxisInterval = interval;
float x1 = DrawBarWidth / ((o.SeriesCount * 2) + o.SeriesCount + 1);
float x1 = DrawBarWidth / (BarOption.SeriesCount * 2 + BarOption.SeriesCount + 1);
float x2 = x1 * 2;
for (int i = 0; i < o.SeriesCount; i++)
for (int i = 0; i < BarOption.SeriesCount; i++)
{
float barX = DrawOrigin.X;
var series = o.Series[i];
var series = BarOption.Series[i];
Bars.TryAdd(i, new List<BarInfo>());
for (int j = 0; j < series.Data.Count; j++)
{

View File

@ -28,45 +28,44 @@ using System.Windows.Forms;
namespace Sunny.UI
{
public class UIBarChartEx : UIBarChart
public sealed class UIBarChartEx : UIBarChart
{
protected override void CalcData(UIOption option)
protected override void CalcData()
{
Bars.Clear();
NeedDraw = false;
UIBarOption o = (UIBarOption)option;
if (o == null || o.Series == null || o.SeriesCount == 0) return;
if (BarOption == null || BarOption.Series == null || BarOption.SeriesCount == 0) return;
DrawOrigin = new Point(BarOption.Grid.Left, Height - BarOption.Grid.Bottom);
DrawSize = new Size(Width - BarOption.Grid.Left - BarOption.Grid.Right,
Height - BarOption.Grid.Top - BarOption.Grid.Bottom);
if (DrawSize.Width <= 0 || DrawSize.Height <= 0) return;
if (o.Series.Count == 0) return;
if (BarOption.Series.Count == 0) return;
NeedDraw = true;
DrawBarWidth = DrawSize.Width * 1.0f / o.Series.Count;
DrawBarWidth = DrawSize.Width * 1.0f / BarOption.Series.Count;
double min = double.MaxValue;
double max = double.MinValue;
foreach (var series in o.Series)
foreach (var series in BarOption.Series)
{
min = Math.Min(min, series.Data.Min());
max = Math.Max(max, series.Data.Max());
}
if (min > 0 && max > 0 && !o.YAxis.Scale)
if (min > 0 && max > 0 && !BarOption.YAxis.Scale)
{
min = 0;
}
if (min < 0 && max < 0 && !o.YAxis.Scale)
if (min < 0 && max < 0 && !BarOption.YAxis.Scale)
{
max = 0;
}
if (!o.YAxis.MaxAuto) max = o.YAxis.Max;
if (!o.YAxis.MinAuto) min = o.YAxis.Min;
if (!BarOption.YAxis.MaxAuto) max = BarOption.YAxis.Max;
if (!BarOption.YAxis.MinAuto) min = BarOption.YAxis.Min;
if ((max - min).IsZero())
{
@ -74,7 +73,7 @@ namespace Sunny.UI
min = 0;
}
UIChartHelper.CalcDegreeScale(min, max, o.YAxis.SplitNumber,
UIChartHelper.CalcDegreeScale(min, max, BarOption.YAxis.SplitNumber,
out int start, out int end, out double interval);
YAxisStart = start;
@ -87,9 +86,9 @@ namespace Sunny.UI
float x1 = DrawSize.Width * 1.0f / DataCount / 4;
float x2 = x1 * 2;
for (int i = 0; i < o.SeriesCount; i++)
for (int i = 0; i < BarOption.SeriesCount; i++)
{
var series = o.Series[i];
var series = BarOption.Series[i];
Bars.TryAdd(i, new List<BarInfo>());
for (int j = 0; j < series.Data.Count; j++)
@ -162,9 +161,9 @@ namespace Sunny.UI
}
else
{
for (int i = 0; i < o.SeriesCount; i++)
for (int i = 0; i < BarOption.SeriesCount; i++)
{
var series = o.Series[i];
var series = BarOption.Series[i];
float x1;
if (BarOption.FixedSeriesCount > 0)
x1 = DrawBarWidth / (BarOption.FixedSeriesCount * 2 + BarOption.FixedSeriesCount + 1);

View File

@ -25,13 +25,13 @@ using System.Drawing;
namespace Sunny.UI
{
public class UIBarOption : UIOption, IDisposable
public sealed class UIBarOption : UIOption, IDisposable
{
public UICategoryAxis XAxis { get; set; } = new UICategoryAxis();
public UIAxis XAxis { get; set; } = new UIAxis(UIAxisType.Category);
public UIBarToolTip ToolTip { get; set; }
public UIValueAxis YAxis { get; set; } = new UIValueAxis();
public UIAxis YAxis { get; set; } = new UIAxis(UIAxisType.Value);
public List<UIBarSeries> Series = new List<UIBarSeries>();
@ -90,6 +90,16 @@ namespace Sunny.UI
public class UIAxis
{
public UIAxis()
{
}
public UIAxis(UIAxisType axisType)
{
Type = axisType;
}
public string Name { get; set; }
public UIAxisType Type { get; set; }
@ -122,15 +132,6 @@ namespace Sunny.UI
public double Max { get; set; } = 100;
public double Min { get; set; } = 0;
}
public class UICategoryAxis : UIAxis
{
public UICategoryAxis()
{
Type = UIAxisType.Category;
}
public List<string> Data = new List<string>();
public void Clear()
@ -197,14 +198,6 @@ namespace Sunny.UI
public int Distance { get; set; } = 0;
}
public class UIValueAxis : UIAxis
{
public UIValueAxis()
{
Type = UIAxisType.Value;
}
}
public class UIBarSeries : IDisposable
{
public string Name { get; set; }

View File

@ -86,7 +86,7 @@ namespace Sunny.UI
}
/// <summary>
/// 字体颜色
/// 字体颜色
/// </summary>
[Description("字体颜色")]
[Category("SunnyUI")]
@ -109,7 +109,7 @@ namespace Sunny.UI
}
/// <summary>
/// 填充颜色,当值为背景色或透明色或空值则不填充
/// 填充颜色,当值为背景色或透明色或空值则不填充
/// </summary>
[Description("填充颜色")]
[Category("SunnyUI")]
@ -141,10 +141,10 @@ namespace Sunny.UI
public void SetOption(UIOption option)
{
Option = option;
CalcData(option);
CalcData();
}
protected virtual void CalcData(UIOption o)
protected virtual void CalcData()
{
}
@ -158,7 +158,7 @@ namespace Sunny.UI
if (emptyOption == null)
{
CreateEmptyOption();
CalcData(emptyOption);
CalcData();
}
return emptyOption;
@ -307,8 +307,8 @@ namespace Sunny.UI
if (legend.Top == UITopAlignment.Bottom) top = Height - totalHeight - TextInterval;
}
float startleft = left;
float starttop = top;
float startLeft = left;
float startTop = top;
for (int i = 0; i < legend.DataCount; i++)
{
var data = legend.Data[i];
@ -320,17 +320,17 @@ namespace Sunny.UI
if (legend.Orient == UIOrient.Horizontal)
{
g.FillRoundRectangle(color, (int)startleft, (int)top + 1, 18, (int)oneHeight - 2, 5);
g.DrawString(data, LegendFont, color, startleft + 20, top);
startleft += 22;
startleft += sf.Width;
g.FillRoundRectangle(color, (int)startLeft, (int)top + 1, 18, (int)oneHeight - 2, 5);
g.DrawString(data, LegendFont, color, startLeft + 20, top);
startLeft += 22;
startLeft += sf.Width;
}
if (legend.Orient == UIOrient.Vertical)
{
g.FillRoundRectangle(color, (int)left, (int)starttop + 1, 18, (int)oneHeight - 2, 5);
g.DrawString(data, LegendFont, color, left + 20, starttop);
starttop += oneHeight;
g.FillRoundRectangle(color, (int)left, (int)startTop + 1, 18, (int)oneHeight - 2, 5);
g.DrawString(data, LegendFont, color, left + 20, startTop);
startTop += oneHeight;
}
}
}

View File

@ -29,7 +29,7 @@ using System.Windows.Forms;
namespace Sunny.UI
{
[ToolboxItem(true), Description("甜甜圈图")]
public class UIDoughnutChart : UIChart
public sealed class UIDoughnutChart : UIChart
{
protected override void CreateEmptyOption()
{
@ -58,7 +58,7 @@ namespace Sunny.UI
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
CalcData(DoughnutOption);
CalcData();
}
protected override void DrawOption(Graphics g)
@ -69,15 +69,14 @@ namespace Sunny.UI
DrawLegend(g, DoughnutOption.Legend);
}
protected override void CalcData(UIOption option)
protected override void CalcData()
{
Angles.Clear();
UIDoughnutOption o = (UIDoughnutOption)option;
if (o == null || o.Series == null || o.Series.Count == 0) return;
if (DoughnutOption == null || DoughnutOption.Series == null || DoughnutOption.Series.Count == 0) return;
for (int pieIndex = 0; pieIndex < o.Series.Count; pieIndex++)
for (int pieIndex = 0; pieIndex < DoughnutOption.Series.Count; pieIndex++)
{
var pie = o.Series[pieIndex];
var pie = DoughnutOption.Series[pieIndex];
Angles.TryAdd(pieIndex, new ConcurrentDictionary<int, Angle>());
double all = 0;
@ -93,14 +92,14 @@ namespace Sunny.UI
float angle = (float)(pie.Data[i].Value * 360.0f / all);
float percent = (float)(pie.Data[i].Value * 100.0f / all);
string text = "";
if (o.ToolTip != null)
if (DoughnutOption.ToolTip != null)
{
try
{
UITemplate template = new UITemplate(o.ToolTip.Formatter);
UITemplate template = new UITemplate(DoughnutOption.ToolTip.Formatter);
template.Set("a", pie.Name);
template.Set("b", pie.Data[i].Name);
template.Set("c", pie.Data[i].Value.ToString(o.ToolTip.ValueFormat));
template.Set("c", pie.Data[i].Value.ToString(DoughnutOption.ToolTip.ValueFormat));
template.Set("d", percent.ToString("F2"));
text = template.Render();
}
@ -113,7 +112,7 @@ namespace Sunny.UI
Angle pieAngle = new Angle(start, angle, text);
GetSeriesRect(pie, ref pieAngle);
Angles[pieIndex].AddOrUpdate(i, pieAngle);
Angles[pieIndex].TryAddOrUpdate(i, pieAngle);
start += angle;
}
}

View File

@ -0,0 +1,313 @@
using Sunny.UI.Charts;
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
namespace Sunny.UI
{
[ToolboxItem(true)]
public sealed class UILineChart : UIChart
{
private bool NeedDraw;
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
CalcData();
}
private Point DrawOrigin;
private Size DrawSize;
private int YAxisStart;
private int YAxisEnd;
private double YAxisInterval;
private int XAxisStart;
private int XAxisEnd;
private double XAxisInterval;
protected override void CalcData()
{
NeedDraw = false;
if (LineOption == null || LineOption.Series == null || LineOption.Series.Count == 0) return;
DrawOrigin = new Point(LineOption.Grid.Left, Height - LineOption.Grid.Bottom);
DrawSize = new Size(Width - LineOption.Grid.Left - LineOption.Grid.Right,
Height - LineOption.Grid.Top - LineOption.Grid.Bottom);
if (DrawSize.Width <= 0 || DrawSize.Height <= 0) return;
CalcAxises();
foreach (var series in LineOption.Series.Values)
{
series.Points.Clear();
for (int i = 0; i < series.XData.Count; i++)
{
float x = (float)(series.XData[i] - XAxisStart) * 1.0f * DrawSize.Width / (XAxisEnd - XAxisStart);
float y = (float)(series.YData[i] - YAxisStart) * 1.0f * DrawSize.Height / (YAxisEnd - YAxisStart);
series.Points.Add(new PointF(DrawOrigin.X + x, DrawOrigin.Y - y));
}
}
NeedDraw = true;
}
private void CalcAxises()
{
//Y轴
double min = double.MaxValue;
double max = double.MinValue;
foreach (var series in LineOption.Series.Values)
{
min = Math.Min(min, series.YData.Min());
max = Math.Max(max, series.YData.Max());
}
if (min > 0 && max > 0 && !LineOption.YAxis.Scale) min = 0;
if (min < 0 && max < 0 && !LineOption.YAxis.Scale) max = 0;
if (!LineOption.YAxis.MaxAuto) max = LineOption.YAxis.Max;
if (!LineOption.YAxis.MinAuto) min = LineOption.YAxis.Min;
if ((max - min).IsZero())
{
max = 100;
min = 0;
}
UIChartHelper.CalcDegreeScale(min, max, LineOption.YAxis.SplitNumber,
out int startY, out int endY, out double intervalY);
YAxisStart = startY;
YAxisEnd = endY;
YAxisInterval = intervalY;
//X轴
min = double.MaxValue;
max = double.MinValue;
foreach (var series in LineOption.Series.Values)
{
min = Math.Min(min, series.XData.Min());
max = Math.Max(max, series.XData.Max());
}
if (min > 0 && max > 0 && !LineOption.XAxis.Scale) min = 0;
if (min < 0 && max < 0 && !LineOption.XAxis.Scale) max = 0;
if (!LineOption.XAxis.MaxAuto) max = LineOption.XAxis.Max;
if (!LineOption.XAxis.MinAuto) min = LineOption.XAxis.Min;
if ((max - min).IsZero())
{
max = 100;
min = 0;
}
UIChartHelper.CalcDegreeScale(min, max, LineOption.XAxis.SplitNumber,
out int startX, out int endX, out double intervalX);
XAxisStart = startX;
XAxisEnd = endX;
XAxisInterval = intervalX;
}
[Browsable(false)]
private UILineOption LineOption
{
get
{
UIOption option = Option ?? EmptyOption;
return (UILineOption)option;
}
}
protected override void CreateEmptyOption()
{
if (emptyOption != null) return;
UILineOption option = new UILineOption();
option.Title = new UITitle();
option.Title.Text = "SunnyUI";
option.Title.SubText = "LineChart";
option.AddSeries(new UILineSeries("Line"));
option.AddData("Line", 0, 1);
option.AddData("Line", 1, 2);
option.AddData("Line", 2, 3);
option.AddData("Line", 3, 4);
option.AddData("Line", 4, 3);
option.AddData("Line", 5, 2);
option.XAxis.Name = "日期";
option.YAxis.Name = "数值";
emptyOption = option;
}
protected override void DrawOption(Graphics g)
{
if (LineOption == null) return;
if (!NeedDraw) return;
// if (BarOption.ToolTip != null && BarOption.ToolTip.AxisPointer.Type == UIAxisPointerType.Shadow) DrawToolTip(g);
DrawAxis(g);
DrawTitle(g, LineOption.Title);
DrawSeries(g);
// if (BarOption.ToolTip != null && BarOption.ToolTip.AxisPointer.Type == UIAxisPointerType.Line) DrawToolTip(g);
DrawLegend(g, LineOption.Legend);
DrawAxisScales(g);
}
private void DrawAxis(Graphics g)
{
if (YAxisStart >= 0) g.DrawLine(ChartStyle.ForeColor, DrawOrigin,
new Point(DrawOrigin.X + DrawSize.Width, DrawOrigin.Y));
if (YAxisEnd <= 0) g.DrawLine(ChartStyle.ForeColor, new Point(DrawOrigin.X, LineOption.Grid.Top),
new Point(DrawOrigin.X + DrawSize.Width, LineOption.Grid.Top));
g.DrawLine(ChartStyle.ForeColor, DrawOrigin, new Point(DrawOrigin.X, DrawOrigin.Y - DrawSize.Height));
//X Tick
if (LineOption.XAxis.AxisTick.Show)
{
float start = DrawOrigin.X;
float DrawBarWidth = DrawSize.Width * 1.0f / (XAxisEnd - XAxisStart);
for (int i = XAxisStart; i <= XAxisEnd; i++)
{
g.DrawLine(ChartStyle.ForeColor, start, DrawOrigin.Y, start, DrawOrigin.Y + LineOption.XAxis.AxisTick.Length);
if (i != 0)
{
using (Pen pn = new Pen(ChartStyle.ForeColor))
{
pn.DashStyle = DashStyle.Dash;
pn.DashPattern = new float[] { 3, 3 };
g.DrawLine(pn, start, DrawOrigin.Y, start, LineOption.Grid.Top);
}
}
else
{
g.DrawLine(ChartStyle.ForeColor, start, DrawOrigin.Y, start, LineOption.Grid.Top);
}
start += DrawBarWidth;
}
}
//X Label
if (LineOption.XAxis.AxisLabel.Show)
{
float start = DrawOrigin.X;
float DrawBarWidth = DrawSize.Width * 1.0f / (XAxisEnd - XAxisStart);
int idx = 0;
float wmax = 0;
for (int i = XAxisStart; i <= XAxisEnd; i++)
{
string label = LineOption.XAxis.AxisLabel.GetLabel(i * XAxisInterval, idx);
SizeF sf = g.MeasureString(label, SubFont);
wmax = Math.Max(wmax, sf.Width);
g.DrawString(label, SubFont, ChartStyle.ForeColor, start - sf.Width / 2.0f,
DrawOrigin.Y + LineOption.XAxis.AxisTick.Length);
start += DrawBarWidth;
}
SizeF sfname = g.MeasureString(LineOption.XAxis.Name, SubFont);
g.DrawString(LineOption.XAxis.Name, SubFont, ChartStyle.ForeColor,
DrawOrigin.X + (DrawSize.Width - sfname.Width) / 2.0f,
DrawOrigin.Y + LineOption.XAxis.AxisTick.Length + sfname.Height);
}
//Y Tick
if (LineOption.YAxis.AxisTick.Show)
{
float start = DrawOrigin.Y;
float DrawBarHeight = DrawSize.Height * 1.0f / (YAxisEnd - YAxisStart);
for (int i = YAxisStart; i <= YAxisEnd; i++)
{
g.DrawLine(ChartStyle.ForeColor, DrawOrigin.X, start, DrawOrigin.X - LineOption.YAxis.AxisTick.Length, start);
if (i != 0)
{
using (Pen pn = new Pen(ChartStyle.ForeColor))
{
pn.DashStyle = DashStyle.Dash;
pn.DashPattern = new float[] { 3, 3 };
g.DrawLine(pn, DrawOrigin.X, start, Width - LineOption.Grid.Right, start);
}
}
else
{
g.DrawLine(ChartStyle.ForeColor, DrawOrigin.X, start, Width - LineOption.Grid.Right, start);
}
start -= DrawBarHeight;
}
}
//Y Label
if (LineOption.YAxis.AxisLabel.Show)
{
float start = DrawOrigin.Y;
float DrawBarHeight = DrawSize.Height * 1.0f / (YAxisEnd - YAxisStart);
int idx = 0;
float wmax = 0;
for (int i = YAxisStart; i <= YAxisEnd; i++)
{
string label = LineOption.YAxis.AxisLabel.GetLabel(i * YAxisInterval, idx);
SizeF sf = g.MeasureString(label, SubFont);
wmax = Math.Max(wmax, sf.Width);
g.DrawString(label, SubFont, ChartStyle.ForeColor, DrawOrigin.X - LineOption.YAxis.AxisTick.Length - sf.Width, start - sf.Height / 2.0f);
start -= DrawBarHeight;
}
SizeF sfname = g.MeasureString(LineOption.YAxis.Name, SubFont);
int x = (int)(DrawOrigin.X - LineOption.YAxis.AxisTick.Length - wmax - sfname.Height);
int y = (int)(LineOption.Grid.Top + (DrawSize.Height - sfname.Width) / 2);
g.DrawString(LineOption.YAxis.Name, SubFont, ChartStyle.ForeColor, new Point(x, y),
new StringFormat() { Alignment = StringAlignment.Center }, 270);
}
}
private void DrawSeries(Graphics g)
{
int idx = 0;
foreach (var series in LineOption.Series.Values)
{
Color color = series.Color;
if (!series.CustomColor) color = ChartStyle.GetColor(idx);
if (series.Smooth)
g.DrawCurve(color, series.Points.ToArray(), true);
else
g.DrawLines(series.Color, series.Points.ToArray(), true);
idx++;
}
}
private void DrawAxisScales(Graphics g)
{
foreach (var line in LineOption.YAxisScaleLines)
{
double ymin = YAxisStart * YAxisInterval;
double ymax = YAxisEnd * YAxisInterval;
float pos = (float)((line.Value - ymin) * (Height - LineOption.Grid.Top - LineOption.Grid.Bottom) / (ymax - ymin));
pos = (Height - LineOption.Grid.Bottom - pos);
using (Pen pn = new Pen(line.Color, line.Size))
{
g.DrawLine(pn, DrawOrigin.X, pos, Width - LineOption.Grid.Right, pos);
}
SizeF sf = g.MeasureString(line.Name, SubFont);
if (line.Left == UILeftAlignment.Left)
g.DrawString(line.Name, SubFont, line.Color, DrawOrigin.X + 4, pos - 2 - sf.Height);
if (line.Left == UILeftAlignment.Center)
g.DrawString(line.Name, SubFont, line.Color, DrawOrigin.X + (Width - LineOption.Grid.Left - LineOption.Grid.Right - sf.Width) / 2, pos - 2 - sf.Height);
if (line.Left == UILeftAlignment.Right)
g.DrawString(line.Name, SubFont, line.Color, Width - sf.Width - 4 - LineOption.Grid.Right, pos - 2 - sf.Height);
}
}
}
}

View File

@ -0,0 +1,224 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
namespace Sunny.UI.Charts
{
public sealed class UILineOption : UIOption, IDisposable
{
public UIAxis XAxis { get; set; } = new UIAxis(UIAxisType.Value);
public UIAxis YAxis { get; set; } = new UIAxis(UIAxisType.Value);
public UIBarToolTip ToolTip { get; set; }
public void Dispose()
{
Clear();
}
public UIChartGrid Grid = new UIChartGrid();
public UIAxisType XAxisType { get; set; } = UIAxisType.Value;
public UIAxisType YAxisType { get; set; } = UIAxisType.Value;
public ConcurrentDictionary<string, UILineSeries> Series = new ConcurrentDictionary<string, UILineSeries>();
public readonly List<UIScaleLine> XAxisScaleLines = new List<UIScaleLine>();
public readonly List<UIScaleLine> YAxisScaleLines = new List<UIScaleLine>();
public void AddSeries(UILineSeries series)
{
if (series.Name.IsNullOrEmpty()) return;
Series.TryAdd(series.Name, series);
}
public void AddData(string name, double x, double y)
{
if (!Series.ContainsKey(name)) return;
Series[name].Add(x, y);
}
public void AddData(string name, DateTime x, double y)
{
if (!Series.ContainsKey(name)) return;
Series[name].Add(x, y);
}
public void AddData(string name, string x, double y)
{
if (!Series.ContainsKey(name)) return;
Series[name].Add(x, y);
}
public void AddData(string name, List<double> x, List<double> y)
{
if (x.Count != y.Count) return;
for (int i = 0; i < x.Count; i++)
{
AddData(name, x[i], y[i]);
}
}
public void AddData(string name, List<DateTime> x, List<double> y)
{
if (x.Count != y.Count) return;
for (int i = 0; i < x.Count; i++)
{
AddData(name, x[i], y[i]);
}
}
public void AddData(string name, List<string> x, List<double> y)
{
if (x.Count != y.Count) return;
for (int i = 0; i < x.Count; i++)
{
AddData(name, x[i], y[i]);
}
}
public void AddData(string name, double[] x, double[] y)
{
if (x.Length != y.Length) return;
for (int i = 0; i < x.Length; i++)
{
AddData(name, x[i], y[i]);
}
}
public void AddData(string name, DateTime[] x, double[] y)
{
if (x.Length != y.Length) return;
for (int i = 0; i < x.Length; i++)
{
AddData(name, x[i], y[i]);
}
}
public void AddData(string name, string[] x, double[] y)
{
if (x.Length != y.Length) return;
for (int i = 0; i < x.Length; i++)
{
AddData(name, x[i], y[i]);
}
}
public void Clear()
{
foreach (var series in Series.Values)
{
series.Clear();
}
Series.Clear();
}
public void Clear(string name)
{
if (Series.ContainsKey(name))
{
Series[name].Clear();
}
}
public void SetLabels(string[] labels)
{
XAxis.Clear();
if (XAxis.Type == UIAxisType.Category)
{
foreach (var label in labels)
{
AddLabel(label);
}
}
}
public void AddLabel(string label)
{
if (XAxis.Type == UIAxisType.Category)
{
XAxis.Data.Add(label);
}
}
}
public class UILineSeries
{
public string Name { get; private set; }
public float Width { get; set; } = 1;
public Color Color { get; set; }
public UILinePointSymbol Symbol { get; set; } = UILinePointSymbol.None;
public int SymbolSize { get; set; } = 1;
public Color SymbolColor { get; set; }
public bool CustomColor { get; set; }
public bool Smooth { get; set; }
public UILineSeries(string name)
{
Name = name;
Color = UIColor.Blue;
}
public UILineSeries(string name, Color color)
{
Name = name;
Color = color;
CustomColor = true;
}
public readonly List<double> XData = new List<double>();
public readonly List<double> YData = new List<double>();
public readonly List<PointF> Points = new List<PointF>();
public int DataCount => XData.Count;
public void Clear()
{
XData.Clear();
YData.Clear();
Points.Clear();
}
public void Add(double x, double y)
{
XData.Add(x);
YData.Add(y);
}
public void Add(DateTime x, double y)
{
DateTimeInt64 t = new DateTimeInt64(x);
XData.Add(t);
YData.Add(y);
}
public void Add(string x, double y)
{
int cnt = XData.Count;
XData.Add(cnt);
YData.Add(y);
}
}
public enum UILinePointSymbol
{
None,
Square,
Diamond,
Triangle,
Circle,
Plus,
Star
}
}

View File

@ -96,8 +96,7 @@ namespace Sunny.UI
{
Value,
Category,
Time,
Log
Time
}
public class UITitle

View File

@ -57,7 +57,7 @@ namespace Sunny.UI
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
CalcData(PieOption);
CalcData();
}
protected override void DrawOption(Graphics g)
@ -70,15 +70,14 @@ namespace Sunny.UI
private bool AllIsZero;
protected override void CalcData(UIOption option)
protected override void CalcData()
{
Angles.Clear();
UIPieOption o = (UIPieOption)option;
if (o == null || o.Series == null || o.Series.Count == 0) return;
if (PieOption == null || PieOption.Series == null || PieOption.Series.Count == 0) return;
for (int pieIndex = 0; pieIndex < o.Series.Count; pieIndex++)
for (int pieIndex = 0; pieIndex < PieOption.Series.Count; pieIndex++)
{
var pie = o.Series[pieIndex];
var pie = PieOption.Series[pieIndex];
Angles.TryAdd(pieIndex, new ConcurrentDictionary<int, Angle>());
double all = 0;
@ -95,14 +94,14 @@ namespace Sunny.UI
float angle = (float)(pie.Data[i].Value * 360.0f / all);
float percent = (float)(pie.Data[i].Value * 100.0f / all);
string text = "";
if (o.ToolTip != null)
if (PieOption.ToolTip != null)
{
try
{
UITemplate template = new UITemplate(o.ToolTip.Formatter);
UITemplate template = new UITemplate(PieOption.ToolTip.Formatter);
template.Set("a", pie.Name);
template.Set("b", pie.Data[i].Name);
template.Set("c", pie.Data[i].Value.ToString(o.ToolTip.ValueFormat));
template.Set("c", pie.Data[i].Value.ToString(PieOption.ToolTip.ValueFormat));
template.Set("d", percent.ToString("F2"));
text = template.Render();
}
@ -113,7 +112,7 @@ namespace Sunny.UI
}
}
Angles[pieIndex].AddOrUpdate(i, new Angle(start, angle, text));
Angles[pieIndex].TryAddOrUpdate(i, new Angle(start, angle, text));
start += angle;
}
}
@ -288,10 +287,6 @@ namespace Sunny.UI
private float RadiusSize(UIPieSeries series)
{
int left = series.Center.Left;
int top = series.Center.Top;
left = Width * left / 100;
top = Height * top / 100;
return Math.Min(Width, Height) * series.Radius / 200.0f;
}

View File

@ -25,7 +25,7 @@ using System.Drawing;
namespace Sunny.UI
{
public class UIPieOption : UIOption, IDisposable
public sealed class UIPieOption : UIOption, IDisposable
{
public List<UIPieSeries> Series = new List<UIPieSeries>();

View File

@ -185,17 +185,6 @@ namespace Sunny.UI
SetBarPosition();
}
private int VisibleColumnCount()
{
int cnt = 0;
foreach (DataGridViewColumn column in Columns)
{
if (column.Visible) cnt++;
}
return cnt;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
@ -544,10 +533,10 @@ namespace Sunny.UI
ClearColumns();
}
// public void AddRow(params object[] values)
// {
// Rows.Add(values);
// }
public int AddRow(params object[] values)
{
return Rows.Add(values);
}
}
public static class UIDataGridViewHelper

View File

@ -22,9 +22,9 @@
using System;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Sunny.UI
@ -624,7 +624,7 @@ namespace Sunny.UI
{
if (MenuHelper.GetPageIndex(node) >= 0)
{
AllNodes.AddOrUpdate(MenuHelper.GetPageIndex(node), node);
AllNodes.TryAddOrUpdate(MenuHelper.GetPageIndex(node), node);
}
GetAllNodes(node.Nodes);

View File

@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -317,14 +317,14 @@ namespace Sunny.UI
//SetStyle(UIStyles.Style);
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000;
return cp;
}
}
// protected override CreateParams CreateParams
// {
// get
// {
// CreateParams cp = base.CreateParams;
// cp.ExStyle |= 0x02000000;
// return cp;
// }
// }
}
}

View File

@ -126,7 +126,7 @@ namespace Sunny.UI
/// <param name="value">值</param>
/// <typeparam name="Key">键类型</typeparam>
/// <typeparam name="Value">值类型</typeparam>
public static void AddOrUpdate<Key, Value>(this ConcurrentDictionary<Key, Value> dictionary, Key key, Value value)
public static void TryAddOrUpdate<Key, Value>(this ConcurrentDictionary<Key, Value> dictionary, Key key, Value value)
{
if (dictionary.ContainsKey(key))
{
@ -146,7 +146,7 @@ namespace Sunny.UI
/// <param name="value">值</param>
/// <typeparam name="Key">键类型</typeparam>
/// <typeparam name="Value">值类型</typeparam>
public static void AddOrUpdate<Key, Value>(this Dictionary<Key, Value> dictionary, Key key, Value value)
public static void TryAddOrUpdate<Key, Value>(this Dictionary<Key, Value> dictionary, Key key, Value value)
{
if (dictionary.ContainsKey(key))
{

View File

@ -20,7 +20,6 @@
******************************************************************************/
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
@ -35,7 +34,7 @@ namespace Sunny.UI
alpha = Math.Min(255, alpha);
return Color.FromArgb(alpha, color);
}
/// <summary>
/// 九宫切图背景填充,#http://st233.com/blog.php?id=24
/// 例如按钮是图片分成九个区域 然后只需要将四角填充到目标区域 其余的拉伸就可以了
@ -216,6 +215,26 @@ namespace Sunny.UI
}
}
public static void DrawCurve(this Graphics g, Color color, Point[] points, bool smooth = false)
{
using (Pen pen = new Pen(color))
{
g.Smooth(smooth);
g.DrawCurve(pen, points);
g.Smooth(false);
}
}
public static void DrawCurve(this Graphics g, Color color, PointF[] points, bool smooth = false)
{
using (Pen pen = new Pen(color))
{
g.Smooth(smooth);
g.DrawCurve(pen, points);
g.Smooth(false);
}
}
public static void DrawLine(this Graphics g, Color color, int x1, int y1, int x2, int y2, bool smooth = false)
{
using (Pen pen = new Pen(color))

View File

@ -304,7 +304,7 @@ namespace Sunny.UI
{
if (!Forms.ContainsKey(guid))
{
Forms.AddOrUpdate(guid, form);
Forms.TryAddOrUpdate(guid, form);
return true;
}
@ -320,7 +320,7 @@ namespace Sunny.UI
{
if (!Pages.ContainsKey(guid))
{
Pages.AddOrUpdate(guid, page);
Pages.TryAddOrUpdate(guid, page);
return true;
}
@ -335,7 +335,7 @@ namespace Sunny.UI
{
if (!Forms.ContainsKey(form.Guid))
{
Forms.AddOrUpdate(form.Guid, form);
Forms.TryAddOrUpdate(form.Guid, form);
return true;
}
@ -350,7 +350,7 @@ namespace Sunny.UI
{
if (!Pages.ContainsKey(page.Guid))
{
Pages.AddOrUpdate(page.Guid, page);
Pages.TryAddOrUpdate(page.Guid, page);
return true;
}

View File

@ -65,6 +65,10 @@
<Compile Include="Charts\UIDoughnutChart.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Charts\UILineChart.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Charts\UILineChartOption.cs" />
<Compile Include="Charts\UIOption.cs" />
<Compile Include="Charts\UIPieChartOption.cs" />
<Compile Include="Controls\Color\UIColorBar.cs">
@ -503,27 +507,12 @@
<Compile Include="Units\UXmlConfig.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Controls\DropItem\UIDateTimeItem.resx">
<DependentUpon>UIDateTimeItem.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\UIEditForm.resx">
<DependentUpon>UIEditForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\UIForm.resx">
<DependentUpon>UIForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\UILoginForm.resx">
<DependentUpon>UILoginForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\UINotifier.resx">
<DependentUpon>UINotifier.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Font\UIFontImages.resx">
<DependentUpon>UIFontImages.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\UIStatusForm.resx">
<DependentUpon>UIStatusForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>

View File

@ -32,8 +32,8 @@ namespace Sunny.UI
public void TryAdd(TKey1 key1, TKey2 key2)
{
Key1.AddOrUpdate(key1, key2);
Key2.AddOrUpdate(key2, key1);
Key1.TryAddOrUpdate(key1, key2);
Key2.TryAddOrUpdate(key2, key1);
}
public TKey2 this[TKey1 key1]