自定义控件属性的初始化问题

时间:2021-08-01 16:02:58
我有一个自定义的控件,是扩展标准TextBox的,功能就是增加一个水印效果,本来在VS2008的写了一个,也没有什么大问题,但我把它弄到VS2010上的时候就会出现一些莫名其妙的报错:每次设置属性WaterMark后按F5,就会提示生成代码错误,未将对象引用到对象实例,或是类型为WaterMarkStyle的对象无法转换为WaterMarkStyle,.....

还有就是如果我在窗体上创建这个定义的TextBox的一个实例,并在属性窗口的WaterMark属性上右击选"重置",再按F5,一定会出现下图的错误消息:
自定义控件属性的初始化问题
同时,属性窗口中WaterMark前面的+号也消失,不会再出现里面的Text和Color属性

下观是节选的部分代码:


        //
        //自定义的TextBox中WaterMark属性的定义
        //
        static object WaterMarkChangedEvent = new object();
        /// <summary>
        /// 当WaterMark属性更改时触发.
        /// </summary>
        public event EventHandler WaterMarkChanged
        {
            add { Events.AddHandler(WaterMarkChangedEvent, value); }
            remove { Events.RemoveHandler(WaterMarkChangedEvent, value); }
        }
        WaterMarkStyle waterMark = new WaterMarkStyle("",SystemColors.GrayText);
        /// <summary>
        /// 获取或设置控件的水印效果.
        /// </summary>
        [DefaultValue(typeof(WaterMarkStyle),"")]
        [Browsable(true)]
        public WaterMarkStyle WaterMark
        {
            get { return waterMark; }
            set 
            {
                if (waterMark==value) return ;
                waterMark = value;
                OnWaterMarkChanged(EventArgs.Empty);
            }
        }


       //... ...


    //
    //WaterMarkStyle类型定义
    //
    /// <summary>
    /// 可编辑控件的水印样式
    /// </summary>
    [TypeConverter(typeof(WaterMarkStyleTypeConverter))]
    [ComVisible(true)]
    [Serializable]
    public struct WaterMarkStyle
    {
        string text;
        Color color;
        /// <summary>
        /// 获取或设置水印文本.
        /// </summary>
        [DefaultValue("")]
        public string Text
        {
          
            get { return text; }
            set 
            {
                if (text == value) return;
                text = value;
            }
        }
        /// <summary>
        /// 获取或设置水印颜色.
        /// </summary>
        [DefaultValue(typeof(Color),"GrayText")]
        public Color Color
        {
            get { return color; }
            set 
            {
                if (color==value) return ;
                color = value;
            }
        }
        /// <summary>
        /// 重写父类的判等方法.
        /// </summary>
        /// <param name="obj">与当前实例比较的目标对象</param>
        /// <returns>如果两个对象相等则返回true,否则返回false.</returns>
        public override bool Equals(object obj)
        {
            if (obj == null || !(obj is WaterMarkStyle)) return false;
            WaterMarkStyle wms = (WaterMarkStyle)obj;
            return this.text == wms.text && this.color == wms.color;
        }
        /// <summary>
        /// 获取类型当前实例的哈希码.
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return this.text.GetHashCode() ^ this.color.GetHashCode();
        }
        /// <summary>
        /// 获取类型当前实例的文本值.
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return this.text;
        }

        /// <summary>
        /// 判断给定两个参数是否相等
        /// </summary>
        /// <param name="wm1"></param>
        /// <param name="wm2"></param>
        /// <returns></returns>
        public static bool operator  ==(WaterMarkStyle wm1,WaterMarkStyle wm2)
        {
            if (wm1==null ^wm2==null)
            {
                return false;
            }
            return wm1.text == wm2.text && wm1.color.ToArgb() == wm2.color.ToArgb();
        }
        /// <summary>
        /// 判断给定两个参数是否不等.
        /// </summary>
        /// <param name="wm1"></param>
        /// <param name="wm2"></param>
        /// <returns></returns>
        public static bool operator !=(WaterMarkStyle wm1, WaterMarkStyle wm2)
        {
            if (wm1 == null ^ wm2 == null)
            {
                return true;
            }
            return wm1.text != wm2.text || wm1.color.ToArgb() != wm2.color.ToArgb();
        }
        /// <summary>
        /// 根据给定的文本和文本颜色,构造当前类型实例.
        /// </summary>
        /// <param name="text"></param>
        /// <param name="color"></param>
        public WaterMarkStyle(string text,Color color):this()
        {
            this.text = text;
            this.color = color;
        }
        /// <summary>
        /// 根据给定的文本和默认颜色,构造当前类型实例.
        /// </summary>
        /// <param name="text"></param>
        public WaterMarkStyle(string text) : this() 
        {
            this.text = text;
            this.color =SystemColors.GrayText;
        }
    }


    //类型转换器
    class WaterMarkStyleTypeConverter:TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType==typeof(string) || base.CanConvertFrom(context, sourceType);
        }
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            return destinationType ==typeof( InstanceDescriptor) || base.CanConvertTo(context, destinationType);
        }
        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            if (value != null)// return new WaterMarkStyle("",SystemColors.GrayText);// throw new ArgumentNullException("value");
            {
                if (value is string)
                {
                    WaterMarkStyle obj = (WaterMarkStyle)TypeDescriptor.GetProperties(typeof(TextBox))["WaterMark"].GetValue(context.Instance);

                    if (obj == null || obj.Color == Color.Empty)
                    {
                        return new WaterMarkStyle(value.ToString(), SystemColors.GrayText);
                    }
                    return new WaterMarkStyle(value.ToString(), obj.Color);
                }
            }
            return base.ConvertFrom(context, culture, value);
        }
        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType==null)
            {
                throw new ArgumentNullException("destinationType");
            }
            if (value != null)
            {
                WaterMarkStyle wms = (WaterMarkStyle)value;
                if (destinationType == typeof(string))
                {
                    return wms.Text;
                }
                if (destinationType == typeof(InstanceDescriptor))
                {
                    ConstructorInfo ctor = typeof(WaterMarkStyle).GetConstructor(new Type[] { typeof(string), typeof(Color) });
                    if (ctor != null)
                    {
                        return new InstanceDescriptor(ctor, new object[] { wms.Text, wms.Color });
                    }

                }
            }
            return base.ConvertTo(context, culture, value, destinationType);
        }
        public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
        {
            return TypeDescriptor.GetProperties(typeof(WaterMarkStyle), attributes).Sort(new string[] { "Text", "Color" });
        }
        public override bool GetPropertiesSupported(ITypeDescriptorContext context)
        {
            return true;
        }

        public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
        {
            if (propertyValues == null)
            {
                throw new ArgumentNullException("propertyValues");
            }
            object obj2 = propertyValues["Text"];
            object obj3 = propertyValues["Color"];
            if (((obj2 == null) || (obj3 == null)) || (!(obj2 is string) || !(obj3 is Color)))
            {
                throw new ArgumentException("无效属性值!");
            }
            return new WaterMarkStyle(obj2 as string, (Color)obj3);
            
        }

        public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)
        {
            return true;
        }
    }



