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

本文关键字:集中 程序集 窗体 交互 程序 Net 存储 Powershell | 更新日期: 2023-09-27 18:35:06

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

我有一个带有简单文本框的小窗体,存储在 .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) 按钮来移动甚至关闭此表单。每当我将鼠标放在上面时,它就会变成一个沙漏,即等待某个过程。

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

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

而且效果很好。文本框正确接收了此文本,但我仍然无法使用鼠标与表单进行交互。

我觉得,我必须手动设置它的窗口处理程序,即System.Windows.Forms.IWin32Window。但我不知道哪个处理程序以及如何实现这一点?

请指导....对于任何替代技巧,将不胜感激。

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

不能使用 Form.Show() 方法显示 PowerShell 中的窗体,因为它需要消息泵(并且 PowerShell 主机进程不提供)。

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

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

在这里的代码可以做到这一点(我不会过多地更改您的代码,因此即使这会阻止多次显示表单,我也会将其保留为单例实例)。代码只是一个示例(我不建议使用此任务使用线程池)来说明该过程。

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()即可。