自定义光标异常?

Custom cursor anomaly?

我在使用 Windows Forms 在 c# 中使用自定义游标时遇到了一些奇怪的行为。我已将问题减少到一个新项目,其中包含 1 个表单、2 个面板添加到表单、1 个图标添加到项目的 properties/resources.resx,以及 3 个图像添加到同一个地方。

项目唯一的代码是这个

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TestProject
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            panel1.Cursor = new Cursor(Properties.Resources.randomIcon.Handle);
            panel2.Cursor = new Cursor(Properties.Resources.randomIcon.Handle);
        }
    }
}

现在,当我修改表单的背景图像 属性 时,奇怪的行为开始了。我从各种来源下载了多个随机图像并将它们设置为表单的背景图像。

如果我将表单的 backgroundimagelayout 属性 改为 None 而不是 Tile,则无论图像是什么,光标都有效。

整个项目中没有其他任何要修改的内容。 1 个表格、2 个面板、1 个图标作为光标、3 张图像和完全无意义的(或者可能不是,也许我遗漏了什么)行为。

我只是想找出导致这种行为的原因,因为我在处理更大的项目时遇到了这种情况,我花了一些时间来追踪问题的核心。也许我不应该以这种方式使用游标,但问题仍然存在,是什么让 c# 在仅修改背景图像时以这种方式运行。

我在这里做了一个示例项目 - https://www.dropbox.com/s/bl4iomzyz1bv7kb/Sample.rar?dl=0

来自您使用的 Icon.Handle 属性 的 MSDN 文章:

This is not a copy of the handle; do not free it.

委婉地说,这比实际情况更隐秘。它的意思是 Handle 仅在 Icon 对象未被销毁时才有效。这是您的代码中的一个问题,您没有确保 Properties.Resources.randomIcon 返回的 new 对象在任何地方都被引用。

所以垃圾收集器一运行,图标对象就成为历史。句柄不再有效。这反过来又使游标无效。图像的唯一相关性是它们对 GC 的影响。

你必须这样写:

    private Icon customCursor;

    public Form1()
    {
        InitializeComponent();
        customCursor = Properties.Resources.Cat;
        panel1.Cursor = panel2.Cursor = new Cursor(customCursor.Handle);
    }

现在,只要表单对象保持活动状态,垃圾收集器就会始终看到对 Icon 对象的引用。所以它的 Handle 属性 保持有效。

这奖牌还有另外一面。 Icon class 实现了 IDisposable。所以做一个好的 .NET 公民:

    protected override void OnFormClosed(FormClosedEventArgs e) {
        customCursor.Dispose();
        base.OnFormClosed(e);
    }

Fwiw,可以很安全地假设,如果 Microsoft 可以重新设计 .NET 1.0 图标和光标 classes,以及 Properties.Resources 设施,他们可能会采用不同的方式: )