在使用Windows窗体在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);
}
}
}
现在,当我修改窗体的backgroundimage属性时,奇怪的行为开始了.我从各种来源下载了多个随机图像,并将它们设置为表单的背景图像.
>当我设置其中一些并运行程序时,两个面板都有其自定义光标.
>当我设置其他图像时,只有第二个面板具有其光标.
>我什至在前几秒钟就找到了panel1带有光标的图像,但是如果我恰好在几秒钟后走出并回到面板中,则光标将被永久删除.
如果将表单的backgroundimagelayout属性更改为None而不是Tile,则无论图像是什么,光标都将起作用.
整个项目中没有其他要修改的内容. 1个表单,2个面板,1个光标图标,3张图像和完全毫无意义的(也许不是,也许我缺少了)行为.
我只是想找出导致这种行为的原因,而在进行较大的项目时,我花了一些时间来跟踪问题的核心.也许我不应该以这种方式使用游标,但是问题仍然存在,当修改除背景图像之外的任何内容时,是什么使c#表现为这种方式.
我在这里做了一个示例项目-https://www.dropbox.com/s/bl4iomzyz1bv7kb/Sample.rar?dl=0
解决方法:
从MSDN文章中使用的Icon.Handle属性:
This is not a copy of the handle; do not free it.
坦率地说,这比可能要神秘得多.它的意思是,仅在不破坏Icon对象的情况下,Handle才有效.这是您的代码中的问题,您无法确保在任何地方都引用Properties.Resources.randomIcon返回的新对象.
因此,一旦垃圾收集器运行,图标对象就是历史记录.并且该句柄不再有效.这又使光标无效.图像的唯一相关性是它们对GC的影响.
您必须这样写:
private Icon customCursor;
public Form1()
{
InitializeComponent();
customCursor = Properties.Resources.Cat;
panel1.Cursor = panel2.Cursor = new Cursor(customCursor.Handle);
}
现在,只要表单对象保持活动状态,垃圾收集器始终会看到对Icon对象的引用.因此,其Handle属性保持有效.
奖牌也有另一面. Icon类实现IDisposable.因此,成为一个优秀的.NET公民:
protected override void OnFormClosed(FormClosedEventArgs e) {
customCursor.Dispose();
base.OnFormClosed(e);
}
Fwiw,非常安全地假设,如果Microsoft可以重新设计.NET 1.0 Icon和Cursor类,以及Properties.Resources工具,那么他们可能会做不同的事情:)