惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Microsoft Azure Blog
Microsoft Azure Blog
大猫的无限游戏
大猫的无限游戏
月光博客
月光博客
V
V2EX
PCI Perspectives
PCI Perspectives
Latest news
Latest news
博客园 - 三生石上(FineUI控件)
C
CERT Recently Published Vulnerability Notes
W
WeLiveSecurity
Last Week in AI
Last Week in AI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
P
Palo Alto Networks Blog
T
The Exploit Database - CXSecurity.com
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
WordPress大学
WordPress大学
V
Vulnerabilities – Threatpost
H
Heimdal Security Blog
Attack and Defense Labs
Attack and Defense Labs
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Hacker News: Ask HN
Hacker News: Ask HN
博客园 - 叶小钗
V
Visual Studio Blog
Jina AI
Jina AI
P
Proofpoint News Feed
罗磊的独立博客
SecWiki News
SecWiki News
J
Java Code Geeks
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
L
LINUX DO - 热门话题
Security Archives - TechRepublic
Security Archives - TechRepublic
The Hacker News
The Hacker News
Hugging Face - Blog
Hugging Face - Blog
N
News and Events Feed by Topic
NISL@THU
NISL@THU
T
Tailwind CSS Blog
T
Tenable Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Recent Announcements
Recent Announcements
H
Hacker News: Front Page
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
T
Tor Project blog
宝玉的分享
宝玉的分享
Help Net Security
Help Net Security
S
Security Affairs
Microsoft Security Blog
Microsoft Security Blog
Google DeepMind News
Google DeepMind News
F
Fortinet All Blogs
G
GRAHAM CLULEY

博客园 - Vincent Yang

Cannot load macro project error SQL Express - "Failed generate a user instance..." SQL Express 2008 x64 Integration with Visual Studio 2008 SP1 PowerShell Operators Crystal Reports .NET Error - "Access to report file denied. Another program may be using it." - Vincent Yang (转:)SharePoint Database Naming Standards List Types & List Internal ID available within MOSS 2007 Telerik: IIS7 & IIS 7.5 and ‘Telerik.Web.UI.WebResource.axd’ is missing in web config 64bit SQL Server issues : Connections to SQL Server files (*.mdf) require SQL Server Express 2005 to function properly 正式入住Windows 7 + XPM Extreme Programming: Do these 12 practices make perfect? Pick up the pace with extreme programming Testing an ASP.NET Web Service using PowerShell Parsing XML Files with PowerShell Testing SQL Stored Procedures using PowerShell Working with Collections of Objects using PowerShell Generating iCalender file using ASP.NET SQL Server Precision And Scale Problems (SQL Server 精度问题) Six Quick Crystal Reports Design Tips
A Generic Singleton Form Provider for C#
Vincent Yang · 2009-02-20 · via 博客园 - Vincent Yang

June 19, 2008

An interesting, although generally basic, problem with Windows Forms is how to implement the singleton pattern on the forms. What do I mean? Well, consider this…

You’re writing a Windows Forms application and you have a bunch of Forms, such as a Preference window, an About window and so on. You’d like these forms to be modeless, yet you don’t want the user to be able to create more than one of them.

It’s a common problem, but there’s no built in way to handle it. Moreover, I’ve yet to see an elegant solution to it. The method explained below, which is as elegant as it’s going to get, creates a pseudo-factory class to manage the problem for you. Read on to find out more.

If a Form were just any old object, you could implement the Singleton pattern in the said class:

  1. class SomeSingletonClass {  
  2.     protected SomeSingletonClass () {  
  3.     }  
  4.   
  5.     private static SomeSingletonClass mInstance = null;  
  6.   
  7.     public static SomeSingletonClass Instance {  
  8.         get {  
  9.             if (mInstance == null) mInstance = new SomeSingletonClass();  
  10.             return mInstance;  
  11.         }  
  12.     }  
  13. }  

Of course, this isn’t thread safe - there are much better ways to do this in the general case. See here for a good explanation. In the case of forms, however, we don’t need to be thread safe. Windows forms are explicitly un-threadsafe themselves. They should (in most cases) only ever be initialized/used from a single thread. This constraint applies here too.

Now, this won’t work for Windows Forms. How come? Well, once the Windows Form has been closed (with Close() or otherwise) it, generally, gets disposed. We all know you can’t use a disposed form again. You’ll get a crash when trying to access the form again. So, what’s the work around?

Basically, we need to handle the FormClosed event, so that we know the form has been closed. We can then remove the reference to the form, once its been closed, and start all over again next time it’s needed. So we’d end up with something like this:

  1. class SomeSingletonForm : Form {  
  2.     protected SomeSingletonForm () {  
  3.     }  
  4.   
  5.     private static SomeSingletonForm mInstance = null;  
  6.   
  7.     public static SomeSingletonForm Instance {  
  8.         get {  
  9.             if (mInstance == null)  
  10.             {  
  11.                 mInstance = new SomeSingletonClass();  
  12.                 mInstance.FormClosed += new FormEventHandler(remover);  
  13.             }  
  14.             /* Could call mInstance.Show(); */  
  15.             return mInstance;  
  16.         }  
  17.     }  
  18.   
  19.     static void remover(object sender, FormClosedEventArgs e)  
  20.     {  
  21.         mInstance.FormClosed -= new FormClosedEventHandler(remover);  
  22.         mInstance = null;  
  23.     }  
  24. }  

Now we’re getting closer. It seems unnecessary, however, to implement this on every single form that we want to be a singleton form: It’s a lot of copying identical code, and it’s prone to bugs.

So what can we do? We create a provider class which creates singleton forms for us. Sort of like a singleton factory with a few little tricks to ensure only valid forms are around. I’ve seen code before for this on various blogs / message boards, but none of them are as complete as this one.

What’s the difference? It’s the use of generics that makes this implementation really handy. By using a generic method, we can return a form of the correct type: there’s no need to worry about casting.

Another modification is the addition of a parameters to the GetInstance method. Although this is a little dodge, and could break things if you aren’t careful, I’ve found it handy when used with a form whose constructor required extra arguments.

So here it is:

  1. class SingletonFormProvider  
  2. {  
  3.     static Dictionary<Type, Form> mTypeFormLookup = new Dictionary<Type, Form>();  
  4.   
  5.     static public T GetInstance<T>(Form owner)  
  6.         where T : Form  
  7.     {  
  8.         return GetInstance<T>(owner, null);  
  9.     }  
  10.   
  11.     static public T GetInstance<T>(Form owner, params object[] args)  
  12.         where T : Form  
  13.     {  
  14.         if (!mTypeFormLookup.ContainsKey(typeof(T)))  
  15.         {  
  16.             Form f = (Form)Activator.CreateInstance(typeof(T), args);  
  17.             mTypeFormLookup.Add(typeof(T), f);  
  18.             f.Owner = owner;  
  19.             f.FormClosed += new FormClosedEventHandler(remover);  
  20.         }  
  21.         return (T)mTypeFormLookup[typeof(T)];  
  22.     }  
  23.   
  24.     static void remover(object sender, FormClosedEventArgs e)  
  25.     {  
  26.         Form f = sender as Form;  
  27.         if (f == null) return;  
  28.   
  29.         f.FormClosed -= new FormClosedEventHandler(remover);  
  30.         mTypeFormLookup.Remove(f.GetType());  
  31.     }  
  32. }  

and to use it:

  1. AboutBox abox = SingletonFormProvider.GetInstance<AboutBox>(this);  
  2. abox.Show();  

Well, there you have it. A handy Generic Singleton Form provider for C#.

TEST