如何 "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() 调用站点捕获它。简单易行。