ReportViewer in Visual Studio 2010-恐怖的報表地獄
這個星期過得不太順,除了睡眠嚴重不足之外
還有做不完的報表地獄,搞得我頭昏腦脹。
害我為了一個找不到組件的白痴錯誤搞了半個鐘頭,結果原來是參考錯了專案@@
然後帶著我的筆電去MOS想好好發篇文章的,卻遇到一個超瞎的問題又花了我兩個小時...
這個問題,對寫程式習慣越好的人,傷害越大,為什麼這麼說呢?
待我娓娓道來...
最近因為專案需求,做了不少報表。其實我個人不太喜歡這種拖拉的東西
我喜歡的是邏輯跟敲打鍵盤的快感,但好好學的話,其實報表對分析方面還滿有用的,
所以今天就來發一篇用2010做的報表吧。
首先先拉出一個Linq to Sql(這是我在資策會上課時的專題DB其中一部分)
接著在專案中新增一個Report資料夾,然後新增一個 DataSet
接著在這個DataSet中,新增一個DataTable
(注意!不是TableAdapter唷,因為我只要一個空殼,方便供等下的報表精靈使用)
然後加入資料行,(快捷鍵 Ctrl+L 很好用喔)
完成之後,我要的殼長這個樣子
接著呢,就可以新增一個報表精靈啦~
新增完之後,精靈就會帶著你一步一步做,這邊弔詭的事情發生了,找不到我的DataSet!!
就在這邊!!花了我兩個鐘頭的時間Google跟重建,因為我把DataSet放在Report資料夾裡面
所以他找不到我的DataSet,所以把DataSet移到根目錄下...
就找到了....可以賠我兩個小時的青春嗎@@
最前面有提到說對習慣好的人傷害越大,因為會依類型分門別類擺檔案,所以才會遇到這問題
如果直接新增在根目錄下,就沒這問題了..
剩下的就是跟著精靈,選一選,拉一拉
一張報表就出來啦~不過難的才剛要開始。做報表簡單,難是難在資料要如何整理統計
簡單的報表10分鐘就可以做完一張,但難的有時候光下SQL就可以花掉半天時間
接著就開始Code的部分,我是用MVC寫的,但加入WebForm對專案完全不會有影響,照一般開發模式就行了
在頁面中拉入一個ReportViewer
然後這個報表沒有參數跟按鈕,所以直接在Page_Load寫Code就好
public partial class ProductReport : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//給報表檔案的路徑
ReportViewer1.LocalReport.ReportPath = Server.MapPath("~/Report/ProductReport.rdlc");
//將資料清空
ReportViewer1.LocalReport.DataSources.Clear();
//撈出我要的資料
IEnumerable<產品報表> model = GetModel();
//新增一個ReportDataSource,第一個參數的名稱來源要注意
ReportDataSource source = new ReportDataSource("ProductReport", model);
//將資料倒進去
ReportViewer1.LocalReport.DataSources.Add(source);
//重整
ReportViewer1.LocalReport.Refresh();
}
}
//資料怎麼整理看個人
private IEnumerable<產品報表> GetModel()
{
MyDataContext db = new MyDataContext();
//如果要分析區間的資料,我覺得這樣用滿方便的
Dictionary<string,int[]> dic=new Dictionary<string,int[]>();
dic.Add("500以下",new int[]{0,500});
dic.Add("501~1000",new int[]{501,1000});
dic.Add("1000~2000",new int[]{1001,2000});
dic.Add("2001~5000",new int[]{2001,5000});
dic.Add("5000以上",new int[]{5001,int.MaxValue});
//用SelectMany方法
IEnumerable<產品報表> data = dic
.SelectMany(p =>db.Category,(c,d)=> new 產品報表
{ 大類別=d.CategoryPrimary_主分類.CategoryPrimary_主分類1
, 小類別=d.CategorySecondary_次分類.CategorySecondary_次分類1
, 價格區間=c.Key
, 數量=d.Products.Where(w=>w.UnitPrice_單價>=c.Value[0]&&w.UnitPrice_單價<=c.Value[1]).Count()});
return data;
}
}
//自訂的class,名稱要跟DataSet裡的一樣
class 產品報表
{
public string 產品名稱 { get; set; }
public string 大類別 { get; set; }
public string 小類別 { get; set; }
public string 價格區間 { get; set; }
public int 數量 { get; set; }
}
如果是要統計某個區間內的資料的話,我覺得用上方的寫法還滿簡單易懂的
不過我也是想了滿久才想到
OK之後,然Run看看
出現這個錯誤,不過這個簡單,把ScriptManager拖進去就行了
再Run一次,又有錯~
不過錯誤說明很清楚,所以在web.config裡面把該加的加一加。(我的是IIS 7,所以要多加system.webServer那段)
<system.web>
.......
<httpHandlers>
<add verb="*" path="Reserved.ReportViewerWebControl.axd" type = "Microsoft.Reporting.WebForms.HttpHandler, Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</httpHandlers>
......
</system.web>
<system.webServer>
.......
<handlers>
<add name="ReportViewerWebControlHandler" preCondition="integratedMode" verb="*" path="Reserved.ReportViewerWebControl.axd" type="Microsoft.Reporting.WebForms.HttpHandler, Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</handlers>
........
</system.webServer>
接著再執行一次,就OK了。一張報表就完成啦。(2010做出來的真的比2008的好看太多了~)
不過還沒結束,注意一下上方的分類順序錯了,因為預設會從小到大排序,這個問題我找了好久都
不知道怎麼解,不過後來發現一個不知道是哪個天才想出來的辦法!!
首先先改一下分類的Code,注意我在前面加了01…02…03的編號
但這樣報表出來的價格區間不就很怪嗎,所以在要報表上動點手腳,加上一個Mid的函數
有點類似SubString,從第3個字開始抓
結果就完美啦
呼,我一個多星期在報表地獄裡的心得,加上今天四個鐘頭的鬼打牆加寫文章時間
希望能對要用到報表的人有幫助啦。