一、功能描述

该插件的功能跟代码文件的导航功能类似,只是下拉框里的内容是元素的某一属性值,如图-1所示

图-1

当点击下拉框的选项后,会自动定位到该内容在xml文件的位置。此功能适用于xml文件内容较多的情况。

二、选择Editor Margin插件模板

因为该插件模板会在编辑区的底部创建一个WPF控件,如图-2所示。

图-2

而你可以创建一个WPF用户控件,并将用户控件添加到该控件里,还可以改变该控件在编辑区的位置。按照Editor Margin模板的向导建立插件项目,在项目里有三个文件:source.extension.vsixmanifest、EditorMargin1、EditorMargin1Factory,改变位置是通过EditorMargin1Factory类的MarginContainerAttribute特性实现的,该特性接收PredefinedMarginNames静态类的常量字段,这些常量字段定义了控件可以停靠的位置,如图-3所示。具体的功能主要是在EditorMargin1文件里实现。

图-3

当文档打开的时候VS会加载MarginFactory类的CreateMargin方法执行。

三、创建WPF用户控件

在项目里添加一个WPF用户控件,在用户控件里添加一个ComboBox下拉控件,当下拉框的选项改变的时候触发定位操作。由于我们是在用户控件里添加下拉控件,在用户控件外部无法监控到下拉框的改变事件,所以我们需要在用户控件里添加一个事件,在下拉框改变事件里触发该事件,这样就可以间接订阅下拉框的选项改变事件。此外,还需要对外开放一个改变下拉框宽度的函数,用于编辑区大小改变的时候可以修改下拉框的宽度。具体的代码如下所示:

  1. /// <summary>
  2. /// MappingInfo.xaml 的交互逻辑
  3. /// </summary>
  4. public partial class MappingInfo : UserControl
  5. {
  6.   public delegate void DelegateSelectionChanged(object sender, SelectionChangedEventArgs e);
  7.   public event DelegateSelectionChanged SelectionChanged;
  8.  
  9.   public MappingInfo()
  10.   {
  11.     InitializeComponent();
  12.   }
  13.  
  14.   public MappingInfo(IEnumerable<XElement> elements)
      {
  15.     InitializeComponent();
  16.     List<Elements> list = new List<Elements>();
  17.     foreach (var item in elements)
  18.     {
  19.       if (item.Attribute("name") == null)
  20.         continue;
  21.       Elements model = new Elements();
  22.       model.Value = item.Attribute("name").Value;
  23.       string desc = item.Attribute("title") != null ? item.Attribute("title").Value : item.Attribute("remark") == null ? "" : item.Attribute("remark").Value;
  24.       string cache = item.Attribute("cache") != null ? item.Attribute("cache").Value : "";
  25.       model.Text = desc != "" ? string.Format("{0}({1})", model.Value, desc) : model.Value;
  26.       if (cache != "" && cache.Equals("true", StringComparison.OrdinalIgnoreCase))
  27.       {
  28.         model.Text += " √";
  29.       }
  30.       list.Add(model);
  31.     }
  32.     cbElement.DisplayMemberPath = "Text";
  33.     cbElement.SelectedValuePath = "Value";
  34.     cbElement.ItemsSource = list;
  35.     cbElement.SelectedIndex = ;
  36.     //订阅选项改变时的事件
  37.     cbElement.SelectionChanged += cbElement_SelectionChanged;
  38.   }
  39.  
  40.   void cbElement_SelectionChanged(object sender, SelectionChangedEventArgs e)
  41.   {
  42.     SelectionChanged(sender, e);
  43.   }
  44.  
  45.   public void SetComboBoxWidth(double width)
      {
  46.     this.cbElement.Width = width;
  47.   }
  48. }
  49.  
  50. class Elements
  51. {
  52.   public string Text { get; set; }
  53.   public string Value { get; set; }
  54. }

