開發OneNote Add-Ins詳解(下)
接續上一篇UI已經完成了之後,這一篇就繼續來把功能補上。
在開始之前,強力推薦安裝 OMSpy - A OneNote developer’s tool
這套軟體可以看到目前OneNote的文件結構
我覺得與其看文件,不如從現有的結構中學習反而比較快速。
例如這篇的目標是把選擇的圖片插入到OneNote的Page上,那我就先在空白的頁面上
先插入一張圖片,在開啟OMSpy工具來看長出了什麼樣的XML
由右上角的Content內容可得知,我在OneNote做了那些設定會長出什麼樣的XML出來。
例如圖片,則只要有下列這樣的結構就可以了
<one:Image format="png" originalPageNumber="0">
<one:Position x="36.0" y="86.4000015258789" z="0" />
<one:Size width="18.0" height="18.0" />
<one:Data>
Base64String資料
</one:Data>
</one:Image>
接著在上一篇留下的gallery_Click事件中,加上
//取得組件所在目錄
static string codeBase = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
public void gallery_Click(IRibbonControl control, string selectedId, int selectedIndex)
{
var path = Path.Combine(codeBase, "images");
//經由組件所在目錄加上ID的命名規則找到圖片
var imagePath = Path.Combine(path, selectedId.Substring(selectedId.IndexOf('_') + 1));
//讀取圖片並轉為Base64String
var baseString = Convert.ToBase64String(File.ReadAllBytes(imagePath));
//插入到OneNote
InsertIconToOneNotePage(baseString);
}
在讀取圖片之後,剩下的就是一些對XML的操作,由於這些操作不是本篇重點,因此我就簡單帶過
private void InsertIconToOneNotePage(string base64String)
{
string notebookXml;
//取得OneNote內容的結構,第二個參數可指定範圍
onApp.GetHierarchy(null, HierarchyScope.hsPages, out notebookXml);
//將string轉為XDocument
var doc = XDocument.Parse(notebookXml);
//取得命名空間
ns = doc.Root.Name.Namespace;
//取得目前可視頁面
var pageNode = doc.Descendants(ns + "Page")
.Where(n => n.Attribute("isCurrentlyViewed") != null && n.Attribute("isCurrentlyViewed").Value == "true")
.FirstOrDefault();
if (pageNode != null)
{
//頁面ID
var existingPageId = pageNode.Attribute("ID").Value;
//滑鼠游標位置
string[] position = GetMousePointPosition(existingPageId);
//插入圖片
var page = InsertIcon(base64String, position);
page.Root.SetAttributeValue("ID", existingPageId);
//更新內容
onApp.UpdatePageContent(page.ToString(), DateTime.MinValue);
}
}
取得滑鼠游標位置
/// <summary>
/// 取得滑鼠所在的點
/// Get Mouse Point
/// </summary>
private string[] GetMousePointPosition(string pageID)
{
string pageXml;
//如果指定PageID的內容
onApp.GetPageContent(pageID, out pageXml, PageInfo.piSelection);
//因為當滑鼠在某個區塊時,Outline節點會多了一個Attribute為selected
//因此可利用此來判斷游標位置
var node = XDocument.Parse(pageXml).Descendants(ns + "Outline")
.Where(n => n.Attribute("selected") != null && n.Attribute("selected").Value == "partial")
.FirstOrDefault();
if (node != null)
{
//滑鼠座標會放在Position元素中
var attrPos = node.Descendants(ns + "Position").FirstOrDefault();
if (attrPos != null)
{
var x = attrPos.Attribute("x").Value;
var y = attrPos.Attribute("y").Value;
return new string[] { x, y };
}
}
return null;
}
插入表情符號
/// <summary>
/// 插入表情符號至 OneNote
/// Generate XML Insert To OneNote
/// </summary>
private XDocument InsertIcon(string base64String, string[] position)
{
//由前面觀察到的插入圖片產生的結構
//依樣畫葫蘆寫出一樣的結構
//format這邊寫死成png,可以需求改成動態的
XElement imageElement = new XElement(ns + "Image");
imageElement.Add(new XAttribute("format", "png"));
imageElement.Add(new XAttribute("originalPageNumber", "0"));
//如果有找到滑鼠的座標,則插入一個Position的XElement
if (position != null && position.Length == 2)
{
XElement pos = new XElement(ns + "Position");
pos.Add(new XAttribute("x", position[0]));
pos.Add(new XAttribute("y", position[1]));
imageElement.Add(pos);
}
//插入Data XElement,內容為Base64String
XElement dataElement = new XElement(ns + "Data", base64String);
imageElement.Add(dataElement);
XElement page = new XElement(ns + "Page");
page.Add(imageElement);
XDocument doc = new XDocument();
doc.Add(page);
return doc;
}
重新編譯並且安裝過後,就完成了。
由於是範例的關係,所以功能並不完善,也沒有介面可以新增Icon
(如果真的要新增,必須於安裝路徑修改Ribbon.xml及放入圖片到images資料夾)
如果有興趣的可以試著寫寫看,並且分享讓大家有越來越多好用的工具。