我正在尝试向Sparx EA添加自定义的UI页面。它提供了通过脚本添加ActiveX控件的功能。使用JScript,我已经做到了,但是由于ActiveX必须在每个客户端上注册,因此我宁愿使用已经安装在所有客户端上的Microsoft Forms。
我已经通过添加“ Forms.Form.1” ActiveX对象并将文本框,标签和按钮添加到所创建表单的控件属性中,成功构建了UI(外观方面)。 这些对象支持事件,但是我不知道如何分配事件处理程序。
这是我用来获取屏幕布局的JScript代码:
function _addControl(parentControl, controlProgId, controlName, left, top, width, height){
var newControl = parentControl.controls.add(controlProgId, controlName,1);
newControl.Name=controlName;
newControl._SetLeft(left);
newControl._SetTop(top);
newControl._SetWidth(width);
newControl._SetHeight(height);
return newControl;
}
function main(){
//Create main form
var form = Repository.AddTab("ScriptedForm", "Forms.Form.1");
if (null != form){
//Add control
var textBox1 = _addControl(form, "Forms.TextBox.1","TextBox1", 18,21,94,93);
var textBox2 = _addControl(form, "Forms.TextBox.1","TextBox2", 120, 21, 91, 93);
var btnTest = _addControl(form, "Forms.CommandButton.1", "btnTest", 60, 140, 90, 30);
btnTest.Caption = "Test";
//Here's where I assign the click event, but it's unhappy.
btnTest.add_Click(this.TextBox1_Click);
}
}
function TextBox1_Click(Object){
Session.Prompt("Click", promptOK);
}
add_Click事件需要一个类型为CommandButtonEvents_ClickEventHandler的参数。
我无法创建任何可以作为参数提交的内容。我尝试创建一个复制接口的JScript类,但没有任何乐趣。
答案 0 :(得分:2)
我认为您一次遇到了几个问题。
据我了解您的问题及其上下文,您正在以某种方式手动执行JScript
脚本。进行此EA将从内部开始SScripter.exe
。您会在 Debug 窗口中看到以下内容:
脚本完成后,该过程实际上终止了(因此也终止了您可能已经在UserControl
或Form
对象中注册的所有事件处理程序)。
JScript
对象实例作为.NET delegate
如果您可以某种方式延长脚本环境的寿命,并且可以将某些内容传递给事件,则您将意识到JScript
代码中的任何对象都将作为System.__ComObject
传递给EA中的.NET运行时。因此,您不能仅注册事件处理程序。
但是,当您从.NET评估对象时,您会发现它不是IDispatch
接口:
MemberNames:
ToString,
GetLifetimeService,
InitializeLifetimeService,
CreateObjRef,
Equals,
GetHashCode,
GetType
TargetInvocationException@mscorlib: 'COM target does not implement IDispatch.'
我用下面的代码做了一个小测试:
function MyClass(name)
{
this.name = name;
}
MyClass.prototype.Invoke = function(value)
{
Session.Output("name " + value);
return true;
}
function main()
{
var myClass = new MyClass("Hotzenplotz");
myClass.Invoke("some Value");
var ctrl = new ActiveXObject("IMASE.TestUserControl2");
ctrl.Repository = Repository;
ctrl.JavaScriptObject = myClass;
}
[ProgId(Global.ADDIN_NAME + Global.DOT + "TestUserControl2")]
[Guid("87156dd9-e947-44bf-92a9-e9554a5b1844")]
[ComVisible(true)]
public partial class TestUserControl2 : ActivexControl
{
public static string TabName { get; } = Global.ADDIN_NAME;
private static readonly Lazy<string> _controlId = new Lazy<string>(() =>
{
var attribute = typeof(TestUserControl).GetCustomAttribute<ProgIdAttribute>();
return attribute.Value;
});
private Timer timer;
public static string ControlId = _controlId.Value;
public Repository Repository { get; set; }
public object JavaScriptObject { get; set; }
public TestUserControl2()
{
timer = new Timer();
timer.Elapsed += TimerEvent;
timer.Interval = 5000;
timer.Enabled = true;
timer.Start();
}
~TestUserControl2()
{
Logger.Default.TraceInformation("I'm gonna die ... " + this.GetHashCode());
}
private void OnDispose(object sender, EventArgs e)
{
timer.Dispose();
}
private void TimerEvent(object source, ElapsedEventArgs e)
{
Logger.Default.TraceInformation("I'm still alive ... " + this.GetHashCode());
if(null == JavaScriptObject) return;
try
{
var memberNames = JavaScriptObject.GetType().GetMembers(BindingFlags.Instance|BindingFlags.FlattenHierarchy|BindingFlags.Public).Select(p => p.Name);
Logger.Default.TraceInformation("memberNames: " + string.Join(", ", memberNames));
var result = JavaScriptObject.GetType().InvokeMember("Invoke", BindingFlags.InvokeMethod, null, JavaScriptObject, new object[] {"arbitraryString"});
Logger.Default.TraceInformation("result: " + result);
}
catch (Exception ex)
{
Logger.Default.TraceException(ex);
}
}
}
在外接程序中创建UserControl
(使用WinForm
或Forms
),然后将ClearScript
用作ScriptEngine。
将EA脚本中的Session
和Repository
传递给您的控件(或执行其他操作,例如使用菜单来解决生命周期问题),并让您的表单代码从存储库中加载脚本(或任何其他来源)。然后对事件处理程序做出反应,以根据需要执行JScript
代码。我创建了一个简单的示例,该示例演示如何从EA JScript
调用控件,并从表单代码内部调用另一个JScript
,然后依次登录到Debug会话或常规脚本输出窗口:>
function main()
{
var ctrl = new ActiveXObject("IMASE.TestUserControl2");
ctrl.Repository = Repository;
ctrl.Session = Session;
Session.Prompt("wait", promptOK);
}
main();
在表单代码中,您可以使用JScript
和其他类似的对象来调用Repository
:
public Repository Repository { get; set; }
public object Session { get; set; }
using (var engine = new JScriptEngine())
{
engine.AddHostObject("Repository", this.Repository);
engine.AddHostObject("Session", this.Session);
engine.Execute("Session.Output('Repository.ConnectionString: ' + Repository.ConnectionString);");
}
以下是上述脚本交互的输出:
侧面说明:我个人认为不需要使用表单,因为我们可以在AddIn启动时动态注册ActiveX控件。有关执行此操作的代码,请查看以下要点:
https://gist.github.com/dfch/6a27bb1b9320c93456cee6d5b2b9d551
此外,如果您使用ClearScript
作为脚本宿主,则可以按照ClearScript FAQtorial问题#16中的描述,通过脚本代码直接连接到(UI)事件。