創建圖表是最常見的圖形任務。ASP.NET Chat 控件提供了眾多的圖表類型和配置選項。對於 ASP.NET 3.5 SP1,Chart 控件可以下載使用,4.0 中已經包括了。
Chart 控件有眾多不同特性及選項,這里不可能全面講述。如果需要一整套示例,可參考 http://code.msdn.microsoft.com/mschart 的示例代碼庫,它包含了 200 多個 Chart 控件示例。
創建基本的圖表
理解 Chart 最好的方式還是通過示例。首先,拖出 Chart 控件:
<asp:Chart ID="Chart1" runat="server" Width="900px">
<ChartAreas>
<asp:ChartArea Name="ChartArea1" />
</ChartAreas>
</asp:Chart>
每個圖表有一個或多個描繪數據的圖形區域。我們的基本聲明里有一個圖表,我們將用它描繪兩組數據。和多數 ASP.NET 控件一樣,可以使用隱藏文件來驅動 Chart 控件或繼續使用標記。
1. 使用代碼隱藏方式
首先配置圖表的外觀。圖表背景是包圍圖表區域的區域。本例以對角線模式從灰到白漸變填充背景色,通過 BackColor、BackSecondaryColor、BackGradientStyle 屬性指定。
protected void Page_Load(object sender, EventArgs e)
{
// format the chart.
Chart1.BackColor = Color.Gray;
Chart1.BackSecondaryColor = Color.WhiteSmoke;
Chart1.BackGradientStyle = GradientStyle.DiagonalRight;
...
BorderlineDashStyle 控制每個邊框的邊緣;ChartDashStyle.Solid 值在圖表的邊緣繪制一個像素寬的邊線;BorderlineColor 決定邊線的顏色;BorderSkin 有多個選項,把 SkinStyle 設置為 Emboss 顯示有陰影的凸起的 3D 效果。
...
Chart1.BorderlineDashStyle = ChartDashStyle.Solid;
Chart1.BorderlineColor = Color.Gray;
Chart1.BorderSkin.SkinStyle = BorderSkinStyle.Emboss;
...
把圖形區域設置成我們想要的顏色並設置標題。通過一個索引值來引用圖表區域,這是因為圖表可以有多個描繪數據的區域(我們的圖表目前只有一個區域)。圖表可以有多個標題,因此必須通過 Add()方法把新標題添加到 Titles 集合,然后通過索引找到對應標題進行格式化。這里只設置了字體和大小。
// forma the chart area
Chart1.ChartAreas[0].BackColor = Color.Wheat;
// add and format the title
Chart1.Titles.Add("ASP.NET Chart");
Chart1.Titles[0].Font = new Font("Utopia", 16);
有多種格式化圖表的方法,找到你期望的組合會花費不少的時間。具有諷刺意味的是,添加數據的過程要比找到滿意的顏色方案更加簡單。目前的效果是這樣的:
有了基礎的表現設置后,可以開始處理數據了。通過 Series 類來表示成組的數據。我們創建的每個 Series 類都必須通過 Add 方法被添加到 Chart.Series 集合。我們創建一個名為 ColumnSeries 的新序列,並指定用柱狀圖來描繪這個序列里的數據。SeriesChartType 有 35 個不同的圖表類型值,它們值得探索。如果不指定值,默認就是 Column 。
Chart1.Series.Add(new Series("ColumnSeries")
{
ChartType = SeriesChartType.Column
});
序列有一系列屬性可以進行配置。這是我們為圖表創建第二個 Series 的代碼,其中進行了自定義:
Chart1.Series.Add(new Series("SplineSeries")
{
ChartType = SeriesChartType.Spline,
BorderWidth = 3,
ShadowOffset = 2,
Color = Color.PaleVioletRed
});
這里把圖表類型設置為 Spline(折線圖)。BorderWidth 的值控制線描繪時的寬度,ShadowOffset 設置了在描繪線的時候創建 3D 的陰影效果。
最后一步是向序列添加數據。有很多方式可以把數據關聯到圖表,這個示例使用最簡單的靜態值:
Chart1.Series[0].Points.DataBindY(
new int[] { 5, 3, 12, 14, 11, 7, 3, 5, 9, 12, 11, 10 });
Chart1.Series[1].Points.DataBindY(
new int[] { 3, 7, 13, 2, 7, 15, 23, 20, 1, 5, 7, 6 });
每個 Series 都有一個 Point 集合。我們使用 DataBindY 方法,它接受一個 IEnumerable 對象,可以把整型數組作為數據源。這些數據的索引被用作 X 軸的值,而數據值被用在 Y 軸。
現在運行頁面,可以看到這樣的效果:
2. 使用頁面標記配置
<asp:Chart ID="Chart2" runat="server" Width="900px" BackColor="Gray" BackSecondaryColor="WhiteSmoke"
BackGradientStyle="DiagonalRight" BorderlineDashStyle="Solid" BorderlineColor="Gray">
<BorderSkin SkinStyle="Emboss" />
<Titles>
<asp:Title Text="ASP.NET Chart" Font="Utopia,16">
</asp:Title>
</Titles>
<Series>
<asp:Series Name="ColumnSeries" ChartType="Column">
<Points>
<asp:DataPoint YValues="5" />
<asp:DataPoint YValues="3" />
<asp:DataPoint YValues="12" />
<asp:DataPoint YValues="14" />
<asp:DataPoint YValues="11" />
<asp:DataPoint YValues="7" />
<asp:DataPoint YValues="3" />
<asp:DataPoint YValues="5" />
<asp:DataPoint YValues="9" />
<asp:DataPoint YValues="12" />
<asp:DataPoint YValues="11" />
<asp:DataPoint YValues="10" />
</Points>
</asp:Series>
<asp:Series Name="SplineSeries" ChartType="Spline" BorderWidth="3" ShadowOffset="2"
Color="PaleVioletRed">
<Points>
<asp:DataPoint YValues="3" />
<asp:DataPoint YValues="7" />
<asp:DataPoint YValues="13" />
<asp:DataPoint YValues="2" />
<asp:DataPoint YValues="7" />
<asp:DataPoint YValues="15" />
<asp:DataPoint YValues="23" />
<asp:DataPoint YValues="20" />
<asp:DataPoint YValues="1" />
<asp:DataPoint YValues="5" />
<asp:DataPoint YValues="7" />
<asp:DataPoint YValues="6" />
</Points>
</asp:Series>
</Series>
<ChartAreas>
<asp:ChartArea Name="ChartArea1" BackColor="Wheat">
</asp:ChartArea>
</ChartAreas>
</asp:Chart>
Chart 控件的靈活性在於各種元素間相互獨立。為了證明這一點,下一個示例演示如何在同一個圖表上創建第二個圖標區域,並且讓同一個數據序列分別在兩個區域上描繪,在第一個示例的 Load 事件里增加下面的代碼:
Chart1.ChartAreas.Add("SecondArea");
Chart1.Series[1].ChartArea = "SecondArea";
如果使用標記要達到同樣的效果,只需指定折線圖的 ChartArea 特性即可:
<asp:Series Name="SplineSeries" ChartType="Spline" BorderWidth="3" ShadowOffset="2"
Color="PaleVioletRed" ChartArea="SecondArea">
有一個常見的任務是創建 3D 圖表。為了把一個簡單的圖表轉換為 3D 圖表,需要添加下列代碼:
Chart1.ChartAreas[0].Area3DStyle.Enable3D = true;
在 ChartArea 級別啟用 3D 。如果圖表有多個 ChartArea,可以按照需求混合 2D 和 3D 描繪。
用數據填充圖表
Chart 控件可以通過一系列不同數據源的數據來填充。
1. 綁定到數據庫表
使用 Northwind 數據庫中的 Products 表來演示。查詢 ProductName 和 UnitsInStock 列,選擇沒有停產的產品並且只返回至多 5 條記錄。
protected void Page_Load(object sender, EventArgs e)
{
Chart1.BackColor = Color.Gray;
Chart1.BackSecondaryColor = Color.WhiteSmoke;
Chart1.BackGradientStyle = GradientStyle.DiagonalRight;
Chart1.BorderlineDashStyle = ChartDashStyle.Solid;
Chart1.BorderlineColor = Color.Gray;
Chart1.BorderSkin.SkinStyle = BorderSkinStyle.Emboss;
Chart1.ChartAreas[0].BackColor = Color.Wheat;
Chart1.Titles.Add("Table Bound Chart");
Chart1.Titles[0].Font = new Font("Utopia", 16);
// Data Binding ...
SqlConnection conn = new SqlConnection(
ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString);
SqlCommand cmd = new SqlCommand("select top (5) ProductName, UnitsInStock " +
"from Products where Discontinued = 'false'", conn);
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
...
現在該把數據綁定到圖表了。首先,清空 Chart.Series 集合。這是因為綁定到表時,Chart 控件自動為它在數據中找到的數值列創建一個新的 Series 實例,最終我們會得到一個名為 UnitsInStock 的 Series,但默認的 Series 並沒有被移除(名為 Series1),如果把 Series.ChartType 屬性改為不可以作為柱狀圖在同一 CharArea 描繪的其他類型的值就會產生問題,而柱狀圖是默認的序列圖表類型。
在綁定前移除默認的 Series 類是好的實踐,這樣最終只有一個 Series 類關聯到我們的數據!
Chart1.Series.Clear();
Chart1.DataBindTable(reader);
Chart1.Series["UnitsInStock"].ChartType = SeriesChartType.StackedBar;
reader.Close();
conn.Close();
綁定到表時會自動根據數據中的每個數值列創建相同數量的數據序列。示例里,Chart 控件忽略了文本類型的 ProductName 列,而為 UnitsInStock 列創建序列。
只有 Series 創建后才能對其進行格式化,因此只有把表綁定到控件之后,才能設置 ChartType 屬性。
運行效果如下:
這個圖表的問題是 ProductName 列被忽略了。在綁定過程中,Chart 控件按所有 SQL 數據都被解析為 Y 軸的數據的機制工作,從而放棄了不可以這樣使用的其他所有值。
如果我們希望把某列用作 Y 軸的值,就必須通過 Series 類的 Points.DataBindXY 方法綁定數據來顯式的通知 Chart 控件。可將先前的代碼修改為如下:
//Chart1.Series.Clear();
//Chart1.DataBindTable(reader);
//Chart1.Series["UnitsInStock"].ChartType = SeriesChartType.StackedBar;
Chart1.Series[0].Points.DataBindXY(reader, "ProductName", reader, "UnitsInStock");
Chart1.Series[0].ChartType = SeriesChartType.StackedBar;
DataBindXY 方法可以指定 X軸 和 Y軸 的數據源以及名稱。注意,這一次沒有清空 Series 集合。DataBindXY 方法被應用到已經存在的 Series(並且不會創建新的)。
2. 綁定到對象數據源
填充圖表數據最靈活的方式是使用對象數據源,這樣可以創建一個獲取數據的對象,並把 ObjectDataSource 用作代碼檢索邏輯和 Chart 控件之間的橋梁。應該在 App_Code 目錄里創建獲取數據的類。
下面是示例,它返回簡單的靜態數據:
public class MyObjectDataSource
{
public class DataItem
{
public string Name { get; set; }
public double Popularity { get; set; }
}
public DataItem[] GetData()
{
return new DataItem[]{
new DataItem(){Name = "CheeseCake", Popularity = 30},
new DataItem(){Name = "Ice Cream", Popularity = 30},
new DataItem(){Name = "Fudge", Popularity = 20},
new DataItem(){Name = "Milkshake", Popularity = 20}
};
}
}
這項綁定技術對於返回 DataSet 和 DataTable 的方法同樣適用。使用 ObjectDataSource 的靈活性在於數據存儲的方式對圖表是抽象的,這樣你可以自由修改業務邏輯。
protected void Page_Load(object sender, EventArgs e)
{
Chart1.BackColor = Color.Gray;
Chart1.BackSecondaryColor = Color.WhiteSmoke;
Chart1.BackGradientStyle = GradientStyle.DiagonalRight;
Chart1.BorderlineDashStyle = ChartDashStyle.Solid;
Chart1.BorderlineColor = Color.Gray;
Chart1.BorderSkin.SkinStyle = BorderSkinStyle.Emboss;
Chart1.ChartAreas[0].BackColor = Color.Wheat;
Chart1.ChartAreas[0].Area3DStyle.Enable3D = true;
Chart1.Titles.Add("Table Object Adaptor Chart");
Chart1.Titles[0].Font = new Font("Utopia", 16);
// Create the object data source
ObjectDataSource ds = new ObjectDataSource("MyObjectDataSource", "GetData");
// bind the source to the chart
Chart1.DataSource = ds;
Chart1.Series[0].XValueMember = "Name";
Chart1.Series[0].YValueMembers = "Popularity";
// format the series
Chart1.Series[0].ChartType = SeriesChartType.Pie;
}
效果如下:
3. 綁定到 XML 文件
你還可以通過 System.Data.DataSet 類用 XML 文件的數據填充表。
<?xml version="1.0" encoding="utf-8" ?>
<Data>
<Product>
<Name>Apple</Name>
<Quantity>40</Quantity>
</Product>
<Product>
<Name>Orange</Name>
<Quantity>20</Quantity>
</Product>
<Product>
<Name>Banana</Name>
<Quantity>30</Quantity>
</Product>
<Product>
<Name>Mango</Name>
<Quantity>22</Quantity>
</Product>
<Product>
<Name>Cherry</Name>
<Quantity>38</Quantity>
</Product>
</Data>
protected void Page_Load(object sender, EventArgs e)
{
Chart1.BackColor = Color.Gray;
Chart1.BackSecondaryColor = Color.WhiteSmoke;
Chart1.BackGradientStyle = GradientStyle.DiagonalRight;
Chart1.BorderlineDashStyle = ChartDashStyle.Solid;
Chart1.BorderSkin.SkinStyle = BorderSkinStyle.Emboss;
Chart1.BorderlineColor = Color.Gray;
Chart1.ChartAreas[0].BackColor = Color.Wheat;
Chart1.ChartAreas[0].Area3DStyle.Enable3D = true;
Chart1.Titles.Add("XML Chart");
Chart1.Titles[0].Font = new Font("Utopia", 16);
// 雷達圖形
Chart1.Series[0].ChartType = SeriesChartType.Radar;
// define the path to the xml file
string dataPath = MapPath(".") + "\\sampledata.xml";
DataSet dataSet = new DataSet();
dataSet.ReadXml(dataPath);
DataView dataView = new DataView(dataSet.Tables[0]);
// bind the XML ata to the chart
Chart1.Series[0].Points.DataBindXY(dataView, "Name", dataView, "Quantity");
}
4. 綁定到 LINQ
將數據綁定到圖表的另一種靈活的方式是使用 LINQ 。而且,不論你使用的是 LINQ to Objects、LINQ to XML 還是 LINQ to Entities,你都可以這么做。
首先,為 Northwind 數據庫創建實體數據模型,接着,創建一個包含 Chart 控件的頁面進行測試:
protected void Page_Load(object sender, EventArgs e)
{
Chart1.BackColor = Color.Gray;
Chart1.BackSecondaryColor = Color.WhiteSmoke;
Chart1.BackGradientStyle = GradientStyle.DiagonalRight;
Chart1.BorderlineDashStyle = ChartDashStyle.Solid;
Chart1.BorderSkin.SkinStyle = BorderSkinStyle.Emboss;
Chart1.BorderlineColor = Color.Gray;
Chart1.ChartAreas[0].BackColor = Color.Wheat;
Chart1.Titles.Add("LINQ Chart");
Chart1.Titles[0].Font = new Font("Utopia", 16);
// add and format a new data series
Chart1.Series.Add("StockLevel");
Chart1.Series["StockLevel"].ChartType = SeriesChartType.Spline;
Chart1.Series["StockLevel"].BorderWidth = 3;
Chart1.Series["StockLevel"].Color = Color.PaleVioletRed;
// create a new EF context
NorthwindEntities context = new NorthwindEntities();
// perform a query
var data = context.Products
.Where(item => !item.Discontinued)
.Select(item => item)
.Take(5);
// bind the default data series to the data
Chart1.Series[0].Points.DataBind(data, "ProductName", "UnitPrice", "");
Chart1.Series[1].Points.DataBind(data, "ProductName", "UnitsInStock", "");
}
創建了 NorthwindEntities 類的一個新實例,使用 LINQ 仍舊查詢未停產的所有產品,將結果限制為 5 條。
緊接着通過 DataBind 方法將查詢結果綁定至圖表中的兩個 Series。這將指定用於 X軸 和 Y軸 的數據源和結果類型成員。我們把 UnitPrice 值綁定到一個 Series 並把 UnitsInStock 綁定到另一個,它們都將 ProductName 的值用作 X軸 的值。
Chart 控件是一個強大而靈活的圖表工具,它提供多種類型的圖表格式並且可以使用來自各種數據源的數據,只需要很少的努力,就可以創建高質量的結果。