Powershell:无法与存储在.Net程序集中的表单进行交互

时间:2013-10-11 07:16:51

标签: c# winforms powershell

我只是想学习这个东西,并且将来想在我的一个项目中使用它。

我有一个带有简单文本框的小表单,存储在.Net dll(C#)中。这是我在这个dll中的类,其中包含与此表单交互的方法:

using System;
using System.Collections.Generic;
using System.Text;

namespace ClassLibrary1
{
    public class Class1
    {
        static Form1 dlg = new Form1();

        public static void ShowForm()
        {
            dlg.ShowIcon = true;
            dlg.Show();

        }

        public static void SetText(string MyText)
        {
            dlg.Text = "Form Text ";
            dlg.SetText(MyText);

        }
    }
}

通过在调用其方法时将此dll引用到另一个C#应用程序中成功加载此表单,即:。

private void button1_Click(object sender, EventArgs e)
{
    ClassLibrary1.Class1.ShowForm();
}

我能够完美地与形式互动。

现在使用以下方法在Powershell中加载相同内容:

[Reflection.Assembly]::LoadFile("D:\Playing\ClassLibrary1\ClassLibrary1\bin\Debug\ClassLibrary1.dll")
[ClassLibrary1.Class1]::ShowForm()

现在这已成功加载到其默认位置,但我无法与此表单进行交互,即我无法输入其文本框,也无法通过单击其关闭(x)来移动甚至关闭此表单右上角的按钮。每当我把鼠标放在它上面时,它就变成了一个HourGlass,即等待某个过程。

要验证表单是否未被挂起,我在Powershell提示符下调用了SetText:

[ClassLibrary1.Class1]::SetText("String from Powershell")

它工作正常。 TextBox正确地收到了这个文本,但我仍然无法用鼠标与表单进行交互。

我觉得,我必须手动设置它的Window Handler,即System.Windows.Forms.IWin32Window。 但我不知道哪个Handler以及如何实现这个目标?

请指导....非常感谢任何其他技巧。

1 个答案:

答案 0 :(得分:3)

您无法使用Form.Show()方法从PowerShell显示表单,因为它需要一个消息泵(并且PowerShell主机进程不提供它)。

您可以采取以下措施来解决此问题:

  • 使用Form.ShowDialog()Application.Run(),您的表单将有自己的消息泵。
  • 它将是模态的,然后你需要在另一个线程中运行它。我建议您在BeginInvoke()方法中使用后台主题和SetText()

这里有代码(我不会过多地更改你的代码所以我会将它保留为单例实例,即使这会阻止多次显示表单)。代码只是一个例子(我不建议使用线程池来完成此任务)来说明该过程。

public static void ShowForm()
{
    if (dlg != null)
        dlg.BeginInvoke(new MethodInvoker(delegate { dlg.Dispose(); }));

    ThreadPool.QueueUserWorkItem(delegate(object state)
    {
        Application.Run(_dlg = new Form1());
    });
}

public static void SetText(string text)
{
    _dlg.BeginInvoke(new MethodInvoker(delegate { dlg.SetText(text); }));
}

这样Form1将在另一个线程(具有自己的消息泵)中进行模态化,并且不会停止调用PowerShell线程。通过消息调度(Invoke() / BeginInvoke())仍然可以实现它们之间的通信。

请注意,SetText()现在是异步的,要使其同步,只需将BeginInvoke()替换为Invoke()