打开处置对象(表单) [英] Open Disposed Object (Form)

查看:51
本文介绍了打开处置对象(表单)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,

i有多形式项目,并且有一个事件,当这个事件被触发时,一个新表单应该打开,现在如果我关闭这个表单并尝试重新打开它时间,编译器抱怨无法访问已处置的对象



经过一些试验后,我设法弄清楚但我想要知道我的解决方案是否很差,是否有更好的解决方案



  if (newgame_form.IsDisposed)
{
newgame_form = new new_game();
newgame_form.Show();
}
其他
newgame_form.Show();





注意newgame_form被声明为全局new_game表格

 new_game newgame_form =  new  new_game (); 





提前致谢,

z3ngew

解决方案

这个解决方案没问题。



但是,如果你只想使用表单的一个实例,你实际上可以将表单存储在一个字典(一旦加载)然后在需要时显示它。


这里有两种情况:



1.当用户(或您,在您的代码中)关闭给定的表单:您不需要保留该表单上的任何当前信息。 信息可能意味着:在表单的各种控件中选择的内容,在表单的各种文本框中输入的内容等。



很好,请使用Dispose。 />


然后,当你再次需要时,你必须重新创建那个表格,就像麦当娜唱的那样:像处女一样,这是第一次。



2.当你想要隐藏一个表格然后再次显示时,可能是因为你想保留表格中的信息:只需使用FormX.Hide();或FormX.Visible ='false;



~



正如我尊敬的同事Abhinav S的回答所指出的那样,有很多方法可以跟踪哪些表格目前活着;他提出的技术是使用字典。