以上是水印样式的类型定义及类型转换器的定义.请高手们给看下,如果还需要其他的代码我再往上加!

16 个解决方案

#1


先站个沙发,顶~

#2


已经说得很清楚了 :未将对象设置到对象的实例,所设置的变量为空值或没有取到值,一般出现在传递参数的时候出现这个问题,   waterMark = value;
看看值有没有,另外 :控件名称与codebehind里面的没有对应,
解决方法:
(1)使用try..catch...finally捕捉错误,或直接用response.write()输出所取的变量值

  (2)查看代码中是否存在未初始化的变量



#3


功能简单一点的可以直接用ExpandableObjectConverter。

public class MyTextBox : TextBox
{
    WaterMarkStyle waterMark = new WaterMarkStyle("", SystemColors.GrayText);
    /// <summary>
    /// 获取或设置控件的水印效果.
    /// </summary>
    public WaterMarkStyle WaterMark
    {
        get { return waterMark; }
        set
        {
            if (waterMark != value)
            {
                waterMark = value;
            }
        }
    }

    /// <summary>
    /// 可编辑控件的水印样式
    /// </summary>
    [TypeConverter(typeof(ExpandableObjectConverter))]  //<---
    public class WaterMarkStyle
    {
        public WaterMarkStyle() : this("", SystemColors.GrayText)
        {
        }
        public WaterMarkStyle(string text, Color color) 
        {
            this.Text = text;
            this.Color = color;
        }

