Windows Mobile - 吸引人的 UI 第二部分






2.43/5 (8投票s)
Windows Mobile - 吸引人的 UI 第二部分
- 下载源代码 - 47.3 KB (包含更新后的
AlphaMobileControls
以及一些附加功能和一组新的控件)
引言
在我的 第一篇博客 中,我承诺会推出第二部分。这里就是第二部分。我们将深入研究 AlphaImage 控件。
第一个问题是:.NET CF 不支持图像透明度。因此,无论何时我们请求透明颜色,它都会被转换为白色。更糟糕的是,带有透明背景的 GIF 图像在这里也无法工作。
AlphaMobileControls 包含一个名为“AlphaPictureBox”的控件,它继承自 AlphaControl。如果使用该控件,就可以解决透明度问题。
如何使用
只需将一个 AlphaPictureBox 控件放置到您的窗体上。在窗体构造函数中设置要在PictureBox中显示的图像。
alphaPictureBox1.Image = AlphaImage.CreateFromResource("mConcierge.Resources.backgroundNormal.jpg");
完成了。如果您需要背景透明度,则图像应该是一个具有正常透明背景的 GIF 图像。
内部原理
AlphaPictureBox 控件暴露的图像属性是一个 AlphaImage。
这个 AlphaImage 是从普通图像创建的。
///
/// Creates a new AlphaImage from the given memory stream.
///
public static AlphaImage CreateFromStream(MemoryStream stream)
{
PlatformAPI.IImaging.IImagingFactory factory = CreateFactory();
AlphaImage alphaImage = new AlphaImage();
byte[] pbBuf = stream.GetBuffer();
uint cbBuf = (uint)stream.Length;
factory.CreateImageFromBuffer(pbBuf, cbBuf, PlatformAPI.IImaging.BufferDisposalFlag.BufferDisposalFlagNone, out alphaImage._image);
}
IImagingFactory 接口定义了本机 (COM) 操作系统操作,如下所示
[ComImport, Guid("327ABDA7-072B-11D3-9D7B-0000F81EF32E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComVisible(true)]
public interface IImagingFactory
{
uint CreateImageFromStream(IStream stream, out IImage image);
uint CreateImageFromFile(string filename, out IImage image);
uint CreateImageFromBuffer([MarshalAs(UnmanagedType.LPArray)] byte[] buffer, uint size, BufferDisposalFlag disposalFlag, out IImage image);
uint CreateNewBitmap(uint width, uint height, PixelFormatID pixelFormat, out IBitmapImage bitmap); uint CreateBitmapFromImage(IImage image, uint width, uint height, PixelFormatID pixelFormat, InterpolationHint hints, out IBitmapImage bitmap); uint CreateBitmapFromBuffer(BitmapData bitmapData, out IBitmapImage bitmap); uint CreateImageDecoder(); uint CreateImageEncoderToStream(); uint CreateImageEncoderToFile(); uint GetInstalledDecoders(); uint GetInstalledEncoders(); uint InstallImageCodec(); uint UninstallImageCodec(); }
剩下的事情都比较简单。由于 AlphaPictureBox 控件继承自 AlphaControl 基类,它重写了 AlphaControl 的绘制方法。这反过来又调用 AlphaImage 的绘制方法。AlphaImage 内部的绘制方法通过调用此处定义的 COM 函数在窗体上绘制图像。
[ComImport, Guid("327ABDA9-072B-11D3-9D7B-0000F81EF32E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [ComVisible(true)] public interface IImage {
uint GetPhysicalDimension(out Size size); uint GetImageInfo(out ImageInfo info); uint SetImageFlags(uint flags); uint Draw(IntPtr hdc, ref Rectangle dstRect, IntPtr srcRect);
uint PushIntoSink(); // pominięte uint GetThumbnail(uint thumbWidth, uint thumbHeight, out IImage thumbImage); }
难以入眠的夜晚
当我计划聚会时,我遇到了问题。当我导航窗体时,我的应用程序开始出现异常。我到处寻找解决方案,但花了很长时间才从 codeplex 上找到一个。
问题在于一个托管数组被传递给 COM 对象。一旦垃圾回收器决定释放/移动这个数组,就会出现问题。
解决方法
在 IImagingFactory.cs 中,替换为
// We need the MarshalAs attribute here to keep COM interop from sending the buffer down as a Safe Array. uint CreateImageFromBuffer([MarshalAs(UnmanagedType.LPArray)] byte[] buffer, uint size, BufferDisposalFlag disposalFlag, out IImage image);
有了
uint CreateImageFromBuffer(IntPtr buffer, uint size, BufferDisposalFlag disposalFlag, out IImage image);
在 AlphaImage.cs 中,在文件顶部添加
using System.Runtime.InteropServices;
并替换为
factory.CreateImageFromBuffer(pbBuf, cbBuf,BufferDisposalFlag.BufferDisposalFlagNone, out alphaImage._image);
有了
// Copy stream data into an unmanaged global buffer that will be freed by the factory once image is decoded
// note that we cannot pass pbBuf directly since it might be moved around or freed by the gc. IntPtr p = Marshal.AllocHGlobal((int)cbBuf); Marshal.Copy(pbBuf, 0, p, (int)cbBuf); factory.CreateImageFromBuffer(p, cbBuf, BufferDisposalFlag.BufferDisposalFlagGlobalFree, out alphaImage._image);
代码和控件可以在 这里 下载。