在EditorMargin1类的构造函数里将自定义的wpf用户控件添加到插件创建的控件里

  1. //设置导航栏的相关信息
  2. this.Height = ;
  3. this.ClipToBounds = false;
  4. this.Background = new SolidColorBrush(Colors.WhiteSmoke);
  5. this.Children.Add(mapInfo);
  6. //导航栏大小改变时改变下拉框的宽度
  7. this.SizeChanged += Navigate_SizeChanged;

四、使用户控件自适应编辑区宽度

要实现自适应的功能只需要在XmlFileNavigation类的构造函数里订阅SizeChanged事件,由于EditorMargin1类继承了Canvas类,而Canvas类又从其他类继承了SizeChanged事件,所以只要通过this.SizeChanged就可以订阅该事件,在事件里调用创建的用户控件对外开发的修改宽度函数即可。代码如下所示:

  1. /// <summary>
  2. /// 大小改变时下拉框也一起调整
  3. /// </summary>
  4. /// <param name="sender"></param>
  5. /// <param name="e"></param>
  6. void Navigate_SizeChanged(object sender, SizeChangedEventArgs e)
  7. {
  8.   //调整下拉框大小
  9.   //mapinfo为添加的wpf用户控件
  10.   mapInfo.SetComboBoxWidth(((EditorMargin1)sender).ActualWidth); }

为什么要在SizeChanged事件里设置下拉框的宽度,在EditorMargin1类的构造函数里设置就不行吗?因为在构造函数里获取编辑区宽度的话,第一个页面获取的宽度是不准确的,获取的宽度都是800,之后打开的页面的宽度才是正常的。有兴趣的同学可以在EditorMargin1类的构造函数里添加如下的代码,获取文档的宽度验证一下

  1. EnvDTE.DTE dte=ServiceProvider.GlobalProvider.GetService(typeof(DTE)) as DTE;
  2. double width = dte.ActiveDocument.ActiveWindow.Width;

五、根据选中的内容进行定位

由于该插件是针对xml文件的,而VS没有提供对xml文件内容的定位方法(可能是我还不知道),所以只能通过遍历整个文件来确定选中的内容是在文件中的行数。以下是在用户控件的响应事件里对选中的内容进行定位的代码:

  1. /// <summary>
  2. /// 下拉框改变事件
  3. /// </summary>
  4. /// <param name="sender"></param>
  5. /// <param name="e"></param>
  6. void cb_SelectionChanged(object sender, SelectionChangedEventArgs e)
  7. {
  8.   try
  9.   {
  10.     //获取下拉框选中项
        Elements model = (Elements)((ComboBox)sender).SelectedItem;
  11.     //获取DTE实例
  12.     DTE dte = ServiceProvider.GlobalProvider.GetService(typeof(DTE)) as DTE;
  13.     //找出选中项在xml文件里的行数
  14.     string[] lines = File.ReadAllLines(dte.ActiveDocument.FullName);
  15.     int line = ;
  16.     foreach (var item in lines)
  17.     {
  18.       line++;
  19.       if (item != "" && item.Contains(model.Value))
  20.       {
  21.         break;
  22.       }
  23.     }
  24.     //滚动条滚动到指定行数并显示光标
  25.     TextSelection selection = dte.ActiveDocument.Selection as TextSelection;
  26.     if (selection != null)
  27.     {
  28.       selection.MoveToLineAndOffset(line, );
  29.       selection.ActivePoint.TryToShow();
  30.     }
  31.   }
  32.   catch (Exception ex)
  33.   {
  34.     MessageBox.Show(ex.Message, "提示", MessageBoxButton.OK, MessageBoxImage.Error);
  35.   }
  36. }

如果要开发的导航插件式针对cs文件的话可以通过下面的代码获取cs文件里的字段、函数、事件、属性等的相关信息:

  1. dte.ActiveDocument.ProjectItem.FileCodeModel

