none
关于使用WindowsFormsApplicationBase实现单例程序的一个问题 RRS feed

  • 问题

  • 为了实现程序单例运行,我使用了WindowsFormsApplicationBase,如下:
    C# code
    public class SingleInstanceManager : WindowsFormsApplicationBase { Form m_Mainapp; public SingleInstanceManager(Form app) { m_Mainapp=app; IsSingleInstance=true; } protected override bool OnStartup(StartupEventArgs eventArgs) { Application.Run(m_Mainapp); return false; } protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs) { MessageBox.Show("已运行"); } }

    现在我在两个需要单例运行的程序中使用这个SingleInstanceManager
    A程序:
    MainFormA forma=new MainFormA();
    SingleInstanceManager manager=new SingleInstanceManager(forma);
    manager.Run(null);
    B程序:
    MainFormB forma=new MainFormB();
    SingleInstanceManager manager=new SingleInstanceManager(formb);
    manager.Run(null);
    现在发现问题:
    当只重复运行A程序或B程序时,工作正常。但是,如果启动了一个A程序,再启动B程序,却提示不能再运行。即认为了B程序也是A程序的实例了。但是A程序和B程序是没有任何关系的,请问这个怎么解决?
    2012年3月7日 2:14

答案

  • Hi 胡玉龙,

      你可以通过Activator.CreateInstance方法去反射出来指定dll里的窗体文件,更详细点就是Module Name,同样实现了singleton模式,只要每个窗体的名字都是唯一的。

    foreach (Type tCheckType in types)
                                {
                                    if (tCheckType.IsSubclassOf(typeof(System.Windows.Forms.Form)) && tCheckType.Name == strItem)
                                    {
                                        object o = Activator.CreateInstance(tCheckType);

                                        try
                                        {
                                            MethodInfo mi = tCheckType.GetMethod(strEntrance, new Type[] { typeof(object), typeof(object), typeof(object) });
                                            ((CModuleForms)p_Apps[strItem]).Form = (System.Windows.Forms.Form)mi.Invoke(o, new Object[] { oParent, oEvent,oWordName });
                                        }
                                        catch (Exception e)
                                        {
                                        
                                        }
                                    }
                                }

    类似上面的代码。


    orichisonic http://blog.csdn.net/orichisonic If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    2012年3月7日 5:15
  •  尝试这样做:

    public class SingleInstanceManager : WindowsFormsApplicationBase
    {
         Form sfrm = null;                             //要启动的那个窗体
         static List<Form> m_Mainapps=null;      //用于记录已经触发的窗体


         static SingleInstanceManager()
    {
    m_Mainapps=new List<Form>(); 
    }


         public SingleInstanceManager(Form app)
         {
           foreach(Form frm in   m_Mainapps)
            {
                if(frm.GetType().ToString()==app.GetType().ToString())             //说明两个窗体类型一致,表示已经被触发过了
               {
                     IsSingleInstance=false;
                     break;
               }
            }
                  IsSingleInstance=true;


            if(IsSingleInstance)
            {
                sfrm = app;
                m_Mainapps.Add(app);
            }
         }
         
         protected override bool OnStartup(StartupEventArgs eventArgs)
         {
                if(sfrm!=null)
               {
                Application.Run(sfrm);
                sfrm=null;
                return true;
               }
                else
                 {
                return false;
                  }
         }
         protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
         {
              MessageBox.Show("已运行");
         }
    }


       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年3月7日 4:35
    版主

