C#實(shí)現(xiàn)數(shù)據(jù)導(dǎo)出任一Word圖表的通用呈現(xiàn)方法
疲憊的修改
應(yīng)人才測(cè)評(píng)產(chǎn)品的需求,導(dǎo)出測(cè)評(píng)報(bào)告是其中一個(gè)重要的環(huán)節(jié),報(bào)告的文件類型也多種多樣,其中WORD輸出也扮演了一個(gè)重要的角色。
實(shí)現(xiàn)方法比較簡單,結(jié)合分析結(jié)果數(shù)據(jù),通過WORD模板文件進(jìn)行替換輸出。在實(shí)現(xiàn)的過程中,圖表的設(shè)計(jì)是必不可少的,根據(jù)初次產(chǎn)品的設(shè)計(jì)方案,圖表采用微軟Chart圖表控件進(jìn)行開發(fā),采用雷達(dá)圖進(jìn)行呈現(xiàn)。使用該控件首先要引入 System.Web.DataVisualization.dll 程序集,通過定義 System.Web.UI.DataVisualization.Charting.Chart 類來實(shí)現(xiàn),本來采用該開發(fā)方案的初衷是覺得都是微軟的技術(shù),圖表的呈現(xiàn)類型也比較豐富,可在實(shí)際的開發(fā)中,情況沒有想像的那么順利,提供的技術(shù)文檔非常有限,各種百度也是鳳毛麟角,經(jīng)過努力與探索,最終還是實(shí)現(xiàn)了需求。
但后來由于種種原因,圖表要求采用餅狀3D圖進(jìn)行呈現(xiàn),雖然已經(jīng)有了第一次的經(jīng)驗(yàn),但細(xì)節(jié)的變化,不得不再次進(jìn)行探索和學(xué)習(xí),可當(dāng)需求再次改變的時(shí)候,我決定游說產(chǎn)品設(shè)計(jì)和改變?cè)O(shè)計(jì)思路。
新的思路
由于引入 Microsoft.Office.Interop.Word 程序集進(jìn)行開發(fā),因此在Word上的所有操作都能用程序去實(shí)現(xiàn),其內(nèi)置的圖表功能也不例外,通過演練和內(nèi)部討論,圖形化的呈現(xiàn)基本能夠滿足需求。
通用性
舉例,我們?cè)赪ord中插入一個(gè)圖表并選擇雷達(dá)圖,如下圖:
插入后,我們看到 Word 會(huì)自動(dòng)彈出一個(gè)微縮版的 Excel 應(yīng)用,改變其中的項(xiàng)和系列值,圖表就會(huì)對(duì)應(yīng)的產(chǎn)生變化。
我們右擊雷達(dá)圖,選擇更改圖表類型為餅圖,如下圖:
可以看到餅圖按照EXCEL數(shù)據(jù)中的系列1數(shù)據(jù)進(jìn)行呈現(xiàn),也不會(huì)因?yàn)橄盗?的數(shù)據(jù)存在而出現(xiàn)錯(cuò)誤。由此可以分析出,控制好這個(gè) Excel 的數(shù)據(jù)應(yīng)用即可按照我們的設(shè)計(jì)實(shí)現(xiàn)任一圖表的輸出。
設(shè)計(jì)方案
(1)負(fù)責(zé)具體業(yè)務(wù)的應(yīng)用程序,輸出后的數(shù)據(jù),存入一個(gè)二維字符串?dāng)?shù)組里,模擬 Excel 數(shù)據(jù)存儲(chǔ)模式。
(2)考慮未來的擴(kuò)展性,將二維數(shù)組轉(zhuǎn)化為Json數(shù)據(jù)格式,并添加一個(gè)查找關(guān)鍵字節(jié)點(diǎn),假設(shè)為“ t:chart1”。
(3)在 Word 模板設(shè)計(jì)圖表,圖表的標(biāo)題設(shè)置為Json對(duì)應(yīng)的查找關(guān)鍵字,即“ t:chart1”。
(4)編寫數(shù)據(jù)導(dǎo)出EXCEL方法,傳遞JSON字符串參數(shù),讀取Word模板文件,遍歷模板文件中的圖表對(duì)象,并按查找關(guān)鍵字與圖表的標(biāo)題進(jìn)行對(duì)比,匹配成功,則將JSON中數(shù)組轉(zhuǎn)化為圖表需要的EXCEL數(shù)組形式,到此輸出完畢。
為什么用 Json 過渡
我們的云架構(gòu)里設(shè)計(jì)了一個(gè) Office 計(jì)算中心,在某些環(huán)境下,比如 Linux 中需要這種方式傳遞并返回值,以達(dá)到導(dǎo)入導(dǎo)出Office文件的目的。所以大家要根據(jù)實(shí)際的應(yīng)用進(jìn)行設(shè)計(jì),這里僅作為參考。
關(guān)鍵代碼實(shí)現(xiàn)
開發(fā)環(huán)境
操作系統(tǒng):Windows Server 2019 DataCenter
開發(fā)工具:VisualStudio2019
框架及語言:.net 4.7.1 C#
服務(wù)上需要安裝 Office 2016或以上
現(xiàn)在開始!
在此我們以最易懂的代碼形式舉例,假設(shè)文件模板中的圖表為條狀圖,關(guān)鍵查找字(圖表標(biāo)題)設(shè)為 “ t:chart1”,如下圖:
(1)創(chuàng)建二維數(shù)組
//定義二維字符串?dāng)?shù)組,第一列為項(xiàng)目名稱,第二列為值 string[,] chart1 = new string[11, 2]; chart1[0, 0] = "項(xiàng)"; chart1[0, 1] = "值"; chart1[1, 0] = "全局觀"; chart1[2, 0] = "影響力"; chart1[3, 0] = "公正性"; chart1[4, 0] = "果敢性"; chart1[5, 0] = "執(zhí)行力"; chart1[6, 0] = "人際理解"; chart1[7, 0] = "成就意識(shí)"; chart1[8, 0] = "創(chuàng)新意識(shí)"; chart1[9, 0] = "情緒控制"; chart1[10, 0] = "學(xué)習(xí)發(fā)展"; Random rnd = new Random(); for (int si = 1; si <= 10; si++) { chart1[si, 0] = rnd.NextDouble().ToString(); //循環(huán)賦值隨機(jī)浮點(diǎn)數(shù) }
(2)二維數(shù)組轉(zhuǎn)Json格式
這里引入 Newtonsoft.Json.dll 程序集進(jìn)行操作,代碼如下:
StringWriter sw = new StringWriter(); //using System.IO using (Newtonsoft.Json.JsonWriter writer = new Newtonsoft.Json.JsonTextWriter(sw)) { writer.Formatting = Newtonsoft.Json.Formatting.Indented; writer.WriteStartObject(); //t:chart1 轉(zhuǎn)化數(shù)組chart1 為 json 對(duì)象 writer.WritePropertyName("t:chart1"); writer.WriteStartArray(); writer.WriteStartObject(); writer.WritePropertyName("col1"); writer.WriteValue(chart1[0, 0]); writer.WritePropertyName("col2"); writer.WriteValue(chart1[0, 1]); writer.WriteEndObject(); for (int r = chart1.GetLength(0) - 1; r > 0; r--) { writer.WriteStartObject(); //循環(huán)寫入列2的具體值 for (int c = 0; c < 2; c++) { writer.WritePropertyName("col" + (c + 1).ToString()); writer.WriteValue(chart1[r, c]); } writer.WriteEndObject(); } writer.WriteEndArray(); //t:chart1 writer.WriteEndObject(); writer.Flush(); } sw.Close(); string jsonContent = sw.GetStringBuilder().ToString(); //得到最終json字串
轉(zhuǎn)化成功的樣例如下:
{ "t:chart1": [ { "col1": "項(xiàng)", "col2": "值" }, { "col1": "學(xué)習(xí)發(fā)展", "col2": "4.1" }, { "col1": "情緒控制", "col2": "5" }, { "col1": "創(chuàng)新意識(shí)", "col2": "5.1" }, { "col1": "成就意識(shí)", "col2": "4.8" }, { "col1": "人際理解", "col2": "4" }, { "col1": "執(zhí)行力", "col2": "5" }, { "col1": "果敢性", "col2": "5.7" }, { "col1": "公正性", "col2": "4.5" }, { "col1": "影響力", "col2": "4.7" }, { "col1": "全局觀", "col2": "4.2" } ] }
(3)查找圖表且替換數(shù)據(jù)
本代碼程序只是示例片斷,非完整程序,僅供參考。
一些引用 using Word=Microsoft.Office.Interop.Word; using Newtonsoft.Json.Linq; 轉(zhuǎn)換 json 字符串為 json 對(duì)象 Newtonsoft.Json.Linq.JObject jObject = null; if (jsonContent != "") { try { jObject = Newtonsoft.Json.Linq.JObject.Parse(jsonContent); //轉(zhuǎn)換為json對(duì)象 } catch (Exception e) { resultReport += "create json object fail.<br>"; //失敗記入調(diào)試報(bào)告 } } 初始化 Word 應(yīng)用程序 Word.Application WordApp=new Word.Application(); //創(chuàng)建一個(gè)名為WordDoc的文檔對(duì)象 WordApp.DisplayAlerts=Word.WdAlertLevel.wdAlertsNone; //禁止一切提示警告 //打開 filename 的文件 Word.Document WordDoc=WordApp.Documents.Open(ref filename,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing,ref Nothing); //禁用拼寫檢查 WordDoc.SpellingChecked = false; WordDoc.ShowSpellingErrors = false; 遍歷word 里的 shapes for (int i = 1; i <= WordDoc.InlineShapes.Count; i++) { Word.InlineShape shape = WordDoc.InlineShapes[i]; //得到 shape對(duì)象 //遍歷 json 對(duì)象 foreach (var item in jObject) { string tcmd = item.Key.ToString(); //取關(guān)鍵字 //如果 shape 包含圖表,則繼續(xù) if (shape.HasChart == Microsoft.Office.Core.MsoTriState.msoTrue) { //如果圖表未設(shè)置標(biāo)題,則短路 if (shape.Chart.HasTitle == false) { continue; } //獲取圖表的title string _name = shape.Chart.ChartTitle.Text.Trim().ToLower(); if (_name.IndexOf(tcmd) != -1) //如果包含關(guān)鍵字則繼續(xù) { //替換掉關(guān)鍵字,保留下來的是真正的標(biāo)題 shape.Chart.ChartTitle.Text = shape.Chart.ChartTitle.Text.Replace(tcmd, ""); //這是一個(gè)玄機(jī),否則會(huì)報(bào)錯(cuò),目前我是這樣的解決,A1:Z100,先賦值為空串 shape.Chart.ChartData.Workbook.Worksheets[1].Range("A1:Z100").Value = ""; //計(jì)算最后的單元格地址 string lastcellAddress = "$" + ((char)(64 + jObject[tcmd][0].Count())).ToString() + "$" + jObject[tcmd].Count().ToString(); //獲得最終地址字串 string sourceDataAddress = "='Sheet1'!$A$1:" + lastcellAddress; //遍歷json對(duì)象節(jié)點(diǎn)里的數(shù)組 for (int i = 0; i < jObject[tcmd].Count(); i++) { List<JToken> tokens = jObject[tcmd][i].ToList(); int k = 0; foreach (JToken jToken in tokens) { //為每一個(gè)單元格賦值 string celladdress = ((char)(65 + k)).ToString() + (i + 1).ToString(); shape.Chart.ChartData.Workbook.Worksheets[1].Range(celladdress).Value = jToken.ToArray()[0].ToString(); k++; } } shape.Chart.SetSourceData(sourceDataAddress); //設(shè)置更新圖表的數(shù)據(jù)源 break; } // index of name } // has chart }//foreach tcmd } //WordDoc.InlineShapes
小結(jié)
通過這種設(shè)計(jì)可以實(shí)現(xiàn)任意更換圖表的類型,基本無需關(guān)注圖表的實(shí)現(xiàn)原理,而讓開發(fā)人員更多的關(guān)注于業(yè)務(wù)邏輯,當(dāng)然這些圖表的種類受限于Word的提供能力,如果能夠滿足需求,不失為一種解決思路。另外,我們可以繼續(xù)擴(kuò)展程序的功能,實(shí)現(xiàn)動(dòng)態(tài)的圖表添加或切換能力等。
一些體會(huì)
作為一名全程管理加全棧開發(fā)的 “野戰(zhàn)軍”,更多的時(shí)候考慮的是滿足需求、穩(wěn)定功能和控制各種成本,而無法深入地研究各項(xiàng)領(lǐng)域。隨著年齡的增長,唯一能做到的就是業(yè)務(wù)經(jīng)驗(yàn)彌補(bǔ)精力和學(xué)習(xí)時(shí)間的不足,還是有幾點(diǎn)體會(huì)與大家共勉吧:
1、后悔學(xué)生時(shí)代沒有端正態(tài)度和認(rèn)識(shí)到認(rèn)真學(xué)習(xí)的重要性,所謂書到用時(shí)方恨少,熟練掌握修煉數(shù)據(jù)結(jié)構(gòu)與算法、數(shù)學(xué)等程序員的內(nèi)功至關(guān)重要。
2、語言只是一種模型和工具而已,可先從一門語言入手到實(shí)際應(yīng)用,抽象的來看所有語言總體上都是大同小異,后來會(huì)覺得學(xué)習(xí)一門新語言是一件非常有趣的事。
3、時(shí)間允許的情況下還是要深入掌握一些底層的技術(shù)開發(fā)和原理,這至少是一件非常有趣的事。
4、在工作中平衡最為關(guān)鍵,也包括人,換位思考很重要。
5、提升設(shè)計(jì)能力、業(yè)務(wù)處理能力和總結(jié)學(xué)習(xí)方法尤為關(guān)鍵。
以上就是C#實(shí)現(xiàn)數(shù)據(jù)導(dǎo)出任一Word圖表的通用呈現(xiàn)方法的詳細(xì)內(nèi)容,更多關(guān)于C#數(shù)據(jù)導(dǎo)出Word圖表的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#數(shù)組學(xué)習(xí)相關(guān)資料整理
最近開始學(xué)習(xí)c#,并有幸接觸到了數(shù)組方便的操作,感覺確實(shí)不錯(cuò),這里簡單的整理下c#相關(guān)的學(xué)習(xí)資料,方便大家學(xué)習(xí)2012-09-09C#實(shí)現(xiàn)密碼驗(yàn)證與輸錯(cuò)密碼賬戶鎖定
這篇文章介紹了C#實(shí)現(xiàn)密碼驗(yàn)證與輸錯(cuò)密碼賬戶鎖定的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04Unity3D控件Easytouch控制主角移動(dòng)
這篇文章主要為大家詳細(xì)介紹了Unity3D控件Easytouch控制主角移動(dòng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-02-02C#實(shí)現(xiàn)把txt文本數(shù)據(jù)快速讀取到excel中
這篇文章主要介紹了C#實(shí)現(xiàn)把txt文本數(shù)據(jù)快速讀取到excel中,本文直接給出示例代碼,需要的朋友可以參考下2015-06-06C#中的并發(fā)編程與.NET任務(wù)并行庫的使用示例和常見問題
在現(xiàn)代軟件開發(fā)中,.NET Framework通過引入任務(wù)并行庫(TPL)和并發(fā)集合類型,簡化了并發(fā)復(fù)雜性,提高程序的性能、可維護(hù)性和可擴(kuò)展性,并發(fā)集合設(shè)計(jì)上允許多線程安全訪問,此外,TPL通過Task類簡化異步操作,正確使用這些工具可避免死鎖和競(jìng)爭(zhēng)條件等常見問題2024-09-09Unity實(shí)現(xiàn)UI光暈效果(發(fā)光效果)
這篇文章主要為大家詳細(xì)介紹了Unity實(shí)現(xiàn)UI光暈效果,發(fā)光效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-01-01