分享

细品RibbonX(55):在Visual Studio中开发Excel商务应用程序(1)

 yuxinrong 2009-12-23
大多数人使用Excel进行各种各样的计算,从普通的财务计算到复杂的科学计算。而有些人使用Excel创建演示图形,还有些人甚至使用Excel进行基本的文字处理或数据库需要。简而言之,Excel是一种相当灵活的应用程序,能够帮助你执行广泛的任务。并且,你会发现许多Excel定制是非常特别的。
下面,我们介绍一些定制Excel的应用示例。
许多商务活动使用非标准等式,例如保险公司使用专门的等式来确定费率。另一类非标准等式是一个行业的通用公式不一定在另一个行业使用,例如电路分析是电子工业的一项通用需求,而银行业不需要任何用于此分析的等式。还有一类非标准的等式是提供某种公共利益,例如,可能需要Excel工作表来帮助比较汽车贷款的利益,或者帮助决定家庭的抵押贷款。一些等式能够帮助执行下列任务,决定信用卡的利息或者为当前的信用卡选择最好的还款计划。一些特定的工作表可以帮助你转换度量单位,或者确定身体特征例如肥胖指标。
因此,当你遇到要使用这些非标准等式时,就强以考虑在Excel中创建一个非标准等式选项卡,来执行专门的任务。
下面的示例演示如何在同一选项卡中使用多个版本来完成多项非标准等式的计算任务。
下图展示了示例应用程序的一个界面。大多数人首先会注意到最显眼的“开始”组没有包含任何控件。许多开发者习惯使应用程序中的每项功能必须执行一项任务。本例中,“开始”组只是作为起点,使用三个标签提供信息,从而起到提示作用。XML代码如下:
        <group id="Start" label="开始">
<labelControl id="StartLabel1"
                        label="选择一个"/>
<labelControl id="StartLabel2"
                        label="开始点"/>
<labelControl id="StartLabel3"
                        label="用于计算."/>
</group>

这个选项卡按照工作流设计,确保用户从左至右,按顺序执行完整个工作过程。
RibbonXApplication1
选择正确的等式
如上图所示,默认选择的是“贷款”切换按钮,当选择“年金”或“有效利率”时,其右侧的组将呈现不同的项目供输入计算数据。当然,这里的“等式”组也可以使用拆分按钮或库的方式。无论使用哪种方式,都必须提供给用户选择等式。本例中,使用的切换按钮在许多情形下都工作得非常好。三个切换按钮的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>

当用户单击某个切换按钮时,应用onAction属性提供的方法

    Public Sub SetupLoan(ByRef control As Office.IRibbonControl, ByVal pressed As Boolean)
' 设置计算类型
        CalcType = "Loan"
 
' 设置按下状态
        pressed = True
 
' 使整个功能区无效
        ribbon.Invalidate()
End Sub
 
Public Sub SetupAnnuity(ByRef control As Office.IRibbonControl, ByVal pressed As Boolean)
' 设置计算类型
        CalcType = "Annuity"
 
' 设置按下状态
        pressed = True
 
' 使整个功能区无效
        ribbon.Invalidate()
End Sub
 
Public Sub SetupEF(ByRef control As Office.IRibbonControl, ByVal pressed As Boolean)
' 设置计算类型
        CalcType = "Effective Rate"
 
' 设置按下状态
        pressed = True
 
' 使整个功能区无效
        ribbon.Invalidate()
End Sub

变量CalcType是一个字符串型的全局变量,用来追踪所使用的等式。这个变量决定应用程序的许多操作,甚至选项卡的最终外观。
设置pressed为true,改变目标控件的状态,但不会影响选项卡中的其他控件,而该应用程序在用户选择不同的等式时会更改许多控件,因此需要调用ribbon.Invalidate()来使整个功能区无效,从而重绘功能区。
然后,Excel调用getPressed属性指向的方法。本例中,所有三个切换按钮都使用相同的方法,因为它们实质上都执行相同的任务。SelectedEquation()方法的代码如下:

    Public Function SelectedEquation(ByRef control As Office.IRibbonControl) As Boolean
' 基于当前的等式确定按下状态
        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语句来选择计算类型,并给调用者返回True或False。返回值确定是否按下了该控件。
定义多个功能区元素
本例虽然只是自定义设计了单个选项卡,但是多重设计给应用程序在单个选项卡中提供多个功能的外观界面。当用户选择特定的等式时,选项卡内容改变以反映该等式的需求。跨功能区的控件让用户从左移到右以解决特定的问题,而工作表显示用户输入的项目的结果,下图显示了选择一个等式并输入数据后的结果。
RibbonXApplication2
注:三个等式都是相当简单的财务等式,Excel已经提供了这些工作表函数:PMT、FV、EFFECT。由于三个函数所需要的输入项不同,因此功能区中设计的控件也不同。例如,计算FV函数的功能区界面如下(在“等式”组中选择“年金”):
RibbonXApplication3
下面列出了选项卡中呈现不同视图所需要的XML:

        <group id="DataEntry" getLabel="GetDataEntryLabel">
