文章目的如下:
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