全部回复

  • 困惑几天了,还忘高人指点一下。

    刚才试了一下,如果为A,B两个程序分别写一个SingleInstanceManager,则不会出问题。

    2012年3月7日 2:42
  •  依我看,我个人认为因为你两个窗体公用一个类SingleInstanceManager,这就导致如果任意一个窗体实例作为参数传入其中,导致IsSingleInstance设置为True,第二个窗体就无法运行了。

    【解决方案】

    public class SingleInstanceManager : WindowsFormsApplicationBase
    {
         Form sfrm = null;                             //要启动的那个窗体
         List<Form> m_Mainapps=new List<Form>();       //用于记录已经触发的窗体

         public SingleInstanceManager(Form app)
         {
           foreach(Form frm in   m_Mainapps)
            {
                if(frm.GetType().ToString()==app.GetType().ToString())             //说明两个窗体类型一致,表示已经被触发过了
               {
                     IsSingleInstance=false;
                     break;
               }
            }
                  IsSingleInstance=true;
            if(IsSingleInstance)
            {
                sfrm = app;
                m_Mainapps.Add(app);
            }
         }
         
         protected override bool OnStartup(StartupEventArgs eventArgs)
         {
                if(sfrm!=null)
               {
                Application.Run(sfrm);
                sfrm=null;
                return true;

               }
                else
                 {
                return false;
                  }
         }
         protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
         {
              MessageBox.Show("已运行");
         }
    }

       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年3月7日 2:45
    版主
  • TO: Wei_Dong:

    谢谢你的回复。我按照你的思路修改了程序,但我发:实际上在每次程序启动一个新的实例时,即SingleInstanceManager被实例化时,IsSingleInstance都为false;因此,像Mainapps这样的对象每次都会重新实例化,无法

    保存。

    不知道它内部是怎么判断的?

    2012年3月7日 3:45
  • 我推测,应该是因为两个程序都使用了SingleInstanceManager这个类的实例,而在它判断是否是单例时,依据就是SingleInstanceManager这个对象,这样,即只要使用了SingleInstanceManager类的程序,都将认为是一个程序(即SingleInstanceManager)的实例。
    2012年3月7日 4:11
  •  尝试这样做:

    public class SingleInstanceManager : WindowsFormsApplicationBase
    {
         Form sfrm = null;                             //要启动的那个窗体
         static List<Form> m_Mainapps=null;      //用于记录已经触发的窗体


         static SingleInstanceManager()
    {
    m_Mainapps=new List<Form>(); 
    }


         public SingleInstanceManager(Form app)
         {
           foreach(Form frm in   m_Mainapps)
            {
                if(frm.GetType().ToString()==app.GetType().ToString())             //说明两个窗体类型一致,表示已经被触发过了
               {
                     IsSingleInstance=false;
                     break;
               }
            }
                  IsSingleInstance=true;


            if(IsSingleInstance)
            {
                sfrm = app;
                m_Mainapps.Add(app);
            }
         }
         
         protected override bool OnStartup(StartupEventArgs eventArgs)
         {
                if(sfrm!=null)
               {
                Application.Run(sfrm);
                sfrm=null;
                return true;
               }
                else
                 {
                return false;
                  }
         }
         protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
         {
              MessageBox.Show("已运行");
         }
    }


       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年3月7日 4:35
    版主
  • Hi 胡玉龙,

      你可以通过Activator.CreateInstance方法去反射出来指定dll里的窗体文件,更详细点就是Module Name,同样实现了singleton模式,只要每个窗体的名字都是唯一的。

    foreach (Type tCheckType in types)
                                {
                                    if (tCheckType.IsSubclassOf(typeof(System.Windows.Forms.Form)) && tCheckType.Name == strItem)
                                    {
                                        object o = Activator.CreateInstance(tCheckType);

                                        try
                                        {
                                            MethodInfo mi = tCheckType.GetMethod(strEntrance, new Type[] { typeof(object), typeof(object), typeof(object) });
                                            ((CModuleForms)p_Apps[strItem]).Form = (System.Windows.Forms.Form)mi.Invoke(o, new Object[] { oParent, oEvent,oWordName });
                                        }
                                        catch (Exception e)
                                        {
                                        
                                        }
                                    }
                                }

    类似上面的代码。


    orichisonic http://blog.csdn.net/orichisonic If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    2012年3月7日 5:15
  • 谢谢大家的热心回复。我再看看
    2012年3月7日 9:36