一、插件功能描述

插件监控一个xml文件,当该文档有添加新元素在保存的时候将新增的元素同步到指定的目录下。

二、模板的选择

由于该功能是跟代码编辑有关的,要监控文档的保存事件,所以要在文档打开的时候就注册保存事件的响应方法。VS提供了一个接口,监听文档的打开事件,这个接口就是:IWpfTextViewCreationListener,接口代码如下,该接口只有一个方法,在文档打开的时候会调用TextViewCreated方法执行。

  1. // 摘要:
  2. // Listens to text view created events.
  3. public interface IWpfTextViewCreationListener
  4. {
  5.   // 摘要:
  6.   // Called when a text view having matching roles is created over a text data
  7.   // model having a matching content type.
  8.   //
  9.   // 参数:
  10.   // textView:
  11.   // The newly created text view.
  12.   void TextViewCreated(IWpfTextView textView);
  13. }

所以随便选择一个模板都是可以的,只要在项目里面将模板创建的插件入口类改为继承IWpfTextViewCreationListener接口,并实现其接口即可。由于该功能需要用到选项配置功能,所以我建议读者使用Visual Stuido Package模板,因为使用该模板添加选项页会比较容易。这是msdn上在使用Visual Studio Package模板的情况下如何添加选项页的教程:http://msdn.microsoft.com/en-us/library/bb166195.aspx。我选择的是Editor Text Adornment模板,因为该模板创建的入口类就是继承IWpfTextViewCreationListener接口,但是使用该模板的话,添加选项页会比较麻烦一点。

三、添加选项页

按照msdn上的教程,我们知道需要添加两个类:继承Package的类和继承DialogPage的类,过程我就不再赘述。如果紧紧按照msdn上的教程,你会发现在工具-选项下根本没有我们添加的选项页(非Visual Studio Package模板的情况),这是为什么呢?原来在我们的csproj文件和source.extension.vsixmanifest里缺少了一些元素,按照下面的步骤就可以实现添加选项页的功能:

1、打开source.extension.vsixmanifest,选择Assets选项,点击New按钮,弹出图-1窗口

图-1

Type选择Microsoft.VisualStudio.Assembly,Source选择A project in current solution,Project选择当前的插件项目,点击OK添加完成,再次点击New按钮,这次的Type选择Microsoft.VisualStudio.VsPackage,Source和Project跟第一次的一样即可。

2、将csproj文件里的GeneratePkgDefFile元素改为true。

3、GeneratePkgDefFile元素后添加<CopyBuildOutputToOutputDirectory>true</CopyBuildOutputToOutputDirectory>

4、在GeneratePkgDefFile元素前添加<IncludeAssemblyInVSIXContainer>true</IncludeAssemblyInVSIXContainer>,注意IncludeAssemblyInVSIXContainer这个元素一定要添加在GeneratePkgDefFile和CopyBuildOutputToOutputDirectory元素之前。

经过上面的四个步骤,我们添加的选项页就会显示在工具-选项里了,如果缺少了第一个步骤的话会出现”加载此属性页时出错“的错误。

四、监听保存事件

通过查看TextViewCreated函数的参数类型textView,可以知道IWpfTextView 接口并没有包含文档保存的事件。那么,我们该如何才能订阅保存事件呢?通过查找相关的资料,发现可以通过以下方式获取文档的保存事件:

  1. //EnvDTE.DTE _dte
    this._dte = ServiceProvider.GlobalProvider.GetService(typeof(DTE)) as DTE;
    //EnvDTE.Events _events
  2. this._events = this._dte.Events;
    //EnvDTE.DocumentEvents _docEvents
  3. this._docEvents = this._events.DocumentEvents;

一定要记住一定要将上面的三个对象定义为全局变量,否则就没办法响应保存事件,这是因为C#的垃圾回收机制造成的,读者可以自己试一下定义为局部变量的情况。