以下的代码是针对ComboBox的美化样式

  1. <UserControl.Resources>
  2. <ControlTemplate x:Key="ComboBoxToggleButton" TargetType="{x:Type ToggleButton}">
  3. <Grid>
  4. <Grid.ColumnDefinitions>
  5. <ColumnDefinition />
  6. <ColumnDefinition Width="" />
  7. </Grid.ColumnDefinitions>
  8. <Border
  9. x:Name="Border"
  10. Grid.ColumnSpan=""
  11. CornerRadius=""
  12. Background="#FCFCFC"
  13. BorderBrush="#9BA7B7"
  14. BorderThickness="1 1 1 1" />
  15. <Border
  16. Grid.Column=""
  17. CornerRadius=""
  18. Margin=""
  19. Background="#FCFCFC"
  20. BorderBrush="#9BA7B7"
  21. BorderThickness="" />
  22. <Path
  23. x:Name="Arrow"
  24. Grid.Column=""
  25. Fill="Black"
  26. HorizontalAlignment="Center"
  27. VerticalAlignment="Center"
  28. Data="M 0 0 L 4 4 L 8 0 Z"/>
  29. </Grid>
  30. <ControlTemplate.Triggers>
  31. <Trigger Property="ToggleButton.IsMouseOver" Value="true">
  32. <Setter TargetName="Border" Property="Background" Value="#FDF4BF" />
  33. <Setter TargetName="Border" Property="BorderBrush" Value="#FFEC8B" />
  34. </Trigger>
  35. <Trigger Property="ToggleButton.IsChecked" Value="true">
  36. <Setter TargetName="Border" Property="Background" Value="#FFEC8B" />
  37. </Trigger>
  38. <Trigger Property="IsEnabled" Value="False">
  39. <Setter TargetName="Border" Property="Background" Value="#EEEEEE" />
  40. <Setter TargetName="Border" Property="BorderBrush" Value="#AAAAAA" />
  41. <Setter Property="Foreground" Value="#888888"/>
  42. <Setter TargetName="Arrow" Property="Fill" Value="#888888" />
  43. </Trigger>
  44. </ControlTemplate.Triggers>
  45. </ControlTemplate>
  46.  
  47. <ControlTemplate x:Key="ComboBoxTextBox" TargetType="{x:Type TextBox}">
  48. <Border x:Name="PART_ContentHost" Focusable="False" Background="{TemplateBinding Background}" />
  49. </ControlTemplate>
  50.  
  51. <Style x:Key="{x:Type ComboBox}" TargetType="{x:Type ComboBox}">
  52. <Setter Property="SnapsToDevicePixels" Value="true"/>
  53. <Setter Property="OverridesDefaultStyle" Value="true"/>
  54. <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
  55. <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
  56. <Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
  57. <Setter Property="Template">
  58. <Setter.Value>
  59. <ControlTemplate TargetType="{x:Type ComboBox}">
  60. <Grid>
  61. <ToggleButton
  62. Name="ToggleButton"
  63. Template="{StaticResource ComboBoxToggleButton}"
  64. Grid.Column=""
  65. Focusable="false"
  66. IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
  67. ClickMode="Press">
  68. </ToggleButton>
  69. <ContentPresenter
  70. Name="ContentSite"
  71. IsHitTestVisible="False"
  72. Content="{TemplateBinding SelectionBoxItem}"
  73. ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
  74. ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
  75. Margin="5,3,23,3"
  76. VerticalAlignment="Center"
  77. HorizontalAlignment="Left" />
  78. <TextBox x:Name="PART_EditableTextBox"
  79. Style="{x:Null}"
  80. Template="{StaticResource ComboBoxTextBox}"
  81. HorizontalAlignment="Left"
  82. VerticalAlignment="Center"
  83. Margin="5,3,23,3"
  84. Focusable="True"
  85. Background="Transparent"
  86. Visibility="Hidden"
  87. IsReadOnly="{TemplateBinding IsReadOnly}"/>
  88. <Popup
  89. Name="Popup"
  90. Placement="Bottom"
  91. IsOpen="{TemplateBinding IsDropDownOpen}"
  92. AllowsTransparency="True"
  93. Focusable="False"
  94. PopupAnimation="Slide">
  95. <Grid
  96. Name="DropDown"
  97. SnapsToDevicePixels="True"
  98. MinWidth="{TemplateBinding ActualWidth}"
  99. MaxHeight="{TemplateBinding MaxDropDownHeight}" >
  100. <Border
  101. x:Name="DropDownBorder"
  102. Background="#EFEFEF"
  103. BorderThickness="1 1 1 1"
  104. CornerRadius=""
  105. BorderBrush="Gray"/>
  106. <ScrollViewer Margin="5,6,4,6" SnapsToDevicePixels="True">
  107. <StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
  108. </ScrollViewer>
  109. </Grid>
  110. </Popup>
  111. </Grid>
  112. <ControlTemplate.Triggers>
  113. <Trigger Property="HasItems" Value="false">
  114. <Setter TargetName="DropDownBorder" Property="MinHeight" Value=""/>
  115. </Trigger>
  116. <Trigger Property="IsEnabled" Value="false">
  117. <Setter Property="Foreground" Value="#888888"/>
  118. </Trigger>
  119. <Trigger Property="IsGrouping" Value="true">
  120. <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
  121. </Trigger>
  122. <Trigger Property="IsEditable"
  123. Value="true">
  124. <Setter Property="IsTabStop" Value="false"/>
  125. <Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible"/>
  126. <Setter TargetName="ContentSite" Property="Visibility" Value="Hidden"/>
  127. </Trigger>
  128. </ControlTemplate.Triggers>
  129. </ControlTemplate>
  130. </Setter.Value>
  131. </Setter>
  132. <Style.Triggers>
  133. </Style.Triggers>
  134. </Style>
  135.  
  136. <Style x:Key="{x:Type ComboBoxItem}" TargetType="{x:Type ComboBoxItem}">
  137. <Setter Property="SnapsToDevicePixels" Value="true"/>
  138. <Setter Property="OverridesDefaultStyle" Value="true"/>
  139. <Setter Property="Template">
  140. <Setter.Value>
  141. <ControlTemplate TargetType="{x:Type ComboBoxItem}">
  142. <Border
  143. Name="Border"
  144. Padding=""
  145. BorderThickness=""
  146. SnapsToDevicePixels="true">
  147. <ContentPresenter />
  148. </Border>
  149. <ControlTemplate.Triggers>
  150. <!--<Trigger Property="IsHighlighted" Value="true">
  151. <Setter TargetName="Border" Property="Background" Value="Gray"/>
  152. </Trigger>-->
  153. <Trigger Property="IsMouseOver" Value="true">
  154. <Setter TargetName="Border" Property="Background" Value="#FCFCFC" />
  155. <Setter TargetName="Border" Property="BorderBrush" Value="#E5C365" />
  156. </Trigger>
  157. <Trigger Property="IsEnabled" Value="false">
  158. <Setter Property="Foreground" Value="#888888"/>
  159. </Trigger>
  160. </ControlTemplate.Triggers>
  161. </ControlTemplate>
  162. </Setter.Value>
  163. </Setter>
  164. </Style>
  165. </UserControl.Resources>

