| File: System\Windows\Forms\ApplicationContext.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms\System.Windows.Forms.csproj (System.Windows.Forms) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; namespace System.Windows.Forms; /// <summary> /// ApplicationContext provides contextual information about an application /// thread. Specifically this allows an application author to redefine what /// circumstances cause a message loop to exit. By default the application /// context listens to the close event on the mainForm, then exits the /// thread's message loop. /// </summary> public class ApplicationContext : IDisposable { private Form? _mainForm; /// <summary> /// Creates a new ApplicationContext with no mainForm. /// </summary> public ApplicationContext() : this(null) { } /// <summary> /// Creates a new ApplicationContext with the specified mainForm. /// If OnMainFormClosed is not overridden, the thread's message /// loop will be terminated when mainForm is closed. /// </summary> public ApplicationContext(Form? mainForm) { // These are subclasses of the ApplicationContext for which we don't need to call the finalizer, // because it's empty. See https://github.com/dotnet/winforms/issues/6858. if (GetType() == typeof(ApplicationContext) || GetType() == Application.s_typeOfModalApplicationContext) GC.SuppressFinalize(this); MainForm = mainForm; } // NOTE: currently this finalizer is unneeded (empty). See https://github.com/dotnet/winforms/issues/6858. // All classes that are not need to be finalized must be checked in ApplicationContext(Form? mainForm) constructor. // Consider to modify it if needed. ~ApplicationContext() => Dispose(false); /// <summary> /// Determines the mainForm for this context. This may be changed /// at anytime. /// If OnMainFormClosed is not overridden, the thread's message /// loop will be terminated when mainForm is closed. /// </summary> public Form? MainForm { get => _mainForm; set { EventHandler onClose = OnMainFormDestroy; _mainForm?.HandleDestroyed -= onClose; _mainForm = value; _mainForm?.HandleDestroyed += onClose; } } [SRCategory(nameof(SR.CatData))] [Localizable(false)] [Bindable(true)] [SRDescription(nameof(SR.ControlTagDescr))] [DefaultValue(null)] [TypeConverter(typeof(StringConverter))] public object? Tag { get; set; } /// <summary> /// Is raised when the thread's message loop should be terminated. /// This is raised by calling ExitThread. /// </summary> public event EventHandler? ThreadExit; /// <summary> /// Disposes the context. This should dispose the mainForm. This is /// called immediately after the thread's message loop is terminated. /// Application will dispose all forms on this thread by default. /// </summary> public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing) { if (_mainForm is not null) { if (!_mainForm.IsDisposed) { _mainForm.Dispose(); } _mainForm = null; } } // If you are adding releasing unmanaged resources code here (disposing == false), you need to: // 1. remove GC.SuppressFinalize from constructor of this class and from all of its subclasses // 2. remove ApplicationContext_Subclasses_SuppressFinalizeCall test // 3. modify ~ApplicationContext() description. } /// <summary> /// Causes the thread's message loop to be terminated. This will call ExitThreadCore. /// </summary> public void ExitThread() => ExitThreadCore(); /// <summary> /// Causes the thread's message loop to be terminated. /// </summary> protected virtual void ExitThreadCore() => ThreadExit?.Invoke(this, EventArgs.Empty); /// <summary> /// Called when the mainForm is closed. The default implementation /// of this will call ExitThreadCore. /// </summary> protected virtual void OnMainFormClosed(object? sender, EventArgs e) => ExitThreadCore(); /// <summary> /// Called when the mainForm is closed. The default implementation /// of this will call ExitThreadCore. /// </summary> private void OnMainFormDestroy(object? sender, EventArgs e) { Debug.Assert(sender is Form); Form form = (Form)sender; if (!form.RecreatingHandle) { form.HandleDestroyed -= OnMainFormDestroy; OnMainFormClosed(sender, e); } } }