WindowsFormsApplicationBase使用说明

WindowsFormsApplicationBase 是一个在 .NET Framework 中用来简化 Windows Forms 应用程序启动过程的基类,通常用于简化应用程序的生命周期管理和其他一些功能。它属于 Microsoft.VisualBasic.ApplicationServices 命名空间,通常在使用 Visual Basic 时会较为常见,但也可以在 C# 中使用。

主要功能

  1. 单实例应用程序IsSingleInstance 属性控制应用程序是否只运行一个实例。当设置为 true 时,如果启动了一个新的实例,新的实例会向已经运行的实例发送消息,而不是再次启动。

  2. 启动事件

    • OnStartup:在应用程序启动时执行的代码,可以在这里设置一些启动逻辑,比如加载配置文件、初始化全局资源等。
    • OnCreateMainForm: 创建主窗体。你可以在这里指定应用程序的主窗体(通常是 Form)。
    • OnStartupNextInstance:当应用程序设置为 单实例模式(即 IsSingleInstance = true)时,如果用户启动了一个新的实例,OnStartupNextInstance 方法将被调用,而不会重新创建主窗体,而是激活已运行的实例。

  3. 退出事件

    • OnShutdown: 应用程序关闭时触发,你可以在这里释放资源或者保存应用程序的状态。
    • OnUnhandledException: 如果应用程序遇到未处理的异常,它会触发此事件。你可以用来做异常日志记录或者显示友好的错误信息。

使用场景1、增加Splash启动动画

  static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            // Application.EnableVisualStyles();
            // Application.EnableRTLMirroring();
            // Application.Run(new Form1());

            string[] commandline = new string[0];

            My.Application.Run(commandline);
        }

        static class My
        {
            private static MyApplication _app;
            private static object _appSyncRoot = new object();

            public static MyApplication Application
            {
                get
                {
                    if (_app == null)
                    {
                        lock (_appSyncRoot)
                        {
                            if (_app == null)
                            {
                                _app = new MyApplication();
                            }
                        }
                    }
                    return _app;
                }
            }
        }
        class MyApplication : WindowsFormsApplicationBase
        {
            public MyApplication() : base(AuthenticationMode.Windows)
            {
                IsSingleInstance = true;
                EnableVisualStyles = true;
                ShutdownStyle = ShutdownMode.AfterMainFormCloses;
            }
            //1.OnInitialize 是应用程序启动时的第一个回调方法,它在主窗体创建之前被调用。这个方法通常用于执行一些应用程序级别的初始化操作,如加载设置、配置资源、初始化全局状态等。它在应用程序的生命周期中仅被调用一次。
            protected override bool OnInitialize(ReadOnlyCollection<string> commandLineArgs)
            {
                Console.WriteLine("OnInitialize: 应用程序初始化");
                return base.OnInitialize(commandLineArgs);
            }
            //2.OnCreateSplashScreen 是用于创建应用程序启动时的 启动画面(Splash Screen)的回调方法。你可以通过重写这个方法来控制在应用程序加载和初始化期间显示一个自定义的启动画面。
            protected override void OnCreateSplashScreen()
            {
                Console.WriteLine("OnCreateSplashScreen: 初始化动画");
                SplashScreen = new SplashScreen();
            }
            //3.在应用程序启动时执行的代码,可以在这里设置一些启动逻辑,比如加载配置文件、初始化全局资源等。
            protected override bool OnStartup(StartupEventArgs eventArgs)
            {
                Console.WriteLine("OnStartup: 应用程序启动");
                return base.OnStartup(eventArgs);
            }
            //4.创建主窗体。可以在这里指定应用程序的主窗体(通常是 Form)。
            protected override void OnCreateMainForm()
            {
                Console.WriteLine("OnCreateMainForm: 创建主窗体");
                MainForm = new Form1();
            }
            //5.当应用程序设置为 单实例模式(即 IsSingleInstance = true)时,如果用户启动了一个新的实例,OnStartupNextInstance 方法将被调用,而不会重新创建主窗体,而是激活已运行的实例。
            protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
            {
                base.OnStartupNextInstance(eventArgs);
            }

            //6.应用程序关闭时触发,可以在这里释放资源或者保存应用程序的状态
            protected override void OnShutdown()
            {
                Console.WriteLine("OnShutdown: 应用程序关闭");
                base.OnShutdown();
            }
            //如果应用程序遇到未处理的异常,它会触发此事件。你可以用来做异常日志记录或者显示友好的错误信息。
            protected override bool OnUnhandledException(Microsoft.VisualBasic.ApplicationServices.UnhandledExceptionEventArgs e)
            {
                Console.WriteLine("OnUnhandledException: 发生了未处理的异常");
                return base.OnUnhandledException(e);
            }
        }

    }