        /// <summary>  获取或设置水印文本. </summary>
        public string Text { get; set;}

        /// <summary> 获取或设置水印颜色. </summary>
        public Color Color {get; set;}

        #region 重写判等方法
        public override bool Equals(object obj)
        {
            return this == (obj as WaterMarkStyle);
        }
        public override int GetHashCode()
        {
            return (this.Text ?? "").GetHashCode() ^ this.Color.GetHashCode();
        }
        public override string ToString()
        {
            return this.Text;
        }
        public static bool operator ==(WaterMarkStyle wm1, WaterMarkStyle wm2)
        {
            if (object.ReferenceEquals(wm1, null) || object.ReferenceEquals(wm2, null) )
            {
                return object.ReferenceEquals(wm1, wm2);
            }
            return wm1.Text == wm2.Text && wm1.Color == wm2.Color;
        }
        public static bool operator !=(WaterMarkStyle wm1, WaterMarkStyle wm2)
        {
            return !(wm1 == wm2);
        }
        #endregion
        }
    }
}


如果要添加一些功能,象字符串转换,以及生成好看一些的代码,则可以提供自定义的TypeConverter:

private class WaterMarkStyleTypeConverter : ExpandableObjectConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
    }
    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        return destinationType == typeof(InstanceDescriptor) || base.CanConvertTo(context, destinationType);
    }
    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
        if (value is string)
        {
            Color color = SystemColors.GrayText;
            if (context != null && context.Instance != null && context.PropertyDescriptor != null)
            {
                WaterMarkStyle old = context.PropertyDescriptor.GetValue(context.Instance) as WaterMarkStyle;
                if (old != null && old.Color != SystemColors.GrayText) color = old.Color;
            }
            return new WaterMarkStyle((string)value, color);
        }
        return base.ConvertFrom(context, culture, value);
    }
    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
    {
        if (value is WaterMarkStyle && destinationType == typeof(InstanceDescriptor))
        {
            ConstructorInfo ctor = typeof(WaterMarkStyle).GetConstructor(new Type[] { typeof(string), typeof(Color) });
            if (ctor != null)
            {
                WaterMarkStyle wms = (WaterMarkStyle)value;
                return new InstanceDescriptor(ctor, new object[] { wms.Text, wms.Color });
            }
        }
        return base.ConvertTo(context, culture, value, destinationType);
    }
}

#4


该回复于2011-08-29 09:08:03被版主删除

#5


应该先判断一下OnWaterMarkChanged是否为空:

        /// <summary>
        /// 获取或设置控件的水印效果.
        /// </summary>
        [DefaultValue(typeof(WaterMarkStyle),"")]
        [Browsable(true)]
        public WaterMarkStyle WaterMark
        {
            get { return waterMark; }
            set 
            {
                if (waterMark==value) return ;
                waterMark = value;
                if(OnWaterMarkChanged != null)
                    OnWaterMarkChanged(EventArgs.Empty);
            }
        }

#6


引用 2 楼 gefangliang 的回复:
已经说得很清楚了 :未将对象设置到对象的实例,所设置的变量为空值或没有取到值,一般出现在传递参数的时候出现这个问题,   waterMark = value;
看看值有没有,另外 :控件名称与codebehind里面的没有对应,
解决方法:
(1)使用try..catch...finally捕捉错误,或直接用response.write()输出所取的变量值

(2)查看代码中是否存在未……


是个办法
调试,看具体是那个地方出现了问题

#7


LZ为了你的1点过发帖的工作精神 先帮顶一个来

#8


