热门:网页模板.net视频教程JQueryMVCjsonExtJs源码示例三级联动JQuery菜单
您现在的位置:.Net中文社区>> .Net编程>>正文内容

关于ImageList.Images集合的特殊行为!

发布时间:2010年06月12日点击数: 佚名

这个问题是我在MSDN中文技术论坛中遇到的,现象十分诡异,仔细的研究了一下源代码,现在分享给大家,大家先看一段Demo:

  1. FileStream fs = new FileStream(@"D:\aa.jpg", FileMode.Open, FileAccess.Read); 
  2.             Image image = Image.FromStream(fs); 
  3.              
  4.             image.Tag = "txtbmp"
  5.             ImageList bigHeadPicList = new ImageList(); 
  6.             bigHeadPicList.Images.Add("1",image); 
  7.             Console.WriteLine(bigHeadPicList.Images["1"].Tag);  //这里Tag是null,相当意外! 
  8. 直观上感觉image和 bigHeadPicList.Images["1"]并不是同一对象,让我们通过源代码来验证这一点: 
  9. 先看ImageCollection 类的索引器的源代码: 
  10.                 public Image this[string key] { 
  11.                 get {  
  12.                     // We do not support null and empty string as valid keys.  
  13.                     if ((key == null) || (key.Length == 0)){ 
  14.                         return null;  
  15.                     } 
  16.  
  17.                     // Search for the key in our collection 
  18.                     int index = IndexOfKey(key);  
  19.                     if (IsValidIndex(index)) { 
  20.                         return this[index];  
  21.                     }  
  22.                     else { 
  23.                         return null;  
  24.                     } 
  25.  
  26.                 } 
  27.             }  

关键的实现都在另外一个索引器中:

  1. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
  2.             public Image this[int index] {  
  3.                 get { 
  4.                     if (index < 0 || index >= Count) 
  5.                         throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", index.ToString(CultureInfo.CurrentCulture))); 
  6.                     return owner.GetBitmap(index);   //这行代码比较关键 
  7.                 } 
  8.                 set {  
  9.                     if (index < 0 || index >= Count)  
  10.                         throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", index.ToString(CultureInfo.CurrentCulture))); 
  11.   
  12.                     if (value == null) { 
  13.                         throw new ArgumentNullException("value"); 
  14.                     } 
  15.   
  16.                    if (!(value is Bitmap)) 
  17.                         throw new ArgumentException(SR.GetString(SR.ImageListBitmap));  
  18.   
  19.                     AssertInvariant(); 
  20.                     Bitmap bitmap = (Bitmap)value;  
  21.  
  22.                     bool ownsImage = false
  23.                     if (owner.UseTransparentColor) { 
  24.                         // Since there's no ImageList_ReplaceMasked, we need to generate  
  25.                         // a transparent bitmap 
  26.                         Bitmap source = bitmap;  
  27.                         bitmap = (Bitmap) bitmap.Clone();  
  28.                         bitmap.MakeTransparent(owner.transparentColor); 
  29.                         ownsImage = true;  
  30.                     } 
  31.  
  32.                     try { 
  33.                         IntPtr hMask = ControlPaint.CreateHBitmapTransparencyMask(bitmap);  
  34.                         IntPtr hBitmap = ControlPaint.CreateHBitmapColorMask(bitmap, hMask); 
  35.                         bool ok = SafeNativeMethods.ImageList_Replace(new HandleRef(owner, owner.Handle), index, new HandleRef(null, hBitmap), new HandleRef(null, hMask));  
  36.                         SafeNativeMethods.DeleteObject(new HandleRef(null, hBitmap));  
  37.                         SafeNativeMethods.DeleteObject(new HandleRef(null, hMask)); 
  38.   
  39.                         if (!ok) 
  40.                             throw new InvalidOperationException(SR.GetString(SR.ImageListReplaceFailed)); 
  41.  
  42.                     } finally {  
  43.                         if(ownsImage) { 
  44.                             bitmap.Dispose();  
  45.                         }  
  46.                     } 
  47.                 }  
  48.           } 

这行代码比较关键:

  1. return owner.GetBitmap(index);   

