无法访问已处置的对象C#(showdialog dispose)

时间:2014-10-06 15:43:17

标签: c# .net winforms

我是c#的新手并且有点畏缩。使用Microsoft Visual C#2010

我检查过很多类似的帖子,似乎没有任何建议可以提供帮助

我收到以下错误:“无法访问已处置的对象” 这里引用了主要表格

private void btn_RunPkgs_Click(object sender, EventArgs e)
        {
            RunPackages rp = new RunPackages();    
            this.Hide();
            rp.ShowDialog();//The error points to this line
            this.Show();
        }

这是安全检查失败时爆炸的代码。

private void securityCheck()
        {
            if (MyGlobals.FormCheck("RUN_JOBS") == 1)
            {
                InitializeComponent();
            }
            else
            {
                //this.BeginInvoke(new MethodInvoker(this.Close));
                //this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
                MessageBox.Show("You do not have permission to access this form!");
                //this.Close();
                this.Dispose();
            }            
        }

修改 看起来我会选择Adriano Repetti将安全性放在我称之为页面的位置,但我现在有点紧张,因为页面上有任何安全性。

   private void btn_RunPkgs_Click(object sender, EventArgs e)
        {
            if (MyGlobals.FormCheck("RUN_JOBS") == 1)
            {
                RunPackages rp = new RunPackages();
                this.Hide();
                rp.ShowDialog();
                this.Show();                
            }
            else
            {
                MessageBox.Show("Not for You!");             
            }
        }

        private void btn_ListUpdater_Click(object sender, EventArgs e)
        {
            if (MyGlobals.FormCheck("MDM") == 1)
            {
                ListUpdater lu = new ListUpdater();

                this.Hide();
                lu.ShowDialog();
                this.Show();
            }
            else
            {
                MessageBox.Show("Private!");
            }            
        }

EDIT2 想出了以下可能的解决方案,但我很担心使用它,因为我是新手,并且不知道可能存在哪些问题。仅为表单加载创建事件处理程序有什么问题吗?

namespace RunPackages
{
    public partial class ListUpdater : Form
    {
        public ListUpdater()
        {            
            InitializeComponent();
            this.Load += new EventHandler(securityCheck);
        }    

        private void securityCheck(object sender, EventArgs e)
        {
            if (MyGlobals.FormCheck("MDM1") == 0)
            {
                MessageBox.Show("Not Allowed!");
                this.Close();
            }    
        }

5 个答案:

答案 0 :(得分:3)

您无法在表单中处理表单。 ShowDialog()方法尝试在退出时访问表单,例如DialogResult

答案 1 :(得分:2)

在处理完表单之后,几乎无法访问其所有方法(并且其大部分属性都无效)。

btn_RunPkgs_Click()的第一行中,您创建了一个对象,并将其置于其构造函数中。 本身,即使你可能甚至从构造函数中调用Dispose()这个非常糟糕的习惯,它甚至可以工作但是你尝试使用这样的对象{{1将生成ShowDialog()。请注意,此代码也会导致相同的结果(例外):

ObjectDisposedException

是的,你可以检查RunPackages rp = new RunPackages(); rp.Dispose(); ,但这不会使代码可读,问题(IMO)是你在混合的东西。构造函数不应该包含这样的逻辑。

关键不仅仅是 你处理你的表单。更好的是甚至不创建这样的表单(让我假设,因为你调用IsDisposed,在表单构造函数中调用InitializeComponent()),为此你可以使用工厂静态方法:

securityCheck()

您的通话功能将缩减为:

public static bool TryShowDialog(Form currentForm)
{
    if (MyGlobals.FormCheck("RUN_JOBS") != 1)
        return false;

    if (currentForm != null)
        currentForm.Hide();

    RunPackages dlg = new RunPackages();
    dlg.ShowDialog();   

    if (currentForm != null)
        currentForm.Show();

    return true;
}

请注意,此类函数非常适合进行某些重构(例如,提取代码以隐藏/显示现有表单)。像这样:

private void btn_RunPkgs_Click(object sender, EventArgs e)
{
    RunPackages.TryShowDialog(this);
}

像这样使用(现在代码在任何地方重复使用):

public static bool ShowDialog<T>(Form currentForm, string authorizationId)
    where T : Form, new()
{
    if (MyGlobals.FormCheck(authorizationId) != 1)
        return false;

    if (currentForm != null)
        currentForm.Hide();

    T dlg = new T();
    T.ShowDialog();   

    if (currentForm != null)
        currentForm.Show();

    return true;
}

请注意,调用代码可能会简化( SecurityHelpers.ShowDialog<RunPackages>(this, "RUN_JOBS"); 可能是authorizationId上的属性,例如,RunPackages也可以从当前活动表单中推断出来。)

编辑调用currentForm并不是更好,如果尚未创建窗口句柄(让我们简化一点:它是在显示窗口时创建的),它会在内部调用{{1 (然后上面适用)。

答案 2 :(得分:1)

我不会试图破坏导致表单创建的事件的链接 副作用很难预测,今天有效的方法在将来的版本中无效。

相反,我会尝试不同的方法

    private void securityCheck()
    {
        if (MyGlobals.FormCheck("RUN_JOBS") == 1)
        {
            InitializeComponent();
        }
        else
        {
            Label message = new Label();
            message.Dock = DockStile.Fill;
            message.Text("You do not have permission to access this form!.");
            message.TextAlign = ContentAlignment.MiddleCenter;
            this.Controls.Add(message);
        }      
    }

通过这种方式,我让表单只显示一个标签,用您的信息覆盖整个表单表面。用户只能关闭表单(假设您没有删除控制框)

顺便说一下,这有利于避免危险的疏忽,因为它不需要对调用代码进行任何更改,最终的效果是有效地阻止使用表单。

如果您坚持在构建阶段关闭表单,那么您可以从this question获得一些建议

答案 3 :(得分:0)

我想出了以下内容,有人可以告诉我这是否有任何问题?

namespace RunPackages
{
    public partial class ListUpdater : Form
    {

        public ListUpdater()
        {            
            InitializeComponent();
            this.Load += new EventHandler(securityCheck);
        }    

        private void securityCheck(object sender, EventArgs e)
        {
            if (MyGlobals.FormCheck("MDM1") == 0)
            {
                MessageBox.Show("Not allowed!");
                this.Close();
            }    
        }

等...

答案 4 :(得分:-1)

使用旗帜。例如,更改代码,如下所示:

    public bool IsDisposed;
    private void securityCheck()
            {
                if (MyGlobals.FormCheck("RUN_JOBS") == 1)
                {
                    InitializeComponent();
                }
                else
                {
                    //this.BeginInvoke(new MethodInvoker(this.Close));
                    //this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
                    MessageBox.Show("You do not have permission to access this form!");
                    //this.Close();
                    this.Dispose();
                    this.IsDisposed = true;
                }      


        }

然后:

private void btn_RunPkgs_Click(object sender, EventArgs e)
        {
            RunPackages rp = new RunPackages();    
            if(rp.IsDisposed)
                return;
            this.Hide();
            rp.ShowDialog();//The error points to this line
            this.Show();
        }