<editBox id="Rate"
                   label="利率"
                   onChange="GetRateText"/>
<dropDown id="Term"
                    label="期数"
                    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>

注意,本应用程序如何使用不同的属性来在不同的情形下看到每个所需要的控件。“利率”控件出现在每个应用程序中,因此不需要使用getVisible属性。其他的控件都有getVisible属性,根据当前等式选择决定该控件是否出现在功能区。各控件的getVisible属性对应的回调代码如下:

    Public Function TermVisible(ByRef control As Office.IRibbonControl) As Boolean
' 应用程序不会使用该字段进行有效利率计算
        If CalcType = "Effective Rate" Then
Return False
Else
Return True
End If
End Function
 
Public Function PaymentVisible(ByRef control As Office.IRibbonControl) As Boolean
' 当处理年金计算时应用程序仅使用该字段
        If CalcType = "Annuity" Then
Return True
Else
Return False
End If
End Function
 
Public Function AmountVisible(ByRef control As Office.IRibbonControl) As Boolean
' 应用程序不会使用该字段进行有效利率计算
        If CalcType = "Effective Rate" Then
Return False
Else
Return True
End If
End Function

取决于变量CalcType,在功能区中呈现相应的控件。这是一项编程技巧,在代码中仅使用一个变量来控制应用程序的外观。
比较上面的两个图,你会发现在选择不同的切换按钮后,其右侧组中的标签不同,这是由getLabel属性来实现的:

    Public Function GetDataEntryLabel(ByRef control As Office.IRibbonControl) As String
' 通过计算类型的选择决定组标签
        Select Case CalcType
Case "Loan"
Return "输入贷款信息"
Case "Annuity"
Return "输入年金信息"
Case "Effective Rate"
Return "输入有效利率信息"
Case Else
Return "没有实现!"
End Select
End Function
 
Public Function AmountLabel(ByRef control As Office.IRibbonControl) As String
' 通过计算类型的选择决定数量标签
        ' 由于有效利率计算不使用该控件,因此应用程序不给它提供标签
        Select Case CalcType
Case "Loan"
Return "贷款金额"
Case "Annuity"
Return "每月年金付款"
Case Else
Return "没有实现!"
End Select
End Function

应用程序根据选择调整控件及显示。注意,应该小心使用ribbon.Invalidate(),最好仅在应用程序中包含一次对该方法的调用,否则可能会引发很多问题。
获取在功能区中输入的数据
功能区不允许任何直接的交互,因此不能直接获取用户输入到功能区控件中的信息。但如何获取这些信息呢?仍然要使用回调。大多数控件提供了onChange属性,能够用于发现控件数据的变化,但下拉列表例外,需要使用onAction属性发现选项的变化。下面的代码显示了onChange属性的实现及Term控件的onAction属性的实现。

    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)
' 存储默认值
        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()将文本框中输入的数据值转换为数字,如果用户在文本框中输入的不是数字,那么Int32.Parse()方法将输出0。
执行计算
需要两段代码。第一段代码响应功能区中单击“开始计算”按钮的操作;第二段代码转换所有数据为字符串,然后在执行计算之前将它们放置到Excel中。

    Public Sub Calculate(ByRef control As Office.IRibbonControl)
' 选择计算并调用
        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

因为应用程序已经在全局变量中放置了所需的数据,因此所有需要做的就是调用合适的加载项函数并提供必需的输入。实际上,计算需要构建与Excel公式命令相同的字符串。下面的代码显示了这些计算函数:

    ' 计算贷款数量
    Public Sub CalculatePMT(ByVal Rate As Double, ByVal NPer As Int32, ByVal PV As Int32)
' 计算利率
        Dim PeriodicRate As Double = (Rate / 100) / 12
 
' 计算期数
        Dim Periods As Int32 = NPer * 12
 
' 执行计算
        Application.ActiveWindow.ActiveCell.Cells(1, 1) = _
"=PMT(" + PeriodicRate.ToString() + "," + _
Periods.ToString() + "," + PV.ToString() + ",0,0)"
Application.ActiveWindow.ActiveCell.Calculate()
End Sub
 
' 计算年金数量
    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
 
' 计算期数
        Dim Periods As Int32 = NPer * 12
 
' 执行计算
        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
 
' 执行计算
        Application.ActiveWindow.ActiveCell.Cells(1, 1) = _
"=EFFECT(" + PeriodicRate.ToString() + ",12)"
Application.ActiveWindow.ActiveCell.Calculate()
End Sub

在工作表中简单地添加文本,不能确保发生计算,因此代码的末尾调用Application.ActiveWindow.ActiveCell.Calculate()来执行计算。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多