VS2013Xml文件节点导航插件开发的更多相关文章

  1. 2.6 XML配置:XML文件节点说明

    来源:http://blog.csdn.net/five3/article/details/25907693 TestNG的DTD检查文件:http://testng.org/testng-1.0.d ...

  2. Android学习笔记(二)Manifest文件节点详解

    在上一篇博文中简单介绍了Manifest文件及其存放位置,本篇就来详细介绍一下Manifest文件中的节点和一些节点的基本作用,首先看一下Manifest文件最基本的结构: <manifest ...

  3. linux设备驱动----利用mdev(udev)自动创建设备文件节点

    1.mdev的使用方法和原理: mdev是busybox 自带的一个简化版的udev,适合于嵌入式的应用埸合.其具有使用简单的特点.它的作用,就是在系统启动和热插拔或动态加载驱动程序时,自动产生驱动程 ...

  4. 根据XPATH去查看修改xml文件节点的内容

    首先给出xml文件解析的路径,然后去读取节点的内容. package com.inetpsa.eqc.threads; import java.util.List; import java.io.Fi ...

  5. 使用cat读取和echo写内核文件节点的一些问题

    span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }.CodeMirror ...

  6. linux下自动创建设备文件节点---class

    在驱动模块初始化函数中实现设备节点的自动创建 我们在刚开始写Linux设备驱动程序的时候,很多时候都是利用mknod命令手动创建设备节点,实际上Linux内核为我们提供了一组函数,可以用来在模块加载的 ...

  7. 如何在Sublime中打开左侧文件夹导航

    Sublime中我们可以通过菜单栏的View->Side Bar->Hide Side Bar(Show Side Bar)来显示和隐藏左侧的导航栏,如下图所示. 但是,这里只会显示当前打 ...

  8. linux 下文件节点索引

    最近发现一个奇怪的问题,就是一个pyhton 后台的服务一直打印日志文件,在中间我用vim看日志文件,关闭时习惯性的:wq退出,在此之后日志文件就不输出了. 1 对于这个现象我开始认为是python ...

  9. [maven] settings 文件节点配置详解

    基本结构 <settings xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3. ...

