检查 X-Y 坐标是否位于保存在字典中的控件的范围内

Checking if X-Y co-ordinate lies within bounds of a control saved in a dictionary

我正在将 WinForm 控件的范围保存在字典中,例如:

Dictionary<Tuple<int, int>, Control> dictionary = 
    new Dictionary<Tuple<int, int>, Control>();

我正在以编程方式在 WinForm 上绘制控件。每当我绘制每个控件时,我都会将该控件的边界保存在此字典中,例如:

dictionary.Add(Tuple.Create(myControl.X, myControl.Y), myControl);
dictionary.Add(Tuple.Create(myControl.X + myControl.Length, myControl.Y), myControl);
dictionary.Add(Tuple.Create(myControl.X + myControl.Length, myControl.Y + myControl.Width), myControl);
dictionary.Add(Tuple.Create(myControl.X, myControl.Y + myControl.Width), myControl);

现在,我想要实现的是,每当鼠标点击 MouseEventArgs e 的 WinForm 时,我想检查 Point(e.X, e.Y) 是否在边界内有没有控件??

我知道我可以遍历字典的键值对并计算 Point(e.X,e.Y) 是否在边界内。但是我想避免遍历字典的Keys并得到解决方案。

知道如何在不遍历字典并计算每个点的情况下实现它吗?

迭代应该非常快,尤其是当您使用标准控件属性来确定它的位置和大小时。例如,此代码将生成 5000 个控件,给它们所有随机大小和位置,然后遍历每个控件并告诉您某个点是否位于其边界内。整个过程在我的机器上运行不到 0.4 秒:

var stopwatch = new Stopwatch();
stopwatch.Start();

Random rnd = new Random();

//Generate 500 controls with random positions
var controls = Enumerable.Range(0, 5000)
    .Select(index => new Control 
    {
        Top = rnd.Next(0, 1000), 
        Left = rnd.Next(0, 1000), 
        Width = rnd.Next(0, 1000), 
        Height = rnd.Next(0, 1000) 
    })
    .ToList();

var controlsUnderMouse = controls
    .Where(c => c.Bounds.Contains(150, 150))
    .ToList();

Console.WriteLine($"Found {controlsUnderMouse.Count()} controls in {stopwatch.Elapsed}");

这将输出如下内容:

Found 106 controls in 00:00:00.3939616

如果您只想寻找一个控件,您可以将 Where 更改为 First,这样 return 会更快。

试试这个。如果需要,可以将 int id 替换为 Control

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Reactive.Linq;
using System.Windows.Forms;

namespace Anything
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var random = new Random();
            var bounds = Screen.PrimaryScreen.Bounds;
            var extents = new Dictionary<int, Rectangle>();

            for (var i = 0; i < 300; i++)
            {
                var x = random.Next(bounds.Width);
                var y = random.Next(bounds.Height);
                var w = random.Next(bounds.Width - x);
                var h = random.Next(bounds.Height - y);

                extents[i] = new Rectangle(x, y, w, h);
            }

            var domains = from time in Observable.Interval(TimeSpan.FromMilliseconds(100))
                          from extent in extents
                          where extent.Value.Contains(Control.MousePosition)
                          select extent.Key;

            var subscription = domains.Subscribe(id => Console.Write($"{id},"));

            Console.ReadKey();

            subscription.Dispose();
        }
    }
}