3

我试图使 Excel VBA 的自动变量(如 ActiveSheet 或 ActiveCell)也可作为 PowerShell 的“自动变量”使用。PowerShell 引擎托管在 Excel VSTO 加载项中,并且 Excel.Application 作为 Globals.ThisAddin.Application 提供给它。我在 StackOverflow 上找到了这个线程并开始创建 PSVariable 派生类,例如:

public class ActiveCell : PSVariable
{
    public ActiveCell(string name) : base(name) { }

    public override object Value
    {
        get 
        { 
            return Globals.ThisAddIn.Application.ActiveCell; 
        }
    }
}

public class ActiveSheet : PSVariable
{
    public ActiveSheet(string name) : base(name) { }

    public override object Value
    {
        get 
        { 
            return Globals.ThisAddIn.Application.ActiveSheet; 
        }
    }
}

并将它们的实例添加到当前的 POwerShell 会话中:

runspace.SessionStateProxy.PSVariable.Set(new ActiveCell("ActiveCell"));
runspace.SessionStateProxy.PSVariable.Set(new ActiveSheet("ActiveSheet"));

这很有效,我可以将 PowerShell 中的这些变量用作 $ActiveCell 和 $ActiveSheet(它们的值随着 Excel 活动表或单元格的变化而变化)。然后我在这里阅读了 PSVariable 文档并看到了这个:

“没有从此类派生的既定方案。要以编程方式创建 shell 变量,请创建此类的实例并使用 PSVariableIntrinsics 类对其进行设置。”

当我从 PSVariable 派生时,我尝试使用建议的内容:

PSVariable activeCell = new PSVariable("ActiveCell");
activeCell.Value = Globals.ThisAddIn.Application.ActiveCell;
runspace.SessionStateProxy.PSVariable.Set(activeCell);

使用它,$ActiveCell 出现在我的 PowerShell 会话中,但它的值不会随着我更改 Excel 中的活动单元格而改变。

PSVariable 文档中的上述评论是我应该担心的,还是我可以继续创建 PSVariable 派生类?是否有另一种使 Excel 全局变量可用于 PowerShell 的方法?

4

2 回答 2

5

我们的文档是错误的 - 这是一个受支持的场景。

以下是有关该技术的更多信息:

  1. http://poshcode.org/2198
  2. http://www.leeholmes.com/blog/2009/03/26/more-tied-variables-in-powershell/
  3. http://www.pavleck.net/powershell-cookbook/ch03.html

Lee Holmes [MSFT] Windows PowerShell 开发

于 2011-01-02T22:49:53.943 回答
0

显然,在您的第二个示例中,您不是从 PSVariable 派生的,您不能期望 $ActiveCell 变量随 ActiveCell 属性的值而改变,因为您只捕获了一次它的值。

我不相信从 PSVariable 派生是受支持的方案,但它确实有效,我已经完成它来添加变量,例如$Nowand $Today

将 $Application 变量而不是 Application 对象的各种属性公开给 PowerShell 脚本可能是一个更好的主意。这样做的好处是您不需要创建一堆自动变量,并且 PowerShell 脚本可以通过使用 $Application.ActiveCell 访问 Application 对象必须提供的任何内容。另一个好处是它根本不需要是一个自动变量,因为 Application 对象引用永远不会改变。

说了这么多,我已经包含了一个 PSVariable 的子类,我不时使用它,它需要一个 ScriptBlock 作为 getter 和 setter。这让我可以从 PowerShell 定义自动变量,而无需为每个变量单独派生类。

using System;
using System.Management.Automation;

namespace Einstein.PowerShell
{

    public sealed class DynamicVariable : PSVariable
    {

        #region Constructors

        /// <summary>
        /// </summary>
        public DynamicVariable(string name, ScriptBlock onGet)
            : this(name, onGet, null)
        {
        }

        /// <summary>
        /// </summary>
        public DynamicVariable(string name, ScriptBlock onGet, ScriptBlock onSet)
            : base(name, null, ScopedItemOptions.AllScope)
        {
            OnGet = onGet;
            OnSet = onSet;
        }

        #endregion

        #region Properties

        /// <summary>
        /// The ScriptBlock that runs to get the value of the variable.
        /// </summary>
        private ScriptBlock OnGet
        {
            get;
            set;
        }

        /// <summary>
        /// The ScriptBlock that runs to get the value of the variable.
        /// </summary>
        private ScriptBlock OnSet
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the underlying value of the variable.
        /// </summary>
        public override object Value
        {
            get
            {
                if (OnGet == null) {
                    return null;
                }
                return OnGet.Invoke();
            }
            set
            {
                if (OnSet == null) {
                    throw new InvalidOperationException("The variable is read-only.");
                }
                OnSet.Invoke(value);
            }
        }

        #endregion

    }

}
于 2011-01-02T22:09:55.700 回答