我有一个名为BackImage的属性的UserControl:
public Metafile BackImage { get; set; }
然后我使用以下代码在Paint事件中将此图像作为UserControl的背景绘制:
if (BackImage != null)
e.Graphics.DrawImage(BackImage, this.ClientRectangle);
我使用.wmf图像,因为我需要在调整UserControl大小时使用矢量格式。
在设计时将UserControl拖动到窗体并通过Visual Studio中的属性窗口设置此属性时,重新绘制时图像会正确显示。
问题是,在运行程序时,Visual Studio会抛出一个" InvalidCastException"包含表单的设计器文件中的错误。这是错误行:
this.imageControl1.BackImage = ((System.Drawing.Imaging.Metafile)(resources.GetObject("imageControl1.BackImage")));
这是Visual Studio中众所周知的错误: http://www.tek-tips.com/viewthread.cfm?qid=425541
由于图像也必须在设计时显示,因此无法在运行时加载它。
问题: 而不是属于Metafile类型的属性是否可以使用一种原始格式,然后在代码中使用它时只需转换或类型转换它?
答案 0 :(得分:4)
此问题是由于GDI +缺乏对Emf / Wmf元文件编码的支持所致。它只能读取它们。选择元文件时获得的内置图像编辑器会将其转换为PNG图像以绕过限制。您将看到它显示在设计器中,但它实际上不是图元文件。此PNG图像也存储在.resx文件中。然后当您运行程序时,Kaboom无法将PNG转换为图元文件。
因此,解决方法是不要将属性设置为元文件,这是无法工作的。我在查找替代方案时遇到了很多麻烦,因为属性类型使得代码序列化程序在尝试查找类型转换器时挂起,因此明显选择了byte []。很奇怪,不明白为什么。我决定使用List<byte>
代替:
private List<byte> BackImageBytes;
[Editor(typeof(MyMetafileEditor), typeof(UITypeEditor))]
public List<byte> BackImage {
get { return BackImageBytes; }
set {
BackImageBytes = value;
if (value == null) base.BackgroundImage = null;
else base.BackgroundImage = new Metafile(new System.IO.MemoryStream(value.ToArray()));
}
}
您需要覆盖BackgroundImage属性,以便它不会被序列化:
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override Image BackgroundImage {
get { return base.BackgroundImage; }
set { base.BackgroundImage = value; }
}
该属性的上下文菜单中的Reset命令已禁用,您需要添加此命令才能获取它:
private void ResetBackImage() {
BackImage = null;
}
最后你需要替换默认的属性编辑器,它需要加载一个元文件并将其转换为一个列表:
class MyMetafileEditor : UITypeEditor {
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) {
using (var dlg = new OpenFileDialog()) {
dlg.Filter = "Metafiles (*.wmf, *.emf)|*.wmf;*.emf";
if (dlg.ShowDialog() == DialogResult.OK) {
value = new List<byte>(System.IO.File.ReadAllBytes(dlg.FileName));
}
}
return value;
}
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) {
return UITypeEditorEditStyle.Modal;
}
}