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

C# Powershell:无法与存储在.Net程序集中的表单交互,c#,winforms,powershell,C#,Winforms,Powershell,我只是想学习这个东西,将来想在我的一个项目中使用它 我有一个带有简单文本框的小表单,存储在.NETDLL(C#)中。这是我在这个dll中的类,它包含与这个表单交互的方法: using System; using System.Collections.Generic; using System.Text; namespace ClassLibrary1 { public class Class1 { static Form1 dlg = new Form1();

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

我有一个带有简单文本框的小表单,存储在.NETDLL(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")
而且效果很好。TextBox正确地接收了此文本,但我仍然无法用鼠标与表单交互

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


请引导。。。。非常感谢您提供任何其他技巧。

您不能使用
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()

是否尝试使用Application.run()而不是Form.Show()运行它?我觉得它应该以正确的方式使用控制台应用程序中的表单。System.Windows.forms.application.Run(dlg)将表单显示为模式对话框,在关闭表单之前,我无法与Powershell交互。但您不能使用form.Show(),因为它没有可使用的消息泵。我会在单独的线程中使用ShowDialog()(或Application.Run())(在SetText()函数中使用BeginInvoke)。@Adriano:建议您重做您的注释作为答案,以便它可以被接受。@Adriano:此应用程序的目的是显示一个带有文本框等控件的对话框,然后传递文本消息以显示在该窗口中。如果我使用ShowDilog()或Application.Run(),这将阻止我在Powershell中发出命令。你能告诉我更多关于在SetText()中启动的信息吗?谢谢你有关于在C#中编写Ps cmdlet并使用winform交互的任何信息吗,因为应该已经有消息泵了?@FarrukhWaheed我刚才看到了你的消息…无论如何,消息泵是由两个东西提供的:Application.Run()或Form.ShowDialog()。即使您编写了C#cmdlet,它本身也不会有任何消息泵。是的,您是对的。一周前,我尝试了一个示例应用程序,得到了相同的结果。此外,还尝试了ShowUI()。它正在做我想做的,但没有提供足够的文档来采用它。@FarrukhWaheed我不知道那个项目。看起来还可以,但很遗憾,源代码不可用!啊。。我想,由于某些系统中断问题,源代码不可用。我只发现没有文件。