Cannot Access Disposed Object - c#

I have a form, which is the main form that the user will work from. When the user presses a button another form loads (this displays a list of customers etc.).
When I exit the customer form, and then click on the button again, I get the "cannot access disposed object" error message.
Any ideas? I'm a beginner at this.
custForm custForm = new custForm();
private void button5_Click(object sender, EventArgs e)
{
custForm.Show();
}

The problem is simple. You declare outside the click method the form variable. This is a class instance variable, meaning that it is visible in every method of the class in which is contained.
But when you close the custForm via its own button, this variable points to a disposed object, meaning that the data area pointed by the variable has been freed and it is available for reuse by other part of your program.
The runtime error says it all. You cannot access this area.
A possible workaround is to check the property IsDisposed and if it returns true recreate the form
custForm cf = new custForm();
private void button5_Click(object sender, EventArgs e)
{
if(cf == null || cf.IsDisposed == true)
cf = new custForm();
cf.Show();
}

You just cannot reuse an instance which was already disposed (see IDisposable). You have to create a new instance of the other form to be able to open it again.

Related

Fully closing application in C# just won't work [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I'm writing a simple game and I have a function that basically should just exit the application or rather close everything currently open in C# (I'm using Windows Forms).
private void ExitApp()
{
Application.Exit();
}
However, nothing will work. I have tried using Environment.Exit(0), Application.Exit, tried using a for loop to close every form but it just won't work. What I have noticed is that even if I press the X button, the solution won't close, but something seems to be running in the background and I do not know what. Browsed Stackoverflow forum for similar issues, browsed other forums, googled for days, but nothing seemed to help.
This is the code for opening more forms :
Podešavanja p = new Podešavanja();
private void Settings_FormClosing(object sender, FormClosingEventArgs e)
{
this.Close();
Menu m = new Menu();
m.Show();
}
private void button1_Click(object sender, EventArgs e)
{
this.Close();
Menu m = new Menu();
m.Show();
}
The SettingsFormClosing event actually just opens up a new Form for me, without closing the previous one, why, I do not know.
Any help would be greatly appreciated.
The problem is that your forms are all running on the same thread. Take a look at your Program.cs file. See how it calls Application.Run(New Form1())? This is where your application form initially runs on the application thread.
So the problem we have here is: you are trying to close your Form, which is hosting your second form. Suppose your a single form with a button control on it. Now suppose you tried to tell your application you wanted the window form to close, but wanted the button to stay active and open -- crazy right? Well what you are trying to do is essentially the same thing -- mind you I am basing this on the assumption you are not multithreading. Your Form1 is hosting your Form2 instance, and thus you cannot run Form2 if Form1 is disposed. The best way I can think of, at least off the top of my head, is you need to create a recursive call in your Program.cs and tell it whether or not it needs to run a new Form before it truly exits. This is questionable at best, but it might suffice.
So let's modify our Program.cs Then:
static class Program
{
//This is where we set the current form running -- or to be run.
static Form CurrentForm;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Obviously, Form 1 starts everything so we hardcode that here on startup.
CurrentForm = new Form1();
//Then call our Run method we created, which starts the cycle.
Run();
}
//This runs the current form
static void Run()
{
//Tell our program to run this current form on the application thread
Application.Run(CurrentForm);
//Once the form OFFICIALLY closes it will execute the code below
//Until that point, imagine Application.Run being stuck there
if(CurrentForm != null && CurrentForm.IsDisposed == false)
{
//If our current form is NOT null and it is NOT disposed,
//Then that means the application has a new form to display
//So we will recall this method.
Run();
}
}
//This method is what we will call inside our forms when we want to
//close the window and open a new one.
public static void StartNew(Form form)
{
//Close the current form running
CurrentForm.Close();
//Set the new form to be run
CurrentForm = form;
//Once all this is called, imagine the program now
//Releasing Application.Run and executing the code after
}
}
Okay so if you wrap your head around this, then closing and opening a new form is a piece of cake. We simply can open new forms on button click events.
Inside Form1.cs:
private void OpenForm2_Click(object sender, EventArgs e)
{
Program.StartNew(new Form2());
}
Inside Form2.cs
private void OpenForm1_Click(object sender, EventArgs e)
{
Program.StartNew(new Form1());
}
I will reiterate, this method is super questionable.... But it may suffice for what ever you are doing. It is also super reusable through your application regardless of the class or form.

