【问题标题】:How to place a windows form in screen coords and close it on command?如何将窗口窗体放置在屏幕坐标中并按命令关闭它?
【发布时间】:2015-09-21 05:02:01
【问题描述】:

我正在开发 Windows 上的 c# 控制台程序来移动窗口,作为其中的一部分,我试图在目标目的地创建一个透明框,以便让用户直观地确认新位置。我目前面临两个主要问题:

  1. 我想将表单放置在屏幕坐标中
  2. 我希望能够在用户确认他们的决定后关闭窗口。

目前,我的控制台客户端正在调用的库中有执行此操作的代码:

    public static void CreateBox(Rect rectangle)
    {
        Form f = new Form();
        f.Name = BoxName;
        f.BackColor = Color.Blue;
        f.FormBorderStyle = FormBorderStyle.None;
        f.Bounds = new System.Drawing.Rectangle(rectangle.Left, rectangle.Top, rectangle.Right - rectangle.Left, rectangle.Bottom - rectangle.Top);
        f.TopMost = true;
        f.Opacity = 0.5;

        Application.EnableVisualStyles();
        Task.Run(() => Application.Run(f));
    }

在这里搜索了一些问题后,我想出了这个尝试稍后关闭表单:

    public static void RemoveBox()
    {
        Form f = Application.OpenForms[BoxName];

        if (f != null)
        {
            f.Close();
        }
    }

这是抛出一个异常,因为它来自不同的线程,我如何关闭这个窗口,以及如何将它放置在屏幕坐标中它应该去的确切位置?

编辑:

我现在正在使用它来尝试找到要移动/关闭它的框,但未成功:

    public static void CreateBox(Rect rectangle)
    {
        Form f = new Form();
        f.Name = BoxName;
        f.BackColor = Color.AliceBlue;
        f.FormBorderStyle = FormBorderStyle.None;
        f.TopMost = true;
        f.Opacity = 0.3;

        Application.EnableVisualStyles();
        Task.Run(() =>
        {
            Application.Run(f);
        });

        MoveBox(rectangle);
    }

    public static void RemoveBox()
    {
        IntPtr hWnd = FindBox(new TimeSpan(0, 0, 1));
        var proc = Process.GetProcesses().Where(p => p.Handle == hWnd).Single();
        if (proc == null)
        {
            return;
        }

        proc.Kill();
    }

    public static void MoveBox(Rect rect)
    {
        IntPtr hWnd = FindBox(new TimeSpan(0, 0, 1));
        MoveWindow(hWnd, rect);
    }

    private static IntPtr FindBox(TimeSpan timeout)
    {
        DateTime time = DateTime.Now;
        IntPtr hWnd = IntPtr.Zero;

        while(DateTime.Now < time.Add(timeout) || hWnd != IntPtr.Zero)
        {
            hWnd = FindWindowByCaption(IntPtr.Zero, BoxName);
        }

        return hWnd;
    }

这个问题:

  1. 我不能让 FindBox 调用花费很长时间,因为我的目标是让这个框出现并在用户拖动它们时将窗口捕捉到它们,并且需要在他们在桌面上移动时移动它。

  2. RemoveBox 函数中的 p.Handle == hWnd 检查抛出和访问被拒绝异常。

【问题讨论】:

    标签: c# winforms asynchronous


    【解决方案1】:

    如果你想做就让它工作吧: Form.CheckForIllegalCrossThreadCalls = false;

    在你的构造函数中,我不推荐它,因为它会使整个表单不再是线程安全的。

    【讨论】:

      【解决方案2】:

      编辑:这是我使用 WinForm 完成的快速测试。它也应该在控制台上运行良好。

      public partial class Form1 : Form
      {
          //Globals
          Form f;
          Task t;
      
          public Form1()
          {
              InitializeComponent();
      
              f = new Form();
              f.Name = "testForm";
              f.BackColor = Color.Blue;
              f.FormBorderStyle = FormBorderStyle.None;
              f.Bounds = new System.Drawing.Rectangle(0, 0, 100, 100);
              f.TopMost = true;
              f.Opacity = 0.5;
      
              Application.EnableVisualStyles();
      
              //f.Show();
               t = Task.Run(() => Application.Run(f));
          }
      
      
          private void btn_CloseForm_Click(object sender, EventArgs e)
          {
              if (f.InvokeRequired)
              {
                  this.Invoke(new CloseForm_Delegate(CloseForm));
              }
          }
      
          delegate void CloseForm_Delegate();
          private void CloseForm()
          {
              f.Close();
          }
      
      
      
          private void btn_MoveForm_Click(object sender, EventArgs e)
          {
              if (f.InvokeRequired)
              {
                  //set form position here
                  this.Invoke(new MoveForm_Delegate(MoveForm), new Point(0, 0));
      
              }
          }
      
          delegate void MoveForm_Delegate(Point p);
          private void MoveForm(Point p)
          {
              f.Location = p;
          }
      }
      

      【讨论】:

      • 当然,我不知道为什么我没有想到使用MoveWindow,已经在整个程序中使用它,会尝试那个和进程终止功能。谢谢!
      • Process.GetProcessesByName 没有找到我的进程,但我认为我错误地假设了我的进程名称,我使用表单的名称作为我正在搜索的名称,我该如何找到我的进程名称是什么或如何设置?
      • 很抱歉,我的解决方案仅适用于外部进程。 IE,你可以编译一个简单的包含透明屏幕的winform程序并用Process.Start()启动它。然后我的解决方案就可以了。如果您不想这样做,我建议您将您的表单作为全局并创建两个调用过程来移动和关闭它。
      • 将表单设为全局并创建调用过程是什么意思?
      猜你喜欢
      • 1970-01-01
      • 2012-06-06
      • 2011-04-30
      • 1970-01-01
      • 1970-01-01
      • 2011-09-04
      • 1970-01-01
      • 2016-10-21
      • 1970-01-01
      相关资源
      最近更新 更多