LZ这是我以前做的水印图片
这是生成验证码
-----------------------
 /**
         * IRequiresSessionState是一个空接口,仅用来
         * 标记handler是否对session拥有读写权
         */
        public void ProcessRequest(HttpContext context)
        {
            //1、建立画板
            Bitmap bitmap = new Bitmap(80, 30);
            //2、建立画布(绘图类)
            Graphics g = Graphics.FromImage(bitmap);
            //3、填充画布
            g.FillRectangle(Brushes.White, 0, 0, 80, 30);
            //4、设置字体
            Font f = new Font("隶书", 16);
            //5、在画布上写入字符
            string letters = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
            //6、定义变量,接受生成的随机字符串
            StringBuilder sb = new StringBuilder();
            //7、取字符
            Random r=new Random();
            //接受生成的单个随机字符
            string result = string.Empty;
            for (int i = 0; i < 4; i++)
            {
                result=letters.Substring(r.Next(0, letters.Length - 1), 1);
                sb.Append(result);
                g.DrawString(result, f, Brushes.Red, i * 15, r.Next(0, 10));
            }
            //8、输出到响应流
            context.Response.ContentType = "image/Jpg";
            bitmap.Save(context.Response.OutputStream, ImageFormat.Jpeg);
            //9、保存随机字符串到session
            context.Session["yanzheng"] = sb.ToString();
            //释放资源
            bitmap.Dispose();
            g.Dispose();
            context.Response.End();
        }

--------------------
这是水印
--------
 public void ProcessRequest(HttpContext context)
        {
            string path = context.Request.PhysicalPath;
            if (File.Exists(path))
            {
                System.Drawing.Image image = Image.FromFile(path);
                Graphics g = Graphics.FromImage(image);
                Font f = new Font("楷体", 12);
                g.DrawString("水印", f, Brushes.Red, 0, 0);
                image.Save(context.Response.OutputStream, ImageFormat.Jpeg);
                g.Dispose();
                image.Dispose();
                context.Response.End();
            }
        }

#9


这是上传的图片
 protected void btnUpload_Click(object sender, EventArgs e)
        {
            //获取图片路径
            string filePath = this.fuplImg.PostedFile.FileName;
            //获取文件名
            string fileName = this.fuplImg.FileName;
            //获取扩展名
            FileInfo info = new FileInfo(fileName);
            string type = info.Extension;
            //判断图片类型是否允许上传
            if (type == ".jpg" || type == ".bmp" || type == ".gif")
            {
                //获取图片存储位置的物理路径
                string path = Server.MapPath("Images//" + fileName);
                //上传保存
                this.fuplImg.PostedFile.SaveAs(path);
                //加载图片
                Image imgFile = new Image();
                imgFile.Width = 200;
                imgFile.Height = 150;
                imgFile.ImageUrl = @"~/Images/" + fileName;
                this.imgDiv.Controls.Add(imgFile);
                Page.ClientScript.RegisterStartupScript(typeof(Page), "", "alert('上传成功!')", true);
            }
            else
            {
                Page.ClientScript.RegisterStartupScript(typeof(Page), "", "alert('请检查上传图片的格式!')", true);
            }
        }

#10


楼主这种错误就是传参数的时候出的错误

再传参数的时候都加个判断就可以了

#11


引用 5 楼 ojlovecd 的回复:
应该先判断一下OnWaterMarkChanged是否为空:

C# code


        /// <summary>
        /// 获取或设置控件的水印效果.
        /// </summary>
        [DefaultValue(typeof(WaterMarkStyle),"")]
        [Browsable(true)]
 ……

同意这个看法,其他人的回复都是答非所问。
我在使用自定义事件的时候,都会加上是否为null的判断,所以从未出现过问题,这是个好习惯,任何可能出现null的地方,在使用前都要加为空判断。也许VS2008的编译机制和VS2010不一样了,导致你移植到VS2010去就报错。

#12


首先谢谢大家的热情参与和讨论,下面我再说几点:
1.关于事件检查为空的问题,是在OnWaterMarkChanged这个方法内部进行的:
protected virtual void OnWaterMarkChanged(EventArgs e)
{
   EventHandler handle=Events[MaterMarkChangedEvent] as EventHandler;
   if(handle!=null && handle.GetInvokedList().Length>0)
   {
      ... ...
   }
}