//启动界面       
 public SplashScreen()
        {
            InitializeComponent();
            //延时以增加Splash Screen的显示时间
            System.Threading.Thread.Sleep(1000);
        }

使用场景2、类似微信双击快捷方式激活窗体

修改方法OnStartupNextInstance

  protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
            {
                Console.WriteLine("OnStartupNextInstance: 再次进入");
                if (MainForm != null)
                {
                    if (!MainForm.Visible)
                    {
                        MainForm.Visible = true;
                    }
                    if (MainForm.WindowState != FormWindowState.Normal)
                    {
                        MainForm.WindowState = FormWindowState.Normal;
                    }
                    MainForm.Activate();
                }
                base.OnStartupNextInstance(eventArgs);
            }

使用场景3、也可以类似wps 在同一个软件内打开不同的文档

要使用 Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs e参数

StartupNextInstanceEventArgs 提供了以下信息:

CommandLine:一个字符串数组,包含启动应用程序时传递的命令行参数。

当然还需要写入注册表,实现双击.xxx后缀时自动调用应用程序:

   string extension = ".xxx";
            string title = "SingleInstanceApplication";
            string extensionDescription = "A Test xxx";
            // Uncomment this line to create the file registration.
            // In Windows Vista, you'll need to run the application
            // as an administrator.            
            FileRegistrationHelper.SetFileAssociation(
              extension, title + "." + extensionDescription);

  protected override void OnStartupNextInstance(
            Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs e)
        {
            if (e.CommandLine.Count > 0)
            {                
               new xxx(e.CommandLine[0]);
            }
        }
 public class FileRegistrationHelper
    {
        public static void SetFileAssociation(string extension, string progID)
        {
            // Create extension subkey
            SetValue(Registry.ClassesRoot, extension, progID);

            // Create progid subkey
            string assemblyFullPath = System.Reflection.Assembly.GetExecutingAssembly().Location.Replace("/", @"\");
            StringBuilder sbShellEntry = new StringBuilder();
            sbShellEntry.AppendFormat("\"{0}\" \"%1\"", assemblyFullPath);
            SetValue(Registry.ClassesRoot, progID + @"\shell\open\command", sbShellEntry.ToString());
            StringBuilder sbDefaultIconEntry = new StringBuilder();
            sbDefaultIconEntry.AppendFormat("\"{0}\",0", assemblyFullPath);
            SetValue(Registry.ClassesRoot, progID + @"\DefaultIcon", sbDefaultIconEntry.ToString());

            // Create application subkey
            SetValue(Registry.ClassesRoot, @"Applications\" + Path.GetFileName(assemblyFullPath), "", "NoOpenWith");
        }

        private static void SetValue(RegistryKey root, string subKey, object keyValue)
        {
            SetValue(root, subKey, keyValue, null);
        }
        private static void SetValue(RegistryKey root, string subKey, object keyValue, string valueName)
        {
            bool hasSubKey = ((subKey != null) && (subKey.Length > 0));
            RegistryKey key = root;

            try
            {
                if (hasSubKey) key = root.CreateSubKey(subKey);
                key.SetValue(valueName, keyValue);
            }
            finally
            {
                if (hasSubKey && (key != null)) key.Close();
            }
        }
    }            
}

禁止 App.xaml 自动生成 Main()

在 WPF 项目的 .csproj 文件中,找到 <PropertyGroup>,添加以下内容:

<PropertyGroup>
    <StartupObject>WpfApp.Program</StartupObject>
</PropertyGroup>

这会阻止 App.xaml 自动生成 Main() 方法,并使用 Program.Main() 作为应用入口。

<think>好的,用户的问题是关于如何防止WPF应用程序被多次打开,并在尝试多开时传递参数到已有实例的函数中。我需要结合提供的引用资料来解答这个问题。首先,用户提到的引用[1]中有SingleInstanceManager的示例,这应该是关键点。我需要回忆一下C#中处理单实例应用的方法。通常可以使用Mutex或者SingleInstanceManager来实现。 用户希望传递参数到已有实例,所以仅仅用Mutex可能不够,需要能够处理后续实例启动时的参数传递。引用[1]中的EntryPoint类使用了SingleInstanceManager,这可能是一个自定义的类,用于管理单实例。可能需要查看SingleInstanceManager的实现,但用户没有提供这部分代码。不过根据常规做法,这个类可能使用Windows消息或者IPC机制来传递参数。 接下来,用户提供的代码示例中的Main方法调用了manager.Run(args),这可能意味着SingleInstanceManager负责检查是否已有实例运行,如果没有则启动新实例,否则将参数传递给已有实例。引用中的代码片段还展示了如何创建EntryPoint,这应该是应用程序的入口点,替代默认的App类。 然后需要考虑如何在WPF应用程序中接收传递过来的参数。通常,后续实例启动时,参数需要发送到主实例,主实例需要监听这些参数并处理。可能需要使用命名管道、内存映射文件或者Windows消息等方式进行进程间通信。 引用[3]提到了使用钩子和ACL来控制访问,但可能不太相关。而引用[2]是关于音频文件写入的,似乎和当前问题无关。因此,重点应放在引用[1]的SingleInstanceManager上。 总结步骤应该是:使用SingleInstanceManager检测是否已有实例,如果是,则将参数传递给已有实例并退出。主实例需要监听传入的参数,可能通过重写OnStartup方法或者使用特定的通信机制。此外,可能需要使用Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase类,虽然这是Windows Forms的,但可以在WPF中使用。 另外,需要处理命令行参数的接收和传递。当新实例启动时,获取其命令行参数,通过IPC发送到主实例,主实例接收后触发事件处理这些参数,比如更新界面或执行函数。 现在需要将这些步骤具体化,给出代码示例,并确保符合WPF的结构。可能需要创建自定义的Application类,处理启动事件,并集成SingleInstanceManager的逻辑。同时,确保参数正确传递到目标函数,比如通过事件或委托。</think>在WPF中实现单实例应用并传递参数,可通过以下步骤实现: ### 一、单实例检测与参数传递实现 1. **使用Microsoft.VisualBasic程序集**(需添加引用) ```csharp using Microsoft.VisualBasic.ApplicationServices; using System.Windows; public class SingleInstanceApp : WindowsFormsApplicationBase { private WpfApp _app; public SingleInstanceApp() { this.IsSingleInstance = true; } protected override bool OnStartup(StartupEventArgs eventArgs) { _app = new WpfApp(); _app.Run(); return false; } protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs) { base.OnStartupNextInstance(eventArgs); // 接收新实例参数并处理 _app.HandleNewInstanceArgs(eventArgs.CommandLine.ToArray()); } } public partial class App : Application { protected override void OnStartup(StartupEventArgs e) { // 主实例参数处理 MainWindow mainWindow = new MainWindow(); mainWindow.ProcessArgs(e.Args); mainWindow.Show(); } public void HandleNewInstanceArgs(string[] args) { if (MainWindow is MainWindow mainWindow) { mainWindow.ProcessArgs(args); } } } ``` 2. **修改入口点**(App.xaml中删除StartupUri) ```csharp public class EntryPoint { [STAThread] public static void Main(string[] args) { SingleInstanceApp app = new SingleInstanceApp(); app.Run(args); } } ``` ### 二、参数处理示例 ```csharp // MainWindow.xaml.cs public partial class MainWindow : Window { public void ProcessArgs(string[] args) { if (args.Length > 0) { // 示例:将参数传递给ViewModel this.DataContext = new MainViewModel(args); // 或直接执行操作 MessageBox.Show($"收到新参数:{string.Join(",", args)}"); } } } ``` ### 三、实现原理 1. **单例检测**:通过`WindowsFormsApplicationBase.IsSingleInstance`实现进程级锁[^1] 2. **参数传递**:使用Windows消息传递机制,新实例参数会通过`OnStartupNextInstance`回调 3. **线程安全**:WPF的`Dispatcher`自动保证UI线程安全
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值