如何 "Cancel" 从对话框加载事件
How To "Cancel" Load Event From a Dialog
我正在尝试创建一个 from 来可视化和编辑图像,简单的东西如:
- 绘制矩形
- 写东西
- 裁剪矩形
但我遇到了很多困难,例如:如果我尝试加载一个不存在或无法打开的文件(它不是图像),我想展示一个 MessageBox,然后关闭窗体。 但是表单不会立即关闭(这可能会导致错误,因为我可能会尝试访问未打开的文件的属性)。你能告诉我为什么吗? (查看Abort()方法)源代码在post.
的末尾
我使用以下事件在内部创建表单:
private void button2_Click(object sender, EventArgs e)
{
Forms.AreaSelector areaSelector = new Forms.AreaSelector(LabelInput);
areaSelector.ShowDialog();
}
我想将我的表单显示为一个对话框,这样用户就无法在不获取对图像的修改的情况下返回到 'main window',这就是我使用的原因.ShowDialog(),而不是 Show()
我尝试在我的 "Abort" 方法中调用 Close() 甚至 Dispose() ,但是表单继续加载(通过继续加载我的意思是 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
}
}
编辑:我收到了很多变通方法的建议。但是汉斯的回答不仅纠正了我正确的设计缺陷(也解决了这个问题)而且还解释了为什么会发生这种问题(检查他的 link)。所以我选择他的答案。
随意关闭这个问题,mods。感谢大家的帮助!
您可以使 TryToLoadImage 布尔值(用 return false 代替 Adort)和 运行 像这样:
if(TryToLoadImage())
{
UpdateWindowSize();
UpdatePictureBox();
}
else Close();
最好的选择是避免加载事件中的"doubtful part"。
但是,如果你想在加载事件本身中执行操作,我建议使用简单的程序。
使用名为 access 的整型变量并将其默认设置为 1
如您所述,您想要显示一个消息框然后将其关闭。在消息框行之前,将访问变量的值设置为 0。
将 post-messagebox 代码包含在 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 事件在 Winforms 中被严重过度使用。它从其前身 VB6 继承的挂起,它非常重要,因为这是您放置任何初始化代码的地方。这使它成为默认事件,太容易使用了。
但不是在 .NET 中,初始化是在 class 的构造函数中完成的。 Load 事件来不及了,火车离开了车站并且已经达到了相当大的速度。试图阻止它很困难,例如抛出异常没有任何效果。而事实上是very dangerous。只有当您需要知道 window 的大小和位置时才应使用 Load 事件。这是非常罕见的,虽然看起来你有用。
您需要在火车开始前停止它,您的 TryToLoadImage() 调用属于构造函数。现在它非常简单,当正常工作的东西不能工作时,你做你在 C# 中做的正常事情,你抛出一个异常。并在 ShowDialog() 调用站点捕获它。简单易行。
我正在尝试创建一个 from 来可视化和编辑图像,简单的东西如:
- 绘制矩形
- 写东西
- 裁剪矩形
但我遇到了很多困难,例如:如果我尝试加载一个不存在或无法打开的文件(它不是图像),我想展示一个 MessageBox,然后关闭窗体。 但是表单不会立即关闭(这可能会导致错误,因为我可能会尝试访问未打开的文件的属性)。你能告诉我为什么吗? (查看Abort()方法)源代码在post.
的末尾我使用以下事件在内部创建表单:
private void button2_Click(object sender, EventArgs e)
{
Forms.AreaSelector areaSelector = new Forms.AreaSelector(LabelInput);
areaSelector.ShowDialog();
}
我想将我的表单显示为一个对话框,这样用户就无法在不获取对图像的修改的情况下返回到 'main window',这就是我使用的原因.ShowDialog(),而不是 Show() 我尝试在我的 "Abort" 方法中调用 Close() 甚至 Dispose() ,但是表单继续加载(通过继续加载我的意思是 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
}
}
编辑:我收到了很多变通方法的建议。但是汉斯的回答不仅纠正了我正确的设计缺陷(也解决了这个问题)而且还解释了为什么会发生这种问题(检查他的 link)。所以我选择他的答案。 随意关闭这个问题,mods。感谢大家的帮助!
您可以使 TryToLoadImage 布尔值(用 return false 代替 Adort)和 运行 像这样:
if(TryToLoadImage())
{
UpdateWindowSize();
UpdatePictureBox();
}
else Close();
最好的选择是避免加载事件中的"doubtful part"。
但是,如果你想在加载事件本身中执行操作,我建议使用简单的程序。
使用名为 access 的整型变量并将其默认设置为 1
如您所述,您想要显示一个消息框然后将其关闭。在消息框行之前,将访问变量的值设置为 0。
将 post-messagebox 代码包含在 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 事件在 Winforms 中被严重过度使用。它从其前身 VB6 继承的挂起,它非常重要,因为这是您放置任何初始化代码的地方。这使它成为默认事件,太容易使用了。
但不是在 .NET 中,初始化是在 class 的构造函数中完成的。 Load 事件来不及了,火车离开了车站并且已经达到了相当大的速度。试图阻止它很困难,例如抛出异常没有任何效果。而事实上是very dangerous。只有当您需要知道 window 的大小和位置时才应使用 Load 事件。这是非常罕见的,虽然看起来你有用。
您需要在火车开始前停止它,您的 TryToLoadImage() 调用属于构造函数。现在它非常简单,当正常工作的东西不能工作时,你做你在 C# 中做的正常事情,你抛出一个异常。并在 ShowDialog() 调用站点捕获它。简单易行。