下面我们看看GetBitmap方法的实现:

  1. private Bitmap GetBitmap(int index) { 
  2.             if (index < 0 || index >= Images.Count) 
  3.                 throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", index.ToString(CultureInfo.CurrentCulture)));  
  4.  
  5.             Bitmap result=null;  
  6.  
  7.             if(ColorDepth == ColorDepth.Depth32Bit) {  
  8.   
  9.                 NativeMethods.IMAGEINFO imageInfo = new NativeMethods.IMAGEINFO(); // review? do I need to delete the mask and image inside of imageinfo? 
  10.                 if(SafeNativeMethods.ImageList_GetImageInfo(new HandleRef(thisthis.Handle), index, imageInfo)) {  
  11.                     Bitmap tmpBitmap = null
  12.                     BitmapData bmpData = null
  13.                     BitmapData targetData = null
  14.                     IntSecurity.ObjectFromWin32Handle.Assert();  
  15.                     try { 
  16.                         tmpBitmap = Bitmap.FromHbitmap(imageInfo.hbmImage);  
  17.                         //  
  18.  
  19.   
  20.  
  21.  
  22.                         bmpData = tmpBitmap.LockBits(new Rectangle(imageInfo.rcImage_left,imageInfo.rcImage_top, imageInfo.rcImage_right-imageInfo.rcImage_left, imageInfo.rcImage_bottom-imageInfo.rcImage_top), ImageLockMode.ReadOnly, tmpBitmap.PixelFormat); 
  23.   
  24.                         int offset =  bmpData.Stride * imageSize.Height   * index; 
  25.                         // we need do the following if the image has alpha because otherwise the image is fully transparent even though it has data  
  26.                         if(BitmapHasAlpha(bmpData)) {  
  27.                             result = new Bitmap(imageSize.Width, imageSize.Height, PixelFormat.Format32bppArgb);  //注意这里是新创建的Bitmap实例 
  28.                             targetData = result.LockBits(new Rectangle(0, 0, imageSize.Width, imageSize.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);  
  29.                             CopyBitmapData(bmpData, targetData);//仅仅拷贝图像数据 
  30.                         } 
  31.                     } finally { 
  32.                         CodeAccessPermission.RevertAssert();  
  33.                         if(tmpBitmap != null && bmpData != null) { 
  34.                             tmpBitmap.UnlockBits(bmpData);  
  35.                         }  
  36.                         if(result != null && targetData != null) { 
  37.                             result.UnlockBits(targetData);  
  38.                         } 
  39.                     } 
  40.                 } 
  41.             }  
  42.  
  43.             if(result == null) { // paint with the mask but no alpha...  
  44.                 result = new Bitmap(imageSize.Width, imageSize.Height); //新创建Bitmap实例 
  45.  
  46.                 Graphics graphics = Graphics.FromImage(result);  
  47.                 try { 
  48.                     IntPtr dc = graphics.GetHdc(); 
  49.                     try { 
  50.                         SafeNativeMethods.ImageList_DrawEx(new HandleRef(this, Handle), index, new HandleRef(graphics, dc), 0, 0,  
  51.                                                 imageSize.Width, imageSize.Height, NativeMethods.CLR_NONE, NativeMethods.CLR_NONE, NativeMethods.ILD_TRANSPARENT); 
  52.   
  53.                     }  
  54.                     finally { 
  55.                         graphics.ReleaseHdcInternal(dc);  
  56.                     } 
  57.                 } 
  58.                 finally { 
  59.                     graphics.Dispose();  
  60.                 } 
  61.             }  
  62.   
  63.             // gpr: See Icon for description of fakeTransparencyColor 
  64.             result.MakeTransparent(fakeTransparencyColor);  
  65.             return result; 
  66.         }  

代码比较长,关键的部分我使用注释标记出来了,大家看我标记的注释就可以了,大家可以发现,无论BitmapHasAlpha是否为真,都是新创建Bitmap对象然后返回的,所以在mage和 bigHeadPicList.Images["1"]并不是同一对象,所以Tag是null的!

本站热点业务

更多模板/案例展示

关于我们 | 联系我们 | 团队日志 | 网站地图 | 网站合作