2.关于加try块调试,单从表面上看,错误的信息比较具体,但我可以比较确定的是和转换器的实现有很大关系,也就是说这个错误是在设计时支持里的,调试起来比较困难,因为你根本没法逐步的去调试,就算加上了Try块,我也不知道设计器会在什么时候执行这段代码并抛出异常.
3.说下目前的情况吧,其他的都差不多了,就还剩下一个问题,就是我设置了WaterMark属性后,F5运行,没有任何问题,包括后台自动生成的代码也可以了,但是我在这个属性上右击选"重置"后,就会出现上面图片上所示的错误,
理解是好理解,因为重置后WaterMark属性为空了呗,但我想知道,这个属性初始化定义的时候我是给了他值的,并且也使用了DefaultValueAttribute设置的默认值,就是空字符串,经过转换器后这个空串也应该被转换为一个空文本和GrayText颜色的WaterMarkStyle对象才对呀,怎么它就成了Null了呢?


最后感谢一下zyloveyrf吧,因为我这个是WinForm的,不是Web,所谓的这个水印效果就是当文本框 没有文本且没有焦点是时候在上面显示一个提示文本,如果输入的内容或获取地焦点,则不显示

这个问题能解决与否都没关系,希望大家都讨论一下!如果有不明白的请留言!

#13


你的转换器写错了,问题应该在这段代码,自己调试去:

        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            if (value != null)// return new WaterMarkStyle("",SystemColors.GrayText);// throw new ArgumentNullException("value");
            {
                if (value is string)
                {
                    WaterMarkStyle obj = (WaterMarkStyle)TypeDescriptor.GetProperties(typeof(TextBox))["WaterMark"].GetValue(context.Instance);

                    if (obj == null || obj.Color == Color.Empty)
                    {
                        return new WaterMarkStyle(value.ToString(), SystemColors.GrayText);
                    }
                    return new WaterMarkStyle(value.ToString(), obj.Color);
                }
            }
            return base.ConvertFrom(context, culture, value);
        }

这句:WaterMarkStyle obj = (WaterMarkStyle)TypeDescriptor.GetProperties(typeof(TextBox))["WaterMark"].GetValue(context.Instance);
ConvertFrom方法是用来将你的空字符串翻译到那个WaterMarkStyle 结构(注意,结构体不可能为空),你并未使用外部给的字符串来转换内部结构,而是用了自己的值来转换。if(obj == null)这个判断永不成立,当然,之前如果就是null的话WaterMarkStyle obj = ...这步就会报错,无法将null转换为WaterMarkStyle结构体,如果是类,不会报错,但是你这个是结构体,没有为null的结构体。

#14


你原先代码是转换器ConvertFrom里有问题:
WaterMarkStyle obj = (WaterMarkStyle)TypeDescriptor...