MS Visual Studio C# - Can someone explain to me why my code isn't working and how I can get it to work?

I'm writing a program to conduct a search within Windows Active Directory and return the search results to another form in a listbox.
This is what my getter method looks like on the main form:
public List<String> getSearchResults()
{
List<String> accountList = new List<String>();
foreach (SearchResult account in searchResultCollection)
{
accountList.Add(account.Properties["cn"][0].ToString());
}
return accountList;
}
It is called only on the second form at load:
private void AccSelect_Form_Load(object sender, EventArgs e)
{
List<String> accountList = Main_Form.getSearchResults();
}
However, the compiler tells me that "An object reference is required for a non-static method". But my getter method cannot be static at all.
From my research prior to asking this, it seemed like I would need an instance of the class that owns my getter method (so my main form) to be running. Which is fine since my first form is what instantiates the second form. The second form will never be running without the first form anyway.
Can anyone give me a possible solution to this? :C
when you need to call a method in the main form from the child form, can code like this (assumes your main form is of type MainForm):
MainForm parent = (MainForm)this.Owner;
parent.getSearchResult();//CustomMethodName();

Singleton form: how to handle the case when form is "disposed"

I want to implement a "Popup" information form, which should be shown at various occasions (like mouse over, context menu, etc), and which should automatically hide when the user changes the focus.
I decided to do it with the SINGLETON pattern, like this:
public class frmCellInfo : Form
{
public static frmCellInfo instance;
public static frmCellInfo GetInstance()
{
if (instance == null)
instance = new frmCellInfo();
return instance;
}
private frmCellInfo() // PRIVATE, because of Singleton
{
InitializeComponent();
}
private void frmCellInfo_Deactivate(object sender, EventArgs e)
{
this.Hide();
}
// ......
The form is called like this:
frmCellInfo frm = frmCellInfo.GetInstance();
frm.Show();
Basically, the automatic show/hide works like intended; however, when the user CLOSES the form by clicking the "X" icon, then the form goes, and next time, when I try to acces the form, I get the exception "Cannot access a disposed object"
So in way, the instance is still "there", but "disposed" (?)
Question: How should I rewrite the call of the form or the singleton pattern, so that in case the form is "disposed", I can create it again?
You can achieve it by canceling FormClosing event and hiding the form.
CancelEventArgs.Cancel Property
private void frmCellInfo_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
this.Hide();
}
Simple answer is: you shouldn't. Jon Skeet's description of the Singleton pattern is quite apt:
Essentially, a singleton is a class which only allows a single instance of itself to be created, and usually gives simple access to that instance.
A Form is possibly a poor candidate for a singleton instance - its state may change and you may need to show the form more than once. From my personal experience, the best candidates for singleton instances are classes which could be static, but either inherit another class or have to implement one or more interfaces. A Form doesn't fit those criteria very well.
So in way, the instance is still "there", but "disposed" (?)
Yes, if you really wanted to you could catch the ObjectDisposedException in your GetInstance method and re-create the instance of the form. This isn't the way to do it and actually goes against the whole idea of a singleton. Think twice whether you really want to follow the pattern before implementing a hack like this.
Your reference frmCellInfo.instance is not null,
when you tried to open form after it was closed by X button (Disposed)
Then method frmCellInfo.GetInstance() return reference to the disposed instance.
Set it to null in the FormClosed eventhandler
private void frmCellInfo_FormClosed(object sender, FormClosedEventArgs e)
{
frmCellInfo.instance = null;
}
Then in the method frmCellInfo.GetInstance() new instance will be created as you wanted

How to use the NavigationService.Navigate inside a CustomMessageBox Dismissed event handler?