随机推荐

  1. 【dp】codeforces C. Vladik and Memorable Trip

    http://codeforces.com/contest/811/problem/C [题意] 给定一个自然数序列,在这个序列中找出几个不相交段,使得每个段的异或值之和相加最大. 段的异或值这样定义 ...

  2. docker容器的导入导出

    导出容器docker export 导出容器快照到本地文件$ sudo docker ps -aCONTAINER ID        IMAGE               COMMAND      ...

  3. 蓝桥杯 算法提高 金属采集 [ 树形dp 经典 ]

    传送门 算法提高 金属采集 时间限制:1.0s   内存限制:256.0MB     锦囊1   锦囊2   锦囊3   问题描述 人类在火星上发现了一种新的金属!这些金属分布在一些奇怪的地方,不妨叫 ...

  4. Windows Server 2003的一些优化设置 (转至网络)

    2003序列号:JCHKR-888KX-27HVK-DT88X-T767M1.禁用配置服务器向导: 禁止“配置你的服务器”(Manage Your Server)向导的出现:在控制面板(Control ...

  5. python学习之-- 事件驱动模型

    目前主流的网络驱动模型:事件驱动模型 事件驱动模型:也属于生产者/消费者结构,通过一个队列,保存生产者触发的事件,队列另一头是一个循环从队列里不断的提取事件.大致流程如下:1:首先生成一个事件消息队列 ...

  6. hdu - 5074 Hatsune Miku (简单dp)

    有m种不同的句子要组成一首n个句子的歌,每首歌都有一个美丽值,美丽值是由相邻的句子种类决定的,给出m*m的矩阵map[i][j]表示第i种句子和第j种句子的最大得分,一首歌的美丽值是由sum(map[ ...

  7. 洛谷——P1551 亲戚

    题目背景 若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系. 题目描述 规定:x和y是亲戚,y和z是亲戚,那么x和z也是亲戚.如 ...

  8. POJ 2240 【这题貌似可以直接FLOYD 屌丝用SPFA通过枚举找正权值环 顺便学了下map】

    题意: 给了n种硬币的名称,给了m种硬币间的转换关系. 从任意兑换地点开始兑换,看是否能够通过兑换的方式增加金钱. 思路: 用SPFA不断对各个点进行松弛操作,寻找正权值的环.如果找到则输出Yes. ...

  9. 关键字检索高亮标出-javasript/jQuery代码实现

    原文:http://www.open-open.com/code/view/1454504432089 此方法传入2个参数,一个是被检索内容所在的表单或者HTML元素的ID,另一为关键字,多个关键字的 ...

  10. 使用nginx代理weblogic负载方案

    之前一直用apache来做weblogic的前端,由于nginx对静态内容的出色性能,不得不转投nginx.这里就不 再写weblogic的安装了. 安装nginx nginx需要pcre做支持,一般 ...