我在3楼的代码,如果要支持重置,则WaterMarkStyle类不能是MyText的内嵌类(不知道Vistual Studio编辑器为什么要挑剔这个),要单独出来。
[DefaultValue(typeof(WaterMarkStyle), "")]
public WaterMarkStyle WaterMark
{
   get { return waterMark; }
   ...

#15


设置一个属性值就ok了

   public WaterMarkStyle WaterMark
    {
        get { return waterMark; }
        set
        {
            if (waterMark != value)
            {
                waterMark = value;
            }
        }
    }

#16


谢谢qldsrx和gomoku了
的确是这样,问题的确就出在WaterMarkStyle obj = (WaterMarkStyle)TypeDescriptor.GetProperties(typeof(TextBox))["WaterMark"].GetValue(context.Instance);
因为重置后,TypeDescriptor.GetProperties(typeof(TextBox))["WaterMark"].GetValue(context.Instance);
得到值为空,此处会引发异常,由于ConvertFrom方法没有返回值,所以会提示一个空引用的异常.

#1


先站个沙发,顶~

#2


已经说得很清楚了 :未将对象设置到对象的实例,所设置的变量为空值或没有取到值,一般出现在传递参数的时候出现这个问题,   waterMark = value;
看看值有没有,另外 :控件名称与codebehind里面的没有对应,
解决方法:
(1)使用try..catch...finally捕捉错误,或直接用response.write()输出所取的变量值

  (2)查看代码中是否存在未初始化的变量



#3


功能简单一点的可以直接用ExpandableObjectConverter。

public class MyTextBox : TextBox
{
    WaterMarkStyle waterMark = new WaterMarkStyle("", SystemColors.GrayText);
    /// <summary>
    /// 获取或设置控件的水印效果.
    /// </summary>
    public WaterMarkStyle WaterMark
    {
        get { return waterMark; }
        set
        {
            if (waterMark != value)
            {
                waterMark = value;
            }
        }
    }

    /// <summary>
    /// 可编辑控件的水印样式
    /// </summary>
    [TypeConverter(typeof(ExpandableObjectConverter))]  //<---
    public class WaterMarkStyle
    {
        public WaterMarkStyle() : this("", SystemColors.GrayText)
        {
        }
        public WaterMarkStyle(string text, Color color) 
        {
            this.Text = text;
            this.Color = color;
        }

        /// <summary>  获取或设置水印文本. </summary>
        public string Text { get; set;}

        /// <summary> 获取或设置水印颜色. </summary>
        public Color Color {get; set;}

        #region 重写判等方法
        public override bool Equals(object obj)
        {
            return this == (obj as WaterMarkStyle);
        }
        public override int GetHashCode()
        {
            return (this.Text ?? "").GetHashCode() ^ this.Color.GetHashCode();
        }
        public override string ToString()
        {
            return this.Text;
        }
        public static bool operator ==(WaterMarkStyle wm1, WaterMarkStyle wm2)
        {
            if (object.ReferenceEquals(wm1, null) || object.ReferenceEquals(wm2, null) )
            {
                return object.ReferenceEquals(wm1, wm2);
            }
            return wm1.Text == wm2.Text && wm1.Color == wm2.Color;
        }
        public static bool operator !=(WaterMarkStyle wm1, WaterMarkStyle wm2)
        {
            return !(wm1 == wm2);
        }
        #endregion
        }
    }
}


如果要添加一些功能,象字符串转换,以及生成好看一些的代码,则可以提供自定义的TypeConverter:

private class WaterMarkStyleTypeConverter : ExpandableObjectConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
    }
    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        return destinationType == typeof(InstanceDescriptor) || base.CanConvertTo(context, destinationType);
    }
    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
        if (value is string)
        {
            Color color = SystemColors.GrayText;
            if (context != null && context.Instance != null && context.PropertyDescriptor != null)
            {
                WaterMarkStyle old = context.PropertyDescriptor.GetValue(context.Instance) as WaterMarkStyle;
                if (old != null && old.Color != SystemColors.GrayText) color = old.Color;
            }
            return new WaterMarkStyle((string)value, color);
        }
        return base.ConvertFrom(context, culture, value);
    }
    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
    {
        if (value is WaterMarkStyle && destinationType == typeof(InstanceDescriptor))
        {
            ConstructorInfo ctor = typeof(WaterMarkStyle).GetConstructor(new Type[] { typeof(string), typeof(Color) });
            if (ctor != null)
            {
                WaterMarkStyle wms = (WaterMarkStyle)value;
                return new InstanceDescriptor(ctor, new object[] { wms.Text, wms.Color });
            }
        }
        return base.ConvertTo(context, culture, value, destinationType);
    }
}

#4


该回复于2011-08-29 09:08:03被版主删除

#5


应该先判断一下OnWaterMarkChanged是否为空:

        /// <summary>
        /// 获取或设置控件的水印效果.
        /// </summary>
        [DefaultValue(typeof(WaterMarkStyle),"")]
        [Browsable(true)]
        public WaterMarkStyle WaterMark
        {
            get { return waterMark; }
            set 
            {
                if (waterMark==value) return ;
                waterMark = value;
                if(OnWaterMarkChanged != null)
                    OnWaterMarkChanged(EventArgs.Empty);
            }
        }

#6


引用 2 楼 gefangliang 的回复:
已经说得很清楚了 :未将对象设置到对象的实例,所设置的变量为空值或没有取到值,一般出现在传递参数的时候出现这个问题,   waterMark = value;
看看值有没有,另外 :控件名称与codebehind里面的没有对应,
解决方法:
(1)使用try..catch...finally捕捉错误,或直接用response.write()输出所取的变量值

