MetaFile类型的属性是错误的,如何解决它?

时间:2014-05-17 13:46:12

标签: c# winforms visual-studio properties user-controls

我有一个名为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类型的属性是否可以使用一种原始格式,然后在代码中使用它时只需转换或类型转换它?

1 个答案:

答案 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;
        }
    }