C# 如何从对话框“取消”加载事件
我正在尝试创建一个从来可视化和编辑图像,简单的东西如下: 绘制矩形 写作材料 裁剪矩形 但我遇到了很多困难,例如:如果我试图加载一个不存在或无法打开的文件,它不是图像,我希望显示一个MessageBox,然后关闭表单。但是表单没有立即关闭,这可能会导致错误,因为我可能会尝试访问未打开的文件的属性。你能告诉我为什么吗?检查Abort方法,源代码在文章的末尾 我使用以下事件在内部创建表单:C# 如何从对话框“取消”加载事件,c#,image,winforms,modal-dialog,C#,Image,Winforms,Modal Dialog,我正在尝试创建一个从来可视化和编辑图像,简单的东西如下: 绘制矩形 写作材料 裁剪矩形 但我遇到了很多困难,例如:如果我试图加载一个不存在或无法打开的文件,它不是图像,我希望显示一个MessageBox,然后关闭表单。但是表单没有立即关闭,这可能会导致错误,因为我可能会尝试访问未打开的文件的属性。你能告诉我为什么吗?检查Abort方法,源代码在文章的末尾 我使用以下事件在内部创建表单: private void button2_Click(object sender, EventArgs e)
private void button2_Click(object sender, EventArgs e)
{
Forms.AreaSelector areaSelector = new Forms.AreaSelector(LabelInput);
areaSelector.ShowDialog();
}
我想以对话框的形式显示表单,这样用户就不能返回“主窗口”,而不查看对图像的修改,这就是我使用.ShowDialog而不是show的原因
我尝试在Abort方法中调用Close甚至Dispose,但是表单继续通过continues to load加载。我的意思是,UpdateWindowSize和UpdatePictureBox被称为与我在Abort中的操作无关
这是实际的表单代码
资料来源:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace PeeAlyser.Forms
{
public partial class AreaSelector : Form
{
#region Variables
Bitmap originalImage, modifiedImage;
string fileName;
#endregion
#region Constructors
public AreaSelector(string fileName)
{
InitializeComponent();
this.fileName = fileName;
}
#endregion
private void AreaSelector_Load(object sender, EventArgs e)
{
TryToLoadImage();
UpdateWindowSize();
UpdatePictureBox();
}
#region Private Methods
private void Abort()
{
this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.BeginInvoke(new MethodInvoker(this.Close));
//this.Close();
//this.Dispose();
// GODAMNIT!
}
private void TryToLoadImage()
{
if (!System.IO.File.Exists(fileName))
{
MessageBox.Show("File not found.");
Abort();
}
try { originalImage = (Bitmap)Bitmap.FromFile(fileName); }
catch (Exception error)
{
MessageBox.Show("Error: " + Environment.NewLine +
error.ToString());
Abort();
}
this.modifiedImage = new Bitmap(originalImage);
}
private void UpdateWindowSize()
{
int widthDifference = this.Width - pictureBox1.Width;
int heightDifference = this.Height - pictureBox1.Height;
Size windowSize = originalImage.Size;
windowSize.Width += widthDifference;
windowSize.Height += heightDifference;
this.Size = this.MinimumSize = this.MaximumSize = windowSize;
this.pictureBox1.Size = originalImage.Size;
this.AdjustFormScrollbars(true);
}
private void UpdatePictureBox()
{
this.pictureBox1.Image = modifiedImage;
this.Refresh();
}
#endregion
}
}
编辑:我收到了很多关于解决这个问题的建议。但是汉斯的回答不仅纠正了我的更正中的一个设计缺陷,也解决了这个问题,而且还解释了为什么在检查他的链接时会出现这种问题。所以我选择了他的答案。
请随意关闭此问题,mods。谢谢你们的帮助 您可以通过返回false使TryToLoadImage布尔替换Adort,并按如下方式运行它:
if(TryToLoadImage())
{
UpdateWindowSize();
UpdatePictureBox();
}
else Close();
您可以通过返回false使TryToLoadImage布尔替换Adort,并按如下方式运行它:
if(TryToLoadImage())
{
UpdateWindowSize();
UpdatePictureBox();
}
else Close();
最好的选择是避免负载事件中的可疑部分 但是,如果您想在Load事件本身中执行操作,我建议使用一个简单的过程 使用名为access的整数变量,并在默认情况下将其设置为1 正如您所提到的,您希望显示一个messagebox,然后关闭它。在messagebox行之前,将access变量的值设置为0 将PostMessageBox代码包含在If-Else块中 您需要的代码是:-
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace PeeAlyser.Forms
{
public partial class AreaSelector : Form
{
#region Variables
Bitmap originalImage, modifiedImage;
string fileName;
#endregion
#region Constructors
public AreaSelector(string fileName)
{
InitializeComponent();
this.fileName = fileName;
}
#endregion
public int access=1;
private void AreaSelector_Load(object sender, EventArgs e)
{
TryToLoadImage();
if(access==1)
{
UpdateWindowSize();
UpdatePictureBox();
}
}
#region Private Methods
private void Abort()
{
this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.BeginInvoke(new MethodInvoker(this.Close));
//this.Close();
//this.Dispose();
// GODAMNIT!
}
private void TryToLoadImage()
{
if (!System.IO.File.Exists(fileName))
{
access=0;
MessageBox.Show("File not found.");
Abort();
}
try { originalImage = (Bitmap)Bitmap.FromFile(fileName); }
catch (Exception error)
{
MessageBox.Show("Error: " + Environment.NewLine +
error.ToString());
Abort();
}
this.modifiedImage = new Bitmap(originalImage);
}
private void UpdateWindowSize()
{
int widthDifference = this.Width - pictureBox1.Width;
int heightDifference = this.Height - pictureBox1.Height;
Size windowSize = originalImage.Size;
windowSize.Width += widthDifference;
windowSize.Height += heightDifference;
this.Size = this.MinimumSize = this.MaximumSize = windowSize;
this.pictureBox1.Size = originalImage.Size;
this.AdjustFormScrollbars(true);
}
private void UpdatePictureBox()
{
this.pictureBox1.Image = modifiedImage;
this.Refresh();
}
#endregion
}
}
最好的选择是避免负载事件中的可疑部分 但是,如果您想在Load事件本身中执行操作,我建议使用一个简单的过程 使用名为access的整数变量,并在默认情况下将其设置为1 正如您所提到的,您希望显示一个messagebox,然后关闭它。在messagebox行之前,将access变量的值设置为0 将PostMessageBox代码包含在If-Else块中 您需要的代码是:-
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace PeeAlyser.Forms
{
public partial class AreaSelector : Form
{
#region Variables
Bitmap originalImage, modifiedImage;
string fileName;
#endregion
#region Constructors
public AreaSelector(string fileName)
{
InitializeComponent();
this.fileName = fileName;
}
#endregion
public int access=1;
private void AreaSelector_Load(object sender, EventArgs e)
{
TryToLoadImage();
if(access==1)
{
UpdateWindowSize();
UpdatePictureBox();
}
}
#region Private Methods
private void Abort()
{
this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.BeginInvoke(new MethodInvoker(this.Close));
//this.Close();
//this.Dispose();
// GODAMNIT!
}
private void TryToLoadImage()
{
if (!System.IO.File.Exists(fileName))
{
access=0;
MessageBox.Show("File not found.");
Abort();
}
try { originalImage = (Bitmap)Bitmap.FromFile(fileName); }
catch (Exception error)
{
MessageBox.Show("Error: " + Environment.NewLine +
error.ToString());
Abort();
}
this.modifiedImage = new Bitmap(originalImage);
}
private void UpdateWindowSize()
{
int widthDifference = this.Width - pictureBox1.Width;
int heightDifference = this.Height - pictureBox1.Height;
Size windowSize = originalImage.Size;
windowSize.Width += widthDifference;
windowSize.Height += heightDifference;
this.Size = this.MinimumSize = this.MaximumSize = windowSize;
this.pictureBox1.Size = originalImage.Size;
this.AdjustFormScrollbars(true);
}
private void UpdatePictureBox()
{
this.pictureBox1.Image = modifiedImage;
this.Refresh();
}
#endregion
}
}
加载事件在Winforms中被过度使用。它继承了它的前身VB6的一个挂起,在那里它是非常重要的,因为这是放置任何初始化代码的地方。这使得它成为默认事件,太容易使用了
但不是在.NET中,初始化是在类的构造函数中完成的。负载事件太晚了,列车离开车站,已经获得了相当大的速度。试图阻止它是困难的,例如,抛出异常没有效果。事实上是这样。只有在需要知道窗口的大小和位置时,才应使用Load事件。这是非常罕见的,尽管看起来你有用处
你需要在火车开动之前停下来,你的TryToLoadImage调用属于构造函数。现在它非常简单,当正常工作的东西不能工作时,你在C中做正常的事情,你抛出一个异常。并在ShowDialog呼叫站点捕获它。轻松搞定。加载事件在Winforms中被过度使用。它继承了它的前身VB6的一个挂起,在那里它是非常重要的,因为这是放置任何初始化代码的地方。这使得它成为默认事件,太容易使用了
但不是在.NET中,初始化是在类的构造函数中完成的。负载事件太晚了,列车离开车站,已经获得了相当大的速度。试图阻止它是困难的,例如,抛出异常没有效果。事实上是这样。只有在需要知道窗口的大小和位置时,才应使用Load事件。这是非常罕见的,尽管看起来你有用处
你需要在火车开动之前停下来,你的TryToLoadImage调用属于构造函数。现在它非常简单,当正常工作的东西不能工作时,你在C中做正常的事情,你抛出一个异常。并在ShowDialog呼叫站点捕获它。轻松轻松。在加载事件中不应该这样做。将错误检测逻辑从加载事件中释放。如何。。。我可以这样做吗?我是说。我是否应该将图像的数据源设置在加载事件之外?那么,在哪种情况下?继续加载是指它进入UpdateWindowSize还是什么?是的,这就是我所说的继续加载。在加载事件中尝试e.取消?你不应该这样做
在加载事件中。将错误检测逻辑从加载事件中释放。如何。。。我可以这样做吗?我是说。我是否应该将图像的数据源设置在加载事件之外?在哪种情况下,那么?继续加载你的意思是它进入UpdateWindowSize还是什么?是的,我的意思是继续加载。在加载事件中尝试e.取消?谢谢你的比喻和建议。我将把我的TryToLoadImage移到构造函数中,并很快回复结果。但是,为什么火车不能停下来呢?顺便说一句这样做是有道理的。在构造函数中分配内容。。。糟糕的是,火车是操作系统创建的本地窗口。它已经创建并初始化,只是还不可见。加载事件是我将要收到的可见通知。您可以调用Close或设置DialogResult属性,但这不会阻止窗口在屏幕上短暂闪烁。并引发一些其他事件,这些事件可能会因为位图未加载而爆炸。Windows没有取消通知的选项,最明显的是加载事件没有CancelEventArgs参数。感谢您的隐喻和建议。我将把我的TryToLoadImage移到构造函数中,并很快回复结果。但是,为什么火车不能停下来呢?顺便说一句这样做是有道理的。在构造函数中分配内容。。。糟糕的是,火车是操作系统创建的本地窗口。它已经创建并初始化,只是还不可见。加载事件是我将要收到的可见通知。您可以调用Close或设置DialogResult属性,但这不会阻止窗口在屏幕上短暂闪烁。并引发一些其他事件,这些事件可能会因为位图未加载而爆炸。Windows没有取消通知的选项,最明显的是加载事件没有CancelEventArgs参数。