(2)查看代码中是否存在未……


是个办法
调试,看具体是那个地方出现了问题

#7


LZ为了你的1点过发帖的工作精神 先帮顶一个来

#8


LZ这是我以前做的水印图片
这是生成验证码
-----------------------
 /**
         * IRequiresSessionState是一个空接口,仅用来
         * 标记handler是否对session拥有读写权
         */
        public void ProcessRequest(HttpContext context)
        {
            //1、建立画板
            Bitmap bitmap = new Bitmap(80, 30);
            //2、建立画布(绘图类)
            Graphics g = Graphics.FromImage(bitmap);
            //3、填充画布
            g.FillRectangle(Brushes.White, 0, 0, 80, 30);
            //4、设置字体
            Font f = new Font("隶书", 16);
            //5、在画布上写入字符
            string letters = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
            //6、定义变量,接受生成的随机字符串
            StringBuilder sb = new StringBuilder();
            //7、取字符
            Random r=new Random();
            //接受生成的单个随机字符
            string result = string.Empty;
            for (int i = 0; i < 4; i++)
            {
                result=letters.Substring(r.Next(0, letters.Length - 1), 1);
                sb.Append(result);
                g.DrawString(result, f, Brushes.Red, i * 15, r.Next(0, 10));
            }
            //8、输出到响应流
            context.Response.ContentType = "image/Jpg";
            bitmap.Save(context.Response.OutputStream, ImageFormat.Jpeg);
            //9、保存随机字符串到session
            context.Session["yanzheng"] = sb.ToString();
            //释放资源
            bitmap.Dispose();
            g.Dispose();
            context.Response.End();
        }

--------------------
这是水印
--------
 public void ProcessRequest(HttpContext context)
        {
            string path = context.Request.PhysicalPath;
            if (File.Exists(path))
            {
                System.Drawing.Image image = Image.FromFile(path);
                Graphics g = Graphics.FromImage(image);
                Font f = new Font("楷体", 12);
                g.DrawString("水印", f, Brushes.Red, 0, 0);
                image.Save(context.Response.OutputStream, ImageFormat.Jpeg);
                g.Dispose();
                image.Dispose();
                context.Response.End();
            }
        }

#9


这是上传的图片
 protected void btnUpload_Click(object sender, EventArgs e)
        {
            //获取图片路径
            string filePath = this.fuplImg.PostedFile.FileName;
            //获取文件名
            string fileName = this.fuplImg.FileName;
            //获取扩展名
            FileInfo info = new FileInfo(fileName);
            string type = info.Extension;
            //判断图片类型是否允许上传
            if (type == ".jpg" || type == ".bmp" || type == ".gif")
            {
                //获取图片存储位置的物理路径
                string path = Server.MapPath("Images//" + fileName);
                //上传保存
                this.fuplImg.PostedFile.SaveAs(path);
                //加载图片
                Image imgFile = new Image();
                imgFile.Width = 200;
                imgFile.Height = 150;
                imgFile.ImageUrl = @"~/Images/" + fileName;
                this.imgDiv.Controls.Add(imgFile);
                Page.ClientScript.RegisterStartupScript(typeof(Page), "", "alert('上传成功!')", true);
            }
            else
            {
                Page.ClientScript.RegisterStartupScript(typeof(Page), "", "alert('请检查上传图片的格式!')", true);
            }
        }

#10


楼主这种错误就是传参数的时候出的错误

再传参数的时候都加个判断就可以了

#11


引用 5 楼 ojlovecd 的回复:
应该先判断一下OnWaterMarkChanged是否为空:

C# code


        /// <summary>
        /// 获取或设置控件的水印效果.
        /// </summary>
        [DefaultValue(typeof(WaterMarkStyle),"")]
        [Browsable(true)]
 ……

同意这个看法,其他人的回复都是答非所问。
我在使用自定义事件的时候,都会加上是否为null的判断,所以从未出现过问题,这是个好习惯,任何可能出现null的地方,在使用前都要加为空判断。也许VS2008的编译机制和VS2010不一样了,导致你移植到VS2010去就报错。

#12


