A Generic Singleton Form Provider for C#
2009-02-20 09:16
477 查看
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:
view plaincopy to clipboardprint?
class SomeSingletonClass {
protected SomeSingletonClass () {
}
private static SomeSingletonClass mInstance = null;
public static SomeSingletonClass Instance {
get {
if (mInstance == null) mInstance = new SomeSingletonClass();
return mInstance;
}
}
}
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:
view plaincopy to clipboardprint?
class SomeSingletonForm : Form {
protected SomeSingletonForm () {
}
private static SomeSingletonForm mInstance = null;
public static SomeSingletonForm Instance {
get {
if (mInstance == null)
{
mInstance = new SomeSingletonClass();
mInstance.FormClosed += new FormEventHandler(remover);
}
/* Could call mInstance.Show(); */
return mInstance;
}
}
static void remover(object sender, FormClosedEventArgs e)
{
mInstance.FormClosed -= new FormClosedEventHandler(remover);
mInstance = null;
}
}
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:
view plaincopy to clipboardprint?
class SingletonFormProvider
{
static Dictionary<Type, Form> mTypeFormLookup = new Dictionary<Type, Form>();
static public T GetInstance<T>(Form owner)
where T : Form
{
return GetInstance<T>(owner, null);
}
static public T GetInstance<T>(Form owner, params object[] args)
where T : Form
{
if (!mTypeFormLookup.ContainsKey(typeof(T)))
{
Form f = (Form)Activator.CreateInstance(typeof(T), args);
mTypeFormLookup.Add(typeof(T), f);
f.Owner = owner;
f.FormClosed += new FormClosedEventHandler(remover);
}
return (T)mTypeFormLookup[typeof(T)];
}
static void remover(object sender, FormClosedEventArgs e)
{
Form f = sender as Form;
if (f == null) return;
f.FormClosed -= new FormClosedEventHandler(remover);
mTypeFormLookup.Remove(f.GetType());
}
}
and to use it:
view plaincopy to clipboardprint?
AboutBox abox = SingletonFormProvider.GetInstance<AboutBox>(this);
abox.Show();
Well, there you have it. A handy Generic Singleton Form provider for C#.
TEST
相关文章推荐
- [Design Pattern] Generic Singleton Pattern with C#
- C#_MVC_ajax for form
- A simple C# generic singleton class
- 最轻量级但强大的ADO.NET Data Provider for SQLite 0.17版也C#了!
- A simple C# generic singleton class
- C#编译问题'System.Collections.Generic.IEnumerable' does not contain a definition for 'Where' and no extension method 'Where' accepting a first argument
- C# asp.net 4.6 For webForm使用FullCalendar3.8基础篇
- dblinq2007 LINQ provider for Oracle, PostgreSQL, MySQL, Ingres, SQLite, Firebird and ... SQL Server (C# 3.0)
- Generic Singleton Provider
- 用CheckForIllegalCrossThreadCalls 属性解决C#线程间操作无效
- (转)C#中的 Interfaces (For 初学者们)
- XSWT for Eclipse form layout
- ionic3 解决Error: No provider for Http!
- C#中设置console和form同时显示
- Form表单中默认值的改变(switch、for中使用break)
- javax.persistence.PersistenceE 4000 xception: No Persistence provider for EntityManage
- C#Form多线程处理
- C#中新建一个form实例后调用this.close,都关闭的问题
- Create a sample admin module for form processing
- c#如何实现在两个窗体(Form)间传输数据或变量