但是,请记住,在Windows窗体的运行时的任何时刻:Application.OpenForms为您提供列表(还有什么?)当前打开的表单(打开表示可见。



不幸的是,它不是支持运营商的列表,如'包含或有用的Linq每次你想看看给定的Form Type是否打开时,你都必须枚举Application.OpenForms(真的,没什么大不了的)



~



那么,是否有另一种系统的方式来跟踪所有开放的表格,以及他们的视觉状态,显示或隐藏:嗯,我相信有一点点变化Abhinav的字典概念可能很有用:



1.定义类型字典< FormInstance,bool>



2.当您处理表格时,将其从字典中删除。



3.当您创建表格的新实例时:添加将它添加到Dictionary中,使用Form as Key添加一个新的KeyValuePair,并将KeyValuePair的布尔值设置为'如果可见则为true,如果不可见则设置为false。



4.当您更改窗体的可视状态但未放置它时:设置KeyValuePair的布尔值,其中Form是其更改的可视状态的关键。



然后,如何更新此词典以反映包含在键中的表单的状态的变化:当表单关闭时,隐藏表单时,何时存在,但是是隐藏的,您或用户是否希望再次显示它?如何处理添加另一个新表格,并用词典注册它,并确保它在状态改变时更新词典?



如果创建字典的表单(可能是您的主表单)也创建了正在使用的其他表单,那么,在创建它们时,您可以将它们的VisibleChanged和FormClosed事件连接到主表单中定义的EventHandler。

这看起来如何代码:

  //  表单实例字典和布尔 
// 表示其视觉状态
// true =显示
// false =隐藏
私人字典<表格,布尔> dictActiveForms = new Dictionary< Form,bool>();

// 为方便起见
private Form changingForm;

// 请注意在
<内创建的表单实例< span class =code-comment> // 此表单的范围加载EventHandler
// 在被调用后消失,唯一的
// 可访问是通过'dictActiveForms

// 还注意我们没有包含主表格
// 实例本身在字典中我们'填充'在这里
私人 void MainForm_Load( object sender,EventArgs e)
{
Form2 instanceOfForm2 = new 窗体2();
instanceOfForm2.Text = 原始Form2实例;
dictActiveForms.Add(instanceOfForm2, true );
instanceOfForm2.Show();

// 没有重复的密钥错误,因为我们正在使用
// 表单实例为键,而不是表单类型
Form2 anotherInstanceOfForm2 = new Form2();
anotherInstanceOfForm2.Text = 第二个Form2实例;
// 注意这个不可见,但
dictActiveForms.Add(anotherInstanceOfForm2 , false );

Form3 instanceOfForm3 = new Form3();
instanceOfForm3.Text = 唯一的Form3实例;
dictActiveForms.Add(instanceOfForm3, true );
instanceOfForm3.Show();

// 为所有表单连接事件
// 我们已创建并放入词典
wireAllFormEvents();
}

private void wireFormEvents(Form theForm)
{
theForm.VisibleChanged + = TheFormOnVisibleChanged;
theForm.Closed + = TheFormOnClosed;
}

private void wireAllFormEvents()
{
// 现在让我们为每个表单连接事件
foreach (在 dictActiveForms.Keys中形成themorm
{
wireFormEvents(theForm);
}
}

private void TheFormOnVisibleChanged( object sender,EventArgs eventArgs)
{
changingForm = sender as Form;

dictActiveForms [changingForm] = changingForm.Visible;
}

private void TheFormOnClosed( object sender,EventArgs eventArgs)
{
changingForm = sender as Form;

dictActiveForms.Remove(changingForm);
}

以此为基础,让我们考虑如果用户(或您,程序员,在您的代码中)想要使上面创建的Type 2的第二个实例可见,会发生什么。出于演示目的,我们将在Button的Click EventHandler中定义:

  private   void  button1_Click( object  sender,EventArgs e)
{
// < span class =code-comment>我们可以在这里使用Linq,注意我们不是
// 检查此处以确保第二个实例
// 仍然存在:即使没有错误
// 如果没有,也会抛出;
// 请记住,这只是一个演示
< span class =code-keyword> foreach (在 dictActiveForms.Keys中形成themorm
{
if (theForm.Text == 第二个Form2实例;
{
if (dictActiveForms [theForm] == false )theForm.Visible = true ;
break ;
}
}
}

如何在运行时添加所需类型的新Form实例,并做正确的事到使其行为与表单加载事件中创建的其他辅助表单相似:

  private   void  addNewForm(类型formType,字符串 formText, bool  isFormVisible)
{
表单newForm =(Form)Activator.CreateInstance(formType);
newForm.Text = formText;
dictActiveForms.Add(newForm,isFormVisible);
wireFormEvents(newForm);
newForm.Visible = isFormVisible;
}

对此方法的调用可能如下所示(再次,出于演示目的,我们将其放入Button的Click EventHandler中):

 < span class =code-keyword> private   void  button2_Click( object  sender,EventArgs e )
{
addNewForm( typeof (Form3), Form3的另一个实例 true );
}

讨论:当管理由WinForms中的主窗体创建的多个窗体时,这是只有一种方法,并提供动态添加的多个窗体(在运行时) 。这里的代码经过了全面测试,但仅出于教育原因而以相当精细的形式写出来。



在很多情况下,你会事先知道究竟有多少次要您的主要表单可能需要的表单,并且不会有所不同,您可以通过简单地保留每个辅助表单的引用来降低此处显示的代码的复杂性。而且,在许多情况下,您不需要允许用户在运行时创建多个新的二级表单实例。



imho,其中的内容非常有趣您可以通过修改WinForms应用程序的正常行为(在Program.cs文件中运行单个主表单实例)来创建多个独立的表单...但这是另一个故事。



希望你在这里的代码中找到一些有用的位。



编辑...对于任何想要使用工作代码的人来说这里显示的是针对FrameWork 2.0编译的,因此,希望每个人都能使用它:[ ^ ]。


Hello everyone,
i have multiform project, and there is an event, when this event is fired a new form is supposed to open, now if i close this form and try to reopen it one more time, the compiler complains "cannot access a disposed object".

after some trials, i managed to figured it out but i would like to know if my solution is poor and if there is some better one

if (newgame_form.IsDisposed)
{
    newgame_form = new new_game();
    newgame_form.Show();
}
else
    newgame_form.Show();



Note newgame_form is declared as global new_game form

new_game newgame_form = new new_game();



Thanks in advance,
z3ngew

解决方案

This solution is ok.

However, if you want to use just a single instance of a form, you can actually store the form in a dictionary (once loaded) then display it as and when required.


There are two scenarios possible here:

1. when the user (or you, in your code) closes a given Form: you don't need to retain any of the current information on that Form. Where "information" could mean: what is selected in a Form's various Controls, what is entered in a Form's various TextBoxes, etc.

Great, use Dispose.

Then, you must recreate that Form, when you need it again, as Madonna sang: "Like a virgin, for the very first time."

2. when you want to 'hide a Form, and then, show it again, presumably because you want to retain the information in the Form: just use FormX.Hide(); or FormX.Visible = 'false;

~

As my respected colleague Abhinav S's answer points out, there are a number of ways you could keep track of which Forms are currently "alive;" the technique he proposed is using a Dictionary.

But, keep in mind that, at any moment at run-time in Windows Forms: Application.OpenForms supplies you with a List of (what else ?) currently open Forms (where open means "visible".

Unfortunately, it's not a List that supports operators like 'Contains, or useful Linq operators. You'd have to enumerate Application.OpenForms every time you wanted to see if a given Form Type was open (really, not such a big deal)

~

So, is there another systematic way to keep track of all the open Forms, and their visual state, shown, or hidden: well, I believe a slight variation on Abhinav's Dictionary concept may be useful:

1. define a Dictionary of type <FormInstance, bool>

2. when you dispose of a Form, remove it from the Dictionary.

3. when you create a new instance of a Form: add it to the Dictionary, add a new KeyValuePair, with the Form as Key, and set the boolean Value of the KeyValuePair to 'true if it is visible, and 'false if it is not.

4. when you change the visual state of a Form, but are not disposing it: set the boolean Value of the KeyValuePair of which the Form is the Key to its changed visual state.

How, then, is this Dictionary to be updated to reflect changes in the "state" of the Forms contained as Keys: when a Form is closed, when it's hidden, when it exists, but is hidden, and you, or the user, want to make it visible again ? How to handle adding another new Form, and "registering" it with the Dictionary, and making sure it, too, updates the Dictionary when its "state" changes ?

If the Form that creates the Dictionary (presumably your Main Form) also creates the other Forms being used, then, at the moment they are created, you can wire-up their VisibleChanged, and FormClosed Events to EventHandlers defined in your main Form.
How might this look in code:

// the dictionary of instances of Forms, and a boolean
// that will indicate their visual state
// true = shown
// false = hidden
private Dictionary<Form, bool> dictActiveForms = new Dictionary<Form, bool>();

// for convenience
private Form changingForm;

// note that the Form instances created inside
// the scope of this Form Load EventHandler
// are "gone" after it's been called, and the only
// access available is through the 'dictActiveForms

// also note that we did not include the Main Form
// instance itself in the Dictionary we 'fill-up' here
private void MainForm_Load(object sender, EventArgs e)
{
    Form2 instanceOfForm2 = new Form2();
    instanceOfForm2.Text = "the original Form2 instance";
    dictActiveForms.Add(instanceOfForm2, true);
    instanceOfForm2.Show();

    // no duplicate key error because we are using
    // Instances of Forms as Keys, not Form "Types"
    Form2 anotherInstanceOfForm2 = new Form2();
    anotherInstanceOfForm2.Text = "the second Form2 instance";
    // note this one's not visible, yet
    dictActiveForms.Add(anotherInstanceOfForm2, false);

    Form3 instanceOfForm3 = new Form3();
    instanceOfForm3.Text = "the one-and-only Form3 instance";
    dictActiveForms.Add(instanceOfForm3, true);
    instanceOfForm3.Show();

    // wire up the Event for all the Forms
    // we've created and put in the Dictionary
    wireAllFormEvents();
}

private void wireFormEvents(Form theForm)
{
    theForm.VisibleChanged += TheFormOnVisibleChanged;
    theForm.Closed += TheFormOnClosed;
}

private void wireAllFormEvents()
{
    // now let's wire the Events up for every Form
    foreach (Form theForm in dictActiveForms.Keys)
    {
        wireFormEvents(theForm);
    }
}

private void TheFormOnVisibleChanged(object sender, EventArgs eventArgs)
{
    changingForm = sender as Form;

    dictActiveForms[changingForm] = changingForm.Visible;
}

private void TheFormOnClosed(object sender, EventArgs eventArgs)
{
    changingForm = sender as Form;

    dictActiveForms.Remove(changingForm);
}

Using this as a basis, let's consider what happens if the user (or you, the programmer, in your code) wants to now make visible the second instance of Type Form2 created above. For demonstration purposes we'll define this in a Button's Click EventHandler:

private void button1_Click(object sender, EventArgs e)
{
    // we could use Linq here, and note we are not
    // checking here to make sure a second instance
    // of Form2 still exists: even though no error
    // will be thrown here if it doesn't;
    // keep in mind this is just a demo
    foreach (Form theForm in dictActiveForms.Keys)
    {
        if (theForm.Text == "the second Form2 instance";
        {
            if (dictActiveForms[theForm] == false) theForm.Visible = true;
            break;
        }
    }
}

How you might add, at run-time, a new Form instance of a Type you want, and "do the right thing" to make it behave like the other "secondary" Forms created here in the Form Load Event:

private void addNewForm(Type formType, string formText, bool isFormVisible)
{
    Form newForm = (Form) Activator.CreateInstance(formType);
    newForm.Text = formText;
    dictActiveForms.Add(newForm, isFormVisible);
    wireFormEvents(newForm);
    newForm.Visible = isFormVisible;
}

A call to this method could look like this (once again, for demo purposes, we'll put it in a Button's Click EventHandler):

private void button2_Click(object sender, EventArgs e)
{
    addNewForm(typeof(Form3), "another instance of Form3", true);
}

Discussion: this is "only one way to fly" when managing multiple Forms created by a Main Form in WinForms, and providing for multiple Forms to be added dynamically (at run-time). The code here is completely tested, but is written-out in fairly elaborate form for educational reasons, only.

In many cases you will know in advance exactly how many secondary Forms your main Form may need, and that doesn't vary, and you can reduce the complexity of the code shown here by simply keeping references around to each secondary Form. And, in many cases, you will not need to allow the user to create multiple new instances of secondary Forms at run-time.

imho, where things get really interesting is where you create multiple independent Forms by modifying the normal behavior of WinForms apps ("running" a single "main" form instance in the Program.cs file) ... but that's another story.

Hope you find some useful "bits" in the code here.

edit ... for anyone wants to play with the working code for what's shown here, compiled against FrameWork 2.0, so, hopefully everyone an use it: [^].


这篇关于打开处置对象(表单)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