首先谢谢大家的热情参与和讨论,下面我再说几点:
1.关于事件检查为空的问题,是在OnWaterMarkChanged这个方法内部进行的:
protected virtual void OnWaterMarkChanged(EventArgs e)
{
   EventHandler handle=Events[MaterMarkChangedEvent] as EventHandler;
   if(handle!=null && handle.GetInvokedList().Length>0)
   {
      ... ...
   }
}


2.关于加try块调试,单从表面上看,错误的信息比较具体,但我可以比较确定的是和转换器的实现有很大关系,也就是说这个错误是在设计时支持里的,调试起来比较困难,因为你根本没法逐步的去调试,就算加上了Try块,我也不知道设计器会在什么时候执行这段代码并抛出异常.
3.说下目前的情况吧,其他的都差不多了,就还剩下一个问题,就是我设置了WaterMark属性后,F5运行,没有任何问题,包括后台自动生成的代码也可以了,但是我在这个属性上右击选"重置"后,就会出现上面图片上所示的错误,
理解是好理解,因为重置后WaterMark属性为空了呗,但我想知道,这个属性初始化定义的时候我是给了他值的,并且也使用了DefaultValueAttribute设置的默认值,就是空字符串,经过转换器后这个空串也应该被转换为一个空文本和GrayText颜色的WaterMarkStyle对象才对呀,怎么它就成了Null了呢?


最后感谢一下zyloveyrf吧,因为我这个是WinForm的,不是Web,所谓的这个水印效果就是当文本框 没有文本且没有焦点是时候在上面显示一个提示文本,如果输入的内容或获取地焦点,则不显示

这个问题能解决与否都没关系,希望大家都讨论一下!如果有不明白的请留言!

#13


你的转换器写错了,问题应该在这段代码,自己调试去:

        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            if (value != null)// return new WaterMarkStyle("",SystemColors.GrayText);// throw new ArgumentNullException("value");
            {
                if (value is string)
                {
                    WaterMarkStyle obj = (WaterMarkStyle)TypeDescriptor.GetProperties(typeof(TextBox))["WaterMark"].GetValue(context.Instance);

                    if (obj == null || obj.Color == Color.Empty)
                    {
                        return new WaterMarkStyle(value.ToString(), SystemColors.GrayText);
                    }
                    return new WaterMarkStyle(value.ToString(), obj.Color);
                }
            }
            return base.ConvertFrom(context, culture, value);
        }

这句:WaterMarkStyle obj = (WaterMarkStyle)TypeDescriptor.GetProperties(typeof(TextBox))["WaterMark"].GetValue(context.Instance);
ConvertFrom方法是用来将你的空字符串翻译到那个WaterMarkStyle 结构(注意,结构体不可能为空),你并未使用外部给的字符串来转换内部结构,而是用了自己的值来转换。if(obj == null)这个判断永不成立,当然,之前如果就是null的话WaterMarkStyle obj = ...这步就会报错,无法将null转换为WaterMarkStyle结构体,如果是类,不会报错,但是你这个是结构体,没有为null的结构体。

#14


你原先代码是转换器ConvertFrom里有问题:
WaterMarkStyle obj = (WaterMarkStyle)TypeDescriptor...

我在3楼的代码,如果要支持重置,则WaterMarkStyle类不能是MyText的内嵌类(不知道Vistual Studio编辑器为什么要挑剔这个),要单独出来。
[DefaultValue(typeof(WaterMarkStyle), "")]
public WaterMarkStyle WaterMark
{
   get { return waterMark; }
   ...

#15


设置一个属性值就ok了

   public WaterMarkStyle WaterMark
    {
        get { return waterMark; }
        set
        {
            if (waterMark != value)
            {
                waterMark = value;
            }
        }
    }

#16


谢谢qldsrx和gomoku了
的确是这样,问题的确就出在WaterMarkStyle obj = (WaterMarkStyle)TypeDescriptor.GetProperties(typeof(TextBox))["WaterMark"].GetValue(context.Instance);
因为重置后,TypeDescriptor.GetProperties(typeof(TextBox))["WaterMark"].GetValue(context.Instance);
得到值为空,此处会引发异常,由于ConvertFrom方法没有返回值,所以会提示一个空引用的异常.