<group id="Start" label="開始"> <labelControl id="StartLabel1" label="選擇一個"/> <labelControl id="StartLabel2" label="開始點(diǎn)"/> <labelControl id="StartLabel3" label="用于計算."/> </group>
這個選項卡按照工作流設(shè)計,確保用戶從左至右,按順序執(zhí)行完整個工作過程。
選擇正確的等式
如上圖所示,默認(rèn)選擇的是“貸款”切換按鈕,當(dāng)選擇“年金”或“有效利率”時,其右側(cè)的組將呈現(xiàn)不同的項目供輸入計算數(shù)據(jù)。當(dāng)然,這里的“等式”組也可以使用拆分按鈕或庫的方式。無論使用哪種方式,都必須提供給用戶選擇等式。本例中,使用的切換按鈕在許多情形下都工作得非常好。三個切換按鈕的XML代碼如下:
<group id="Equations" label="等式"> <toggleButton id="Loan" label="貸款" onAction="SetupLoan" getPressed="SelectedEquation"/> <toggleButton id="Annuity" label="年金" onAction="SetupAnnuity" getPressed="SelectedEquation"/> <toggleButton id="EffectiveRate" label="有效利率" onAction="SetupEF" getPressed="SelectedEquation"/> </group>
當(dāng)用戶單擊某個切換按鈕時,應(yīng)用onAction屬性提供的方法
Public Sub SetupLoan(ByRef control As Office.IRibbonControl, ByVal pressed As Boolean) ' 設(shè)置計算類型 CalcType = "Loan" ' 設(shè)置按下狀態(tài) pressed = True ' 使整個功能區(qū)無效 ribbon.Invalidate() End Sub Public Sub SetupAnnuity(ByRef control As Office.IRibbonControl, ByVal pressed As Boolean) ' 設(shè)置計算類型 CalcType = "Annuity" ' 設(shè)置按下狀態(tài) pressed = True ' 使整個功能區(qū)無效 ribbon.Invalidate() End Sub Public Sub SetupEF(ByRef control As Office.IRibbonControl, ByVal pressed As Boolean) ' 設(shè)置計算類型 CalcType = "Effective Rate" ' 設(shè)置按下狀態(tài) pressed = True ' 使整個功能區(qū)無效 ribbon.Invalidate() End Sub
變量CalcType是一個字符串型的全局變量,用來追蹤所使用的等式。這個變量決定應(yīng)用程序的許多操作,甚至選項卡的最終外觀。
設(shè)置pressed為true,改變目標(biāo)控件的狀態(tài),但不會影響選項卡中的其他控件,而該應(yīng)用程序在用戶選擇不同的等式時會更改許多控件,因此需要調(diào)用ribbon.Invalidate()來使整個功能區(qū)無效,從而重繪功能區(qū)。
然后,Excel調(diào)用getPressed屬性指向的方法。本例中,所有三個切換按鈕都使用相同的方法,因為它們實(shí)質(zhì)上都執(zhí)行相同的任務(wù)。SelectedEquation()方法的代碼如下:
Public Function SelectedEquation(ByRef control As Office.IRibbonControl) As Boolean ' 基于當(dāng)前的等式確定按下狀態(tài) Select Case CalcType Case "Loan" If control.Id = "Loan" Then Return True Else Return False End If Case "Annuity" If control.Id = "Annuity" Then Return True Else Return False End If Case "Effective Rate" If control.Id = "EffectiveRate" Then Return True Else Return False End If Case Else Return False End Select End Function
基于變量CalcType的值,代碼使用Case語句來選擇計算類型,并給調(diào)用者返回True或False。返回值確定是否按下了該控件。
定義多個功能區(qū)元素
本例雖然只是自定義設(shè)計了單個選項卡,但是多重設(shè)計給應(yīng)用程序在單個選項卡中提供多個功能的外觀界面。當(dāng)用戶選擇特定的等式時,選項卡內(nèi)容改變以反映該等式的需求??绻δ軈^(qū)的控件讓用戶從左移到右以解決特定的問題,而工作表顯示用戶輸入的項目的結(jié)果,下圖顯示了選擇一個等式并輸入數(shù)據(jù)后的結(jié)果。
注:三個等式都是相當(dāng)簡單的財務(wù)等式,Excel已經(jīng)提供了這些工作表函數(shù):PMT、FV、EFFECT。由于三個函數(shù)所需要的輸入項不同,因此功能區(qū)中設(shè)計的控件也不同。例如,計算FV函數(shù)的功能區(qū)界面如下(在“等式”組中選擇“年金”):
下面列出了選項卡中呈現(xiàn)不同視圖所需要的XML:
<group id="DataEntry" getLabel="GetDataEntryLabel"> <editBox id="Rate" label="利率" onChange="GetRateText"/> <dropDown id="Term" label="期數(shù)" getVisible="TermVisible" getItemCount="TermCount" getItemID="TermItemID" getItemLabel="TermItemLabel" onAction="GetSelectedTerm"/> <editBox id="Payment" label="期初付款" getVisible="PaymentVisible" onChange="GetPaymentText"/> <editBox id="Amount" getLabel="AmountLabel" getVisible="AmountVisible" onChange="GetAmountText"/> </group>
注意,本應(yīng)用程序如何使用不同的屬性來在不同的情形下看到每個所需要的控件。“利率”控件出現(xiàn)在每個應(yīng)用程序中,因此不需要使用getVisible屬性。其他的控件都有g(shù)etVisible屬性,根據(jù)當(dāng)前等式選擇決定該控件是否出現(xiàn)在功能區(qū)。各控件的getVisible屬性對應(yīng)的回調(diào)代碼如下:
Public Function TermVisible(ByRef control As Office.IRibbonControl) As Boolean ' 應(yīng)用程序不會使用該字段進(jìn)行有效利率計算 If CalcType = "Effective Rate" Then Return False Else Return True End If End Function Public Function PaymentVisible(ByRef control As Office.IRibbonControl) As Boolean ' 當(dāng)處理年金計算時應(yīng)用程序僅使用該字段 If CalcType = "Annuity" Then Return True Else Return False End If End Function Public Function AmountVisible(ByRef control As Office.IRibbonControl) As Boolean ' 應(yīng)用程序不會使用該字段進(jìn)行有效利率計算 If CalcType = "Effective Rate" Then Return False Else Return True End If End Function
取決于變量CalcType,在功能區(qū)中呈現(xiàn)相應(yīng)的控件。這是一項編程技巧,在代碼中僅使用一個變量來控制應(yīng)用程序的外觀。
比較上面的兩個圖,你會發(fā)現(xiàn)在選擇不同的切換按鈕后,其右側(cè)組中的標(biāo)簽不同,這是由getLabel屬性來實(shí)現(xiàn)的:
Public Function GetDataEntryLabel(ByRef control As Office.IRibbonControl) As String ' 通過計算類型的選擇決定組標(biāo)簽 Select Case CalcType Case "Loan" Return "輸入貸款信息" Case "Annuity" Return "輸入年金信息" Case "Effective Rate" Return "輸入有效利率信息" Case Else Return "沒有實(shí)現(xiàn)!" End Select End Function Public Function AmountLabel(ByRef control As Office.IRibbonControl) As String ' 通過計算類型的選擇決定數(shù)量標(biāo)簽 ' 由于有效利率計算不使用該控件,因此應(yīng)用程序不給它提供標(biāo)簽 Select Case CalcType Case "Loan" Return "貸款金額" Case "Annuity" Return "每月年金付款" Case Else Return "沒有實(shí)現(xiàn)!" End Select End Function
應(yīng)用程序根據(jù)選擇調(diào)整控件及顯示。注意,應(yīng)該小心使用ribbon.Invalidate(),最好僅在應(yīng)用程序中包含一次對該方法的調(diào)用,否則可能會引發(fā)很多問題。
獲取在功能區(qū)中輸入的數(shù)據(jù)
功能區(qū)不允許任何直接的交互,因此不能直接獲取用戶輸入到功能區(qū)控件中的信息。但如何獲取這些信息呢?仍然要使用回調(diào)。大多數(shù)控件提供了onChange屬性,能夠用于發(fā)現(xiàn)控件數(shù)據(jù)的變化,但下拉列表例外,需要使用onAction屬性發(fā)現(xiàn)選項的變化。下面的代碼顯示了onChange屬性的實(shí)現(xiàn)及Term控件的onAction屬性的實(shí)現(xiàn)。
Public Sub GetRateText(ByRef control As Office.IRibbonControl, ByVal text As String) ' 保存文本的輸入值 Rate = Int32.Parse(text) End Sub Public Sub GetSelectedTerm(ByRef control As Office.IRibbonControl, ByVal selectedId As String, ByVal selectedIndex As Int32) ' 存儲默認(rèn)值 Term = 0 ' 保存貸款項 If CalcType = "Loan" Then Select Case selectedIndex Case 0 Term = 10 Case 1 Term = 15 Case 2 Term = 20 Case 3 Term = 30 End Select End If ' 保存年金項 If CalcType = "Annuity" Then Select Case selectedIndex Case 0 Term = 5 Case 1 Term = 7 Case 2 Term = 10 Case 3 Term = 15 Case 4 Term = 20 End Select End If End Sub Public Sub GetPaymentText(ByRef control As Office.IRibbonControl, ByVal text As String) ' 保存文本的輸入值 Payment = Int32.Parse(text) End Sub Public Sub GetAmountText(ByRef control As Office.IRibbonControl, ByVal text As String) ' 保存文本的輸入值 Amount = Int32.Parse(text) End Sub
使用Int32.Parse()將文本框中輸入的數(shù)據(jù)值轉(zhuǎn)換為數(shù)字,如果用戶在文本框中輸入的不是數(shù)字,那么Int32.Parse()方法將輸出0。
執(zhí)行計算
需要兩段代碼。第一段代碼響應(yīng)功能區(qū)中單擊“開始計算”按鈕的操作;第二段代碼轉(zhuǎn)換所有數(shù)據(jù)為字符串,然后在執(zhí)行計算之前將它們放置到Excel中。
Public Sub Calculate(ByRef control As Office.IRibbonControl) ' 選擇計算并調(diào)用 Select Case CalcType Case "Loan" Globals.ThisAddIn.CalculatePMT(Rate, Term, Amount) Case "Annuity" Globals.ThisAddIn.CalculateFV(Rate, Term, Payment, Amount) Case "Effective Rate" Globals.ThisAddIn.CalculateEFFECT(Rate) End Select End Sub
因為應(yīng)用程序已經(jīng)在全局變量中放置了所需的數(shù)據(jù),因此所有需要做的就是調(diào)用合適的加載項函數(shù)并提供必需的輸入。實(shí)際上,計算需要構(gòu)建與Excel公式命令相同的字符串。下面的代碼顯示了這些計算函數(shù):
' 計算貸款數(shù)量 Public Sub CalculatePMT(ByVal Rate As Double, ByVal NPer As Int32, ByVal PV As Int32) ' 計算利率 Dim PeriodicRate As Double = (Rate / 100) / 12 ' 計算期數(shù) Dim Periods As Int32 = NPer * 12 ' 執(zhí)行計算 Application.ActiveWindow.ActiveCell.Cells(1, 1) = _ "=PMT(" + PeriodicRate.ToString() + "," + _ Periods.ToString() + "," + PV.ToString() + ",0,0)" Application.ActiveWindow.ActiveCell.Calculate() End Sub ' 計算年金數(shù)量 Public Sub CalculateFV(ByVal Rate As Double, ByVal NPer As Int32, ByVal PMT As Int32, ByVal PV As Int32) ' 計算利率 Dim PeriodicRate As Double = (Rate / 100) / 12 ' 計算期數(shù) Dim Periods As Int32 = NPer * 12 ' 執(zhí)行計算 Application.ActiveWindow.ActiveCell.Cells(1, 1) = _ "=FV(" + PeriodicRate.ToString() + "," + _ Periods.ToString() + "," + PMT.ToString() + "," + _ PV.ToString() + ",0)" Application.ActiveWindow.ActiveCell.Calculate() End Sub ' 計算有效利率 Public Sub CalculateEFFECT(ByVal Rate As Double) ' 計算利率 Dim PeriodicRate As Double = Rate / 100 ' 執(zhí)行計算 Application.ActiveWindow.ActiveCell.Cells(1, 1) = _ "=EFFECT(" + PeriodicRate.ToString() + ",12)" Application.ActiveWindow.ActiveCell.Calculate() End Sub
在工作表中簡單地添加文本,不能確保發(fā)生計算,因此代碼的末尾調(diào)用Application.ActiveWindow.ActiveCell.Calculate()來執(zhí)行計算。