使用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);
}
}
}
现在,当我修改Form的backgroundimage属性时,奇怪的行为开始了。我从各种来源下载了多个随机图像,并将它们设置为表单的背景图像。
当我设置其中一些并运行程序时,两个面板都有自定义光标。
当我设置其他图像时,只有第二个面板有光标。
我甚至找到了一个图像,其中panel1在前几秒内有光标,但是如果我在几秒钟之后碰巧退出面板,则会永久删除光标。
如果我将窗体的backgroundimagelayout属性更改为None而不是Tile,则无论图像是什么,光标都会工作。
整个项目中没有任何其他内容被修改。 1个表格,2个面板,1个图标作为光标,3个图像和一个完全无意义的(或者可能不是,也许我缺少某些东西)行为。
我只想找出导致这种行为的原因,因为我在处理更大的项目时遇到了这种行为,我花了一些时间来跟踪问题的核心。也许我不应该以这种方式使用游标,但问题仍然存在,是什么让c#以这样的方式表现出来,只有背景图像被修改。
我在这里制作了一个示例项目 - https://www.dropbox.com/s/bl4iomzyz1bv7kb/Sample.rar?dl=0
答案 0 :(得分:3)
从您使用的Icon.Handle属性的MSDN文章:
说得温和一点,这比它可能有点神秘。它的意思是只要Icon对象没有被销毁,Handle才有效。这是您的代码中的问题,您无法确保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类实现了IDisposable。所以成为一名优秀的.NET公民:
protected override void OnFormClosed(FormClosedEventArgs e) {
customCursor.Dispose();
base.OnFormClosed(e);
}
Fwiw,非常安全地假设如果微软可以再次设计.NET 1.0 Icon和Cursor类,以及Properties.Resources工具,他们可能会以不同的方式完成它:)