以下是该插件的部分代码

  1. namespace AppSettingsSync
  2. {
  3. public class TextViewListener
  4. {
  5. /// <summary>
  6. /// 文档信息
  7. /// </summary>
  8. private ITextView _view;
  9.  
  10. private DTE _dte;
  11. private Events _events;
  12. private DocumentEvents _docEvents;
  13. /// <summary>
  14. /// 文档是否修改过
  15. /// </summary>
  16. private bool _isChanged;
  17. /// <summary>
  18. /// 保存的时候是否自动同步到其他AppSettings.xml
  19. /// </summary>
  20. private bool _isAutoReplace = true;
  21. /// <summary>
  22. /// 触发同步操作的AppSetting.xml
  23. /// </summary>
  24. private string _sourceFile;
  25. /// <summary>
  26. /// 要被同步的AppSettings.xml所在的文件目录
  27. /// </summary>
  28. private string _targetFolder;
  29.  
  30. /// <summary>
  31. /// 打开文档时触发
  32. /// </summary>
  33. /// <param name="textView"></param>
  34. public TextViewListener(IWpfTextView textView)
  35. {
  36. this._view = textView;
  37. this._dte = ServiceProvider.GlobalProvider.GetService(typeof(DTE)) as DTE;
  38. Properties props = this._dte.get_Properties("IStrong", "AppSettingsSync");
  39. if (props == null)
  40. return;
  41. this._sourceFile = (string)props.Item("SourceXmlFilePath").Value;
  42. //File.AppendAllText(@"D:\log.txt", "源文件" + this._sourceFile + "当前文件" + this._dte.ActiveDocument.FullName);
  43. if (!this._dte.ActiveDocument.FullName.Equals(this._sourceFile, StringComparison.OrdinalIgnoreCase))
  44. return;
  45. //获取DTE对象
  46. this._events = this._dte.Events;
  47. this._docEvents = this._events.DocumentEvents;
  48. //订阅文档保存和修改事件
  49. this._docEvents.DocumentSaved += _docEvents_DocumentSaved;
  50. this._view.TextBuffer.Changed += TextBuffer_Changed;
  51. }
  52.  
  53. /// <summary>
  54. /// 文档修改事件
  55. /// </summary>
  56. /// <param name="sender"></param>
  57. /// <param name="e"></param>
  58. void TextBuffer_Changed(object sender, Microsoft.VisualStudio.Text.TextContentChangedEventArgs e)
  59. {
  60. if (e.Changes.Count() > )
  61. this._isChanged = true;
  62. }
  63.  
  64. /// <summary>
  65. /// 文档保存事件
  66. /// </summary>
  67. /// <param name="Document"></param>
  68. async void _docEvents_DocumentSaved(Document Document)
  69. {
  70. try
  71. {
  72. //File.AppendAllText(@"D:\log.txt", "触发保存事件");
  73. //获取Tool->Opetions->IStrong->AppSettingsSync配置项内容
  74. Properties props = this._dte.get_Properties("IStrong", "AppSettingsSync");
  75. if (props == null)
  76. return;
  77. this._sourceFile = (string)props.Item("SourceXmlFilePath").Value;
  78. //保存时要同时满足是源AppSettings.xml文件和该文件有被修改过
  79. if (Document.FullName.Equals(this._sourceFile, StringComparison.OrdinalIgnoreCase) && this._isChanged)
  80. {
  81. this._isAutoReplace = (bool)props.Item("IsAutoSync").Value;
  82. this._targetFolder = (string)props.Item("TargetFolder").Value;
  83. //手动选择要同步的文件
  84. if (!this._isAutoReplace)
  85. {
  86. SelectFiles sf = new SelectFiles(this._sourceFile, this._targetFolder);
  87. sf.ShowDialog();
  88. this._isChanged = false;
  89. }
  90. else
  91. {
  92. //自动同步文件
  93. string fileName = System.IO.Path.GetFileName(this._sourceFile);
  94. string[] files = Directory.GetFiles(this._targetFolder, fileName, SearchOption.AllDirectories);
  95. this._isChanged = false;
  96. await SyncHelper.SyncAppSettings(this._sourceFile, files);
  97. //同步完成后修改Visual Studio状态栏信息
  98. IVsStatusbar bar = ServiceProvider.GlobalProvider.GetService(typeof(SVsStatusbar)) as IVsStatusbar;
  99. bar.SetText("AppSettings配置文件同步完成。");
  100. }
  101. }
  102. }
  103. catch (Exception ex)
  104. {
  105. MessageBox.Show(ex.Message, "提示", MessageBoxButton.OK, MessageBoxImage.Error);
  106. }
  107. }
  108. }
  109. }

获取VS的主题颜色

  1. /// <summary>
  2. /// 将模态窗口的颜色设置为Visual Studio的背景色
  3. /// </summary>
  4. /// <param name="themeColor"></param>
  5. /// <returns></returns>
  6. private Color converVsThemeColor(vsThemeColors themeColor)
  7. {
  8.   DTE2 dte2 = (EnvDTE80.DTE2)System.Runtime.InteropServices.Marshal.
  9.   GetActiveObject("VisualStudio.DTE.12.0");
  10.   uint color = dte2.GetThemeColor(themeColor);
  11.   int a = (int)color / 0x1000000;
  12.   int b = (int)(color - a * 0x1000000) / 0x10000;
  13.   int g = (int)(color - a * 0x1000000 - b * 0x10000) / 0x100;
  14.   int r = (int)(color - a * 0x1000000 - b * 0x10000 - g * 0x100);
  15.   return Color.FromArgb(0xFF, r, g, b);
  16. }

