用C#写的WinForm程序,因为很多处要用到图像放大的功能,就写了一个由TrackBar和PictureBox构成的UserControl。PictureBox的SizeMode属性设为StretchImage,然后在TrackBar的事件里:
private void trackBar_Zoom_ValueChanged(object sender, EventArgs e)
{
try
{
float _coefficient = (100 + trackBar_Zoom.Value) / 100F; picBox_Scale.Size = new Size(Convert.ToInt32(picBox_Source.Width * _coefficient), Convert.ToInt32(picBox_Source.Height * _coefficient)); //改变PictureBox的大小
label_Scale.Text = (100 + trackBar_Zoom.Value).ToString()+ "%"; //显示放大倍数
}
catch (Exception E)
{
if (E is System.ComponentModel.Win32Exception)
{
System.ComponentModel.Win32Exception exception = E as System.ComponentModel.Win32Exception;
if (exception.ErrorCode == -2147467259)
{
trackBar_Zoom.Enabled = false;
picBox_Scale.Image.Dispose();
picBox_Scale.Dispose();
GC.Collect();
...... //重新new 一个picBox_Scale以及初始化设置,程序较长,省略
MessageBox.Show(E.Message, "出错", MessageBoxButtons.OK, MessageBoxIcon.Warning);
trackBar_Zoom.Enabled = true;
}
}
else
{
MessageBox.Show(E.Message, "出错", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}当放大倍数到了接近20倍时(测试图片是1440×900,电脑2G内存,客户要求最大放大倍数是32倍)就发生异常了,而且发现上面这个try catch根本不能捕获异常,异常是在ValueChanged事件执行完后才抛出的。在 Application的ThreadException事件里能捕获这个异常,但是程序里用了很多个这种UserControl,因而无法在ThreadException确定是哪个出错了并进行恢复。请问有没有什么办法能在UserControl里就捕获这个异常?附出错信息:
未处理 System.ComponentModel.Win32Exception
Message="存储空间不足,无法处理此命令。"
Source="System.Drawing"
ErrorCode=-2147467259
NativeErrorCode=8
StackTrace:
在 System.Drawing.BufferedGraphicsContext.CreateCompatibleDIB(IntPtr hdc, IntPtr hpal, Int32 ulWidth, Int32 ulHeight, IntPtr& ppvBits)
在 System.Drawing.BufferedGraphicsContext.CreateBuffer(IntPtr src, Int32 offsetX, Int32 offsetY, Int32 width, Int32 height)
在 System.Drawing.BufferedGraphicsContext.AllocBuffer(Graphics targetGraphics, IntPtr targetDC, Rectangle targetRectangle)
在 System.Drawing.BufferedGraphicsContext.AllocBufferInTempManager(Graphics targetGraphics, IntPtr targetDC, Rectangle targetRectangle)
在 System.Drawing.BufferedGraphicsContext.Allocate(IntPtr targetDC, Rectangle targetRectangle)
在 System.Windows.Forms.Control.WmPaint(Message& m)
在 System.Windows.Forms.Control.WndProc(Message& m)
在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
在 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
在 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
在 System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
在 System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
在 System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
在 System.Windows.Forms.Application.Run(Form mainForm)
在 Microsoft.VisualStudio.Tools.UserControlTestContainer.Main(String[] args)
private void trackBar_Zoom_ValueChanged(object sender, EventArgs e)
{
try
{
float _coefficient = (100 + trackBar_Zoom.Value) / 100F; picBox_Scale.Size = new Size(Convert.ToInt32(picBox_Source.Width * _coefficient), Convert.ToInt32(picBox_Source.Height * _coefficient)); //改变PictureBox的大小
label_Scale.Text = (100 + trackBar_Zoom.Value).ToString()+ "%"; //显示放大倍数
}
catch (Exception E)
{
if (E is System.ComponentModel.Win32Exception)
{
System.ComponentModel.Win32Exception exception = E as System.ComponentModel.Win32Exception;
if (exception.ErrorCode == -2147467259)
{
trackBar_Zoom.Enabled = false;
picBox_Scale.Image.Dispose();
picBox_Scale.Dispose();
GC.Collect();
...... //重新new 一个picBox_Scale以及初始化设置,程序较长,省略
MessageBox.Show(E.Message, "出错", MessageBoxButtons.OK, MessageBoxIcon.Warning);
trackBar_Zoom.Enabled = true;
}
}
else
{
MessageBox.Show(E.Message, "出错", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}当放大倍数到了接近20倍时(测试图片是1440×900,电脑2G内存,客户要求最大放大倍数是32倍)就发生异常了,而且发现上面这个try catch根本不能捕获异常,异常是在ValueChanged事件执行完后才抛出的。在 Application的ThreadException事件里能捕获这个异常,但是程序里用了很多个这种UserControl,因而无法在ThreadException确定是哪个出错了并进行恢复。请问有没有什么办法能在UserControl里就捕获这个异常?附出错信息:
未处理 System.ComponentModel.Win32Exception
Message="存储空间不足,无法处理此命令。"
Source="System.Drawing"
ErrorCode=-2147467259
NativeErrorCode=8
StackTrace:
在 System.Drawing.BufferedGraphicsContext.CreateCompatibleDIB(IntPtr hdc, IntPtr hpal, Int32 ulWidth, Int32 ulHeight, IntPtr& ppvBits)
在 System.Drawing.BufferedGraphicsContext.CreateBuffer(IntPtr src, Int32 offsetX, Int32 offsetY, Int32 width, Int32 height)
在 System.Drawing.BufferedGraphicsContext.AllocBuffer(Graphics targetGraphics, IntPtr targetDC, Rectangle targetRectangle)
在 System.Drawing.BufferedGraphicsContext.AllocBufferInTempManager(Graphics targetGraphics, IntPtr targetDC, Rectangle targetRectangle)
在 System.Drawing.BufferedGraphicsContext.Allocate(IntPtr targetDC, Rectangle targetRectangle)
在 System.Windows.Forms.Control.WmPaint(Message& m)
在 System.Windows.Forms.Control.WndProc(Message& m)
在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
在 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
在 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
在 System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
在 System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
在 System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
在 System.Windows.Forms.Application.Run(Form mainForm)
在 Microsoft.VisualStudio.Tools.UserControlTestContainer.Main(String[] args)
{
try
{}
catch()
{}
}在这里可能能捕获可能不是你想要的。你最好能计算出多少就会出错。自己来throw错误,自己捕获。
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
if (e.ExceptionObject is OutOfMemoryException)
{
}
} void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
if (e.Exception is OutOfMemoryException)
{
}
}
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledExceptions);
private void UnhandledExceptions(object sender, UnhandledExceptionEventArgs args)
{ }
public class Singleton
{
static Singleton pub = new Singleton();
public Singleton()
{ }
private UserControl control; public UserControl Control
{
get { return control; }
set { control = value; }
}
public static Singleton Instance
{
get { return pub; }
}
}出异常后Singleton.Instance.Control.Dispose();
一个1K*1K的图像放大32倍,内存量是1K*1K*1024*3=3GB!(RGB图像像素是3字节)
要能支持放大32倍,只能对图像作局部截取,再放大.
用你的方法,发现一个很奇怪的问题:
1、在VS2008的用户控件测试容器里调试,UnhandledException事件会触发。好象UnhandledException事件不会阻止异常抛出吧?运行结果是,UnhandledException事件执行完后,异常还是抛出,程序中止。2、直接用主程序调试(就是用户控件调试时选“启动外部程序”),发现在用户控件里加的UnhandledException事件完全没有执行,只执行了Application.ThreadException。我把Application.ThreadException注释掉,结果是出来了系统的那个异常窗口,用户控件里加的UnhandledException事件还是没有执行。是不是要用什么方法去设置?
这个算法比较复杂,和客户沟通后,客户同意在OutOfMemoery时做个警告提示即可,程序不能退出或崩溃。现在就是截获不到这个异常。