zoukankan      html  css  js  c++  java
  • WPF单例启动及利用单例制作类似WORD打开文档选项卡效果

    文章目的如下:

    1.WPF应用同时只允许运行一个实例

    2.利用这个单例特性实现类似Word等多选项卡打开的效果

    3.示例代码下载

    废话不多说直接正题。

    1.引用程度集 Microsoft.VisualBasic

    2.移除App.XAML

    3.创建类 MyWPFApp.cs 继承 System.Windows.Application 自定义一个 Application

        public class MyWPFApp : Application
        {
            public MyWPFApp()
            {
                ConfigApp();
            }
    
            public MyWPFApp(List<string> args)
            {
                this.OpenArgs = args;
                ConfigApp();
            }
    
            protected void ConfigApp()
            {
                this.StartupUri = new Uri("MainWindow.xaml", UriKind.Relative);
            }
    
        }

    2.创建类 SingleAppInsWrapper.cs 继承 Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase 自定义一个包装类 this.IsSingleInstance = true

    在重写 OnStartupNextInstance 中就可以处理当再有相同实例打开时的处理了(利用这个事件可扩展双击文件关联打开应用作出类似Office Word 打开多个文件选择卡的效果)

        /// <summary>
        /// 单例应用包装类
        /// </summary>
        public class SingleAppInsWrapper :Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase
        {
            public SingleAppInsWrapper()
            {
                // 标记为单例应用
                this.IsSingleInstance = true;
            }
    
            private MyWPFApp _myWPFApp;
    
            protected override bool OnStartup(Microsoft.VisualBasic.ApplicationServices.StartupEventArgs eventArgs)
            {
                //手动加载WPF应用
                this._myWPFApp = new MyWPFApp(eventArgs.CommandLine.ToList());
                this._myWPFApp.Run();
                return false;
            }
    
            protected override void OnStartupNextInstance(Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs eventArgs)
            {
                //从这里实现当再有相同应用打开时的逻辑
            }
        }
    

    3.添加 Startup.cs 类作为应用入口(到这步为止单例需要的基本完成)

        /// <summary>
        /// 启用应用类
        /// </summary>
        public class Startup
        {
            [STAThread]
            public static void Main(string[] args)
            {
                SingleAppInsWrapper wrapper = new SingleAppInsWrapper();
                wrapper.Run(args);
            }
        }
    

    以下开始则为额外的扩展,制作一个双击文件打开应用展示文件,当应用已打开则在应用中添加新的选项卡打开文件,不关心这点的可以跳过。

    4.修改 MainWindow.xaml 中内容为

    <Window x:Class="WPF.SingleIns.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="5*"/>
                <RowDefinition Height="59*"/>
            </Grid.RowDefinitions>
            <TextBlock>
                可以设置一些可读取文件(例如.txt)的打开方式为本程序,双击文件则会在这里以Tab方式打开
            </TextBlock>
            <TabControl Name="tabContent" Grid.Row="1">
            </TabControl>
        </Grid>
    </Window>
    

    5.修改MainWindow.xaml.cs 为

        /// <summary>
        /// MainWindow.xaml 的交互逻辑
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
    
                //若为命令打开,则打开参数中的文档
                var app = ((MyWPFApp)Application.Current);
                if (!string.IsNullOrEmpty(app.OpenFilePath))
                    app.OpenDocWin(app.OpenFilePath);
            }
    
            public void SwitchOrAppendTab(string filepath)
            {
                if (!SwitchTab(filepath))
                    AppendTab(filepath);
            }
    
            /// <summary>
            /// 切换选择卡
            /// </summary>
            /// <param name="filepath"></param>
            /// <returns></returns>
            protected bool SwitchTab(string filepath)
            {
                TabItem selItem = null;
                foreach (TabItem item in this.tabContent.Items)
                {
                    if ((string)item.Tag == filepath)
                        selItem = item;
                }
    
                if (selItem != null)
                {
                    this.tabContent.SelectedItem = selItem;
                    return true;
                }
                return false;
            }
    
            /// <summary>
            /// 添加选项卡
            /// </summary>
            /// <param name="filepath"></param>
            protected void AppendTab(string filepath)
            {
                var tabContainer = (IAddChild)this.tabContent;
    
                TabItem tabItem = new TabItem();
                tabItem.Tag = filepath;
                tabItem.Header = System.IO.Path.GetFileName(filepath);
                tabItem.Content = System.IO.File.ReadAllText(filepath, Encoding.Default);
    
                tabContainer.AddChild(tabItem);
    
                //设置添加项为选中项
                this.tabContent.SelectedItem = tabItem;
                
            }
        }
    

    6.MyWPFApp.cs 中添加方法

            public string OpenFilePath
            {
                get
                {
                    if (OpenArgs.Count > 0)
                        return this.OpenArgs.First();
                    return string.Empty;
                }
            }
    
            public void OpenDocWin(string filePath)
            {
                //这里的 MainWindow转换类型换成你的项目所在的命名空间
                var mainWin = (WPF.SingleIns.MainWindow)this.MainWindow;
                mainWin.SwitchOrAppendTab(filePath);
            }
    

    7.SingleAppInsWrapper.cs 中的 OnStartupNextInstance内添加以下代码即可

            protected override void OnStartupNextInstance(Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs eventArgs)
            {
                var filepath = eventArgs.CommandLine.First();
                //从这里实现当再有相同应用打开时的逻辑
                this._myWPFApp.OpenDocWin(filepath);
            }
    

    最终演示效果如下

    源码下载:

     https://files.cnblogs.com/files/nekoyzx/WPF.SingleIns.7z

  • 相关阅读:
    SQL Server索引进阶:第十二级,创建,修改,删除
    SQL Server索引进阶第十一篇:索引碎片分析与解决
    Object.create()和new object()和{}的区别
    vue 前后端分离nginx部署
    实现组件props双向绑定解决方案
    prop不同数据类型设置默认值
    vue + element ui 阻止表单输入框回车刷新页面
    Vue.js中 watch(深度监听)的最易懂的解释
    vue-resource和axios区别
    JS中 reduce() 的用法
  • 原文地址:https://www.cnblogs.com/nekoyzx/p/7594162.html
Copyright © 2011-2022 走看看