VS2013文件同步插件开发的更多相关文章

  1. BAT实现服务器文件同步

    服务器文件同步有很多工具,例如 GoodSync.rsync.BitTorrent Sync等……其实WINDOWS下自带了一个文件同步利器:ROBOCOPY.它是一个命令行的目录复制命令,自从Win ...

  2. 使用syncthing进行双机文件同步

    使用syncthing进行双机文件同步 syncthing是一款开源的文件同步软件,可以 syncthing安装 tar -zxvf syncthing-linux-amd64-v0.12.15.ta ...

  3. sharepoint多个NLB的web前段如何进行文件同步?

    大家都知道,sharepoint2010服务器场可能有2个或2个以上的web服务器做NLB,有个时候牵涉到上传文件到文件夹(说到这里,有人会说全部以二进制文件保存到文档库啊,但是有些情况不允许的,比如 ...

  4. BitTorrent Sync - 神奇的文件同步软件,无需服务器让多台电脑互相同步!

    176,487 微博 腾讯 空间 微信 141 49 如今人们对文件备份和同步的需求已经越来越强烈了.像 Dropbox 一样的云存储网盘有很多,但它们都有一个局限性,就是所有的文件都得经过它们的服务 ...

  5. 烂泥:linux文件同步之rsync学习(一)

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 这几天刚好有空就打算开始学习linux下的文件同步软件rsync,在学习rsync时,我们可以分以下几个步骤进行: 1. rsync是什么 2. rsy ...

  6. CentOS系统rsync文件同步 安装配置

    rsync是类unix系统下的数据镜像备份工具,从软件的命名上就可以看出来了——remote sync 它的特性如下: 可以镜像保存整个目录树和文件系统. 可以很容易做到保持原来文件的权限.时间.软硬 ...

  7. inotify配合rsync实现文件同步

    一.slave端rsync设置在此部署rsync服务和rsync daemon 1.安装rsync   2.配置rsyncd.conf文件#vi /etc/rsyncd.conf配置文件uid = r ...

  8. Rsync 3.1.0 发布,文件同步工具

    文件同步工具Rsync 3.1.0发布.2013-09-29 上一个版本还是2011-09-23的3.0.9 过了2年多.Rsync基本是Linux上文件同步的标准了,也可以和inotify配合做实时 ...

  9. cwRsync window下的跨服务器的文件同步

    cwRsync 是window下的文件同步软件,可以跨服务器运行,第一次运行的时候是全部备份同步,之后的同步采用的是增量同步 这个软件分为服务端和客户端. 服务器是需要同步的文件源, 客户端相当于是备 ...

随机推荐

  1. [NOIP2000] 提高组 洛谷P1017 进制转换

    题目描述 我们可以用这样的方式来表示一个十进制数: 将每个阿拉伯数字乘以一个以该数字所处位置的(值减1)为指数,以10为底数的幂之和的形式.例如:123可表示为 1*10^2+2*10^1+3*10^ ...

  2. hihoCoder #1067 : 最近公共祖先·二 [ 离线LCA tarjan ]

    传送门: #1067 : 最近公共祖先·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上上回说到,小Hi和小Ho用非常拙劣——或者说粗糙的手段山寨出了一个神奇的网站 ...

  3. how-do-i-access-windows-event-viewer-log-data-from-java

    https://stackoverflow.com/questions/310355/how-do-i-access-windows-event-viewer-log-data-from-java

  4. mybatis几种开发方式

    mybatis是比较轻巧的半自动化的CRM框架,它有几种开发方式,现今张列于此: 一.注解方式:在接口方法上面写SQL语句,有点类似springdataJPA 的query sql 语句 范例 @se ...

  5. IO与文件读写---Java的IO流架构

    http://www.blogjava.net/pengpenglin/archive/2010/03/03/314239.html#314399 http://www.blogjava.net/jo ...

  6. MD5加密Java工具类

    原文:http://www.open-open.com/code/view/1421764946296 import java.security.MessageDigest; public class ...

  7. django 简易博客开发 4 comments库使用及ajax支持

    首先还是贴一下源代码地址  https://github.com/goodspeedcheng/sblog 上一篇文章我们介绍了静态文件使用以及如何使用from实现对blog的增删改,这篇将介绍如何给 ...

  8. Robot Framework操作

    Robot Framework 介绍 RobotFramework是一款基于python的开源自动化测试框架,遵守Apache License 2.0协议,在此协议下所有人都可以免费开发和使用.因为R ...

  9. 【Mongodb教程 第五课 】MongoDB 删除集合

    drop() 方法 MongoDB 的 db.collection.drop() 是用来从数据库中删除一个集合. 语法: drop() 命令的基本语法如下 db.COLLECTION_NAME.dro ...

  10. 2 TypeScript--Hello World

    安装好TypeScript后,我们来完成第一个页面--Hello World 新建index.html文件: <!DOCTYPE html> <html> <head&g ...