自定义光标异常?
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);
}
}
}
现在,当我修改表单的背景图像 属性 时,奇怪的行为开始了。我从各种来源下载了多个随机图像并将它们设置为表单的背景图像。
当我设置其中一些和 运行 程序时,两个面板都有自己的自定义光标。
当我设置其他图片时,只有第二个面板有光标。
我什至找到了一张图片,其中 panel1 的前几秒有光标,但如果在那几秒后我碰巧离开并返回面板,光标就会永久消失删除。
如果我将表单的 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 设施,他们可能会采用不同的方式: )
我在使用 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);
}
}
}
现在,当我修改表单的背景图像 属性 时,奇怪的行为开始了。我从各种来源下载了多个随机图像并将它们设置为表单的背景图像。
当我设置其中一些和 运行 程序时,两个面板都有自己的自定义光标。
当我设置其他图片时,只有第二个面板有光标。
我什至找到了一张图片,其中 panel1 的前几秒有光标,但如果在那几秒后我碰巧离开并返回面板,光标就会永久消失删除。
如果我将表单的 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 设施,他们可能会采用不同的方式: )