I am using the CustomMessageBox control from the Silverlight Toolkit for Windows Phone. When passing an anonymous callback (a 'delegate' in MS speak?) as suggested in the tutorials I reference a member of the page's partial class defined in the code-behind file. This builds and deploys but crashes when I reach the logic at runtime.
I noticed from the VS debugger that the scope inside the callback only contains members from the XAML side of the page partial class and not the members from the code-behind file. This means that the member I refer to is not in the scope (even though Intellisense is fine with it). Moreover I cannot use NavigationService.Navigate inside the callback.
How do I call code within the containing class from the callback?
Here is the code,
// This is a member of the partial class which inherits from
// PhoneApplicationPage
private void cancelBtn_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
if ((this.nameTextBox.Text != String.Empty) || (bool)this.protectCheckBox.IsChecked)
{
CustomMessageBox messageBox = new CustomMessageBox()
{
Caption = "Confirm leave page",
Message = "You have entered some profile data which will be lost if you leave this page. Are you sure you want to leave this page?",
LeftButtonContent = "no",
RightButtonContent = "yes"
};
messageBox.Dismissed += (s1, e1) =>
{
if (e1.Result == CustomMessageBoxResult.RightButton)
{
// Both of these raise an exception ...
GoToProfilePage();
//NavigationService.Navigate(new Uri("/View/MainPage.xaml", UriKind.Relative));
// Inspecting the debugger here shows only half the expected
// number of methods in the 'this' object - specifically only
// those defined in XAML
}
};
messageBox.Show();
}
else
{
// This works fine
GoToProfilePage();
}
}
Where GoToProfilePage() is a method in the code-behind file.
This is the exception,
System.NullReferenceException was unhandled
Message=NullReferenceException
StackTrace:
at Microsoft.Phone.Controls.CustomMessageBox.ClosePopup(Boolean restoreOriginalValues)
at Microsoft.Phone.Controls.CustomMessageBox.c__DisplayClass4.b__1(Object s, EventArgs e)
at Microsoft.Phone.Controls.Transition.OnCompleted(Object sender, EventArgs e)
at MS.Internal.CoreInvokeHandler.InvokeEventHandler(Int32 typeIndex, Delegate handlerDelegate, Object sender, Object args)
at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName)
Update
It looks like the code is executed, it is only when the delegate finishes that the null reference exception is raised so it may not be a problem with scope ...
OK figured it out. The latest build of the Windows Toolkit .dll (which includes CustomMessageBox) needed a reference in my solution.
Apparently there is an older version of the Windows Toolkit which is included in the default references somewhere since both ContextMenu and CustomMessageBox worked at least partially beforehand which is very confusing ...
To add the updated reference, I built the .dll from the source in a separate project and copied it to my project. I added a reference from the Reference right-click menu in VS and browsed to the file in the debug\bin directory.
A quick hack is to comment line 657 of CustomMessageBox.cs file in the toolkit source code and compile again. Then reference this new dll in your app.
...
private void ClosePopup(bool restoreOriginalValues)
{
// Remove the popup.
_popup.IsOpen = false;
//_popup = null; <-- THIS IS LINE 657
...
There is an issue posted in http://phone.codeplex.com/workitem/10575

How to access methods in ThisAddin.cs file

I have created an Excel Addin project in C#. Now the solution contains a file ThisAddin.cs, which has a class ThisAddin. Later I have added an item called Form to the same solution. In Form, when I click on a button, for that button click event i want to call a method inside ThisAddin.cs file.
namespace ExcelAddIn
{
public partial class ThisAddIn
{
public void RefreshExcelData()
{
}
}
}
Now in MyForm.cs, while trying to create an object for ThisAddin class there is a compilation error that Thisaddin class doesn't have a constructor that takes 0 arguments.
private void btnUploadTestCases_Click(object sender, EventArgs e)
{
ThisAddIn objrefresh = new ThisAddin();
}
What am I missing here?
You are approaching the problem from the wrong direction. When you click the button, you don't want to create a new add-in, what you really want is to access the add-in instance which is created for you by VSTO when Excel starts up, which is accessible via Globals.ThisAddIn.
Change your code in the Form to the following:
private void btnUploadTestCases_Click(object sender, EventArgs e)
{
var addIn = Globals.ThisAddIn;
addIn.RefreshExcelData();
}
... and it should work a charm.
That being said, is there a good reason for this a method to be on ThisAddIn? In general, ThisAddIn should be used to wire up and tear down the add-in when Excel starts up / shuts down, and I would recommend to put as little logic in there as possible.
Use this code:
Globals.ThisAddIn.Application.StatusBar = "Referesh clicked!!!."; Globals.ThisAddIn.RefreshExcelData();
Just make sure your function remains public.

Categories

Resources