VS2013Xml文件节点导航插件开发
一、功能描述
该插件的功能跟代码文件的导航功能类似,只是下拉框里的内容是元素的某一属性值,如图-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下拉控件,当下拉框的选项改变的时候触发定位操作。由于我们是在用户控件里添加下拉控件,在用户控件外部无法监控到下拉框的改变事件,所以我们需要在用户控件里添加一个事件,在下拉框改变事件里触发该事件,这样就可以间接订阅下拉框的选项改变事件。此外,还需要对外开放一个改变下拉框宽度的函数,用于编辑区大小改变的时候可以修改下拉框的宽度。具体的代码如下所示:
- /// <summary>
- /// MappingInfo.xaml 的交互逻辑
- /// </summary>
- public partial class MappingInfo : UserControl
- {
- public delegate void DelegateSelectionChanged(object sender, SelectionChangedEventArgs e);
- public event DelegateSelectionChanged SelectionChanged;
- public MappingInfo()
- {
- InitializeComponent();
- }
- public MappingInfo(IEnumerable<XElement> elements)
{- InitializeComponent();
- List<Elements> list = new List<Elements>();
- foreach (var item in elements)
- {
- if (item.Attribute("name") == null)
- continue;
- Elements model = new Elements();
- model.Value = item.Attribute("name").Value;
- string desc = item.Attribute("title") != null ? item.Attribute("title").Value : item.Attribute("remark") == null ? "" : item.Attribute("remark").Value;
- string cache = item.Attribute("cache") != null ? item.Attribute("cache").Value : "";
- model.Text = desc != "" ? string.Format("{0}({1})", model.Value, desc) : model.Value;
- if (cache != "" && cache.Equals("true", StringComparison.OrdinalIgnoreCase))
- {
- model.Text += " √";
- }
- list.Add(model);
- }
- cbElement.DisplayMemberPath = "Text";
- cbElement.SelectedValuePath = "Value";
- cbElement.ItemsSource = list;
- cbElement.SelectedIndex = ;
- //订阅选项改变时的事件
- cbElement.SelectionChanged += cbElement_SelectionChanged;
- }
- void cbElement_SelectionChanged(object sender, SelectionChangedEventArgs e)
- {
- SelectionChanged(sender, e);
- }
- public void SetComboBoxWidth(double width)
{- this.cbElement.Width = width;
- }
- }
- class Elements
- {
- public string Text { get; set; }
- public string Value { get; set; }
- }
在EditorMargin1类的构造函数里将自定义的wpf用户控件添加到插件创建的控件里
- //设置导航栏的相关信息
- this.Height = ;
- this.ClipToBounds = false;
- this.Background = new SolidColorBrush(Colors.WhiteSmoke);
- this.Children.Add(mapInfo);
- //导航栏大小改变时改变下拉框的宽度
- this.SizeChanged += Navigate_SizeChanged;
四、使用户控件自适应编辑区宽度
要实现自适应的功能只需要在XmlFileNavigation类的构造函数里订阅SizeChanged事件,由于EditorMargin1类继承了Canvas类,而Canvas类又从其他类继承了SizeChanged事件,所以只要通过this.SizeChanged就可以订阅该事件,在事件里调用创建的用户控件对外开发的修改宽度函数即可。代码如下所示:
- /// <summary>
- /// 大小改变时下拉框也一起调整
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- void Navigate_SizeChanged(object sender, SizeChangedEventArgs e)
- {
- //调整下拉框大小
- //mapinfo为添加的wpf用户控件
- mapInfo.SetComboBoxWidth(((EditorMargin1)sender).ActualWidth); }
为什么要在SizeChanged事件里设置下拉框的宽度,在EditorMargin1类的构造函数里设置就不行吗?因为在构造函数里获取编辑区宽度的话,第一个页面获取的宽度是不准确的,获取的宽度都是800,之后打开的页面的宽度才是正常的。有兴趣的同学可以在EditorMargin1类的构造函数里添加如下的代码,获取文档的宽度验证一下
- EnvDTE.DTE dte=ServiceProvider.GlobalProvider.GetService(typeof(DTE)) as DTE;
- double width = dte.ActiveDocument.ActiveWindow.Width;
五、根据选中的内容进行定位
由于该插件是针对xml文件的,而VS没有提供对xml文件内容的定位方法(可能是我还不知道),所以只能通过遍历整个文件来确定选中的内容是在文件中的行数。以下是在用户控件的响应事件里对选中的内容进行定位的代码:
- /// <summary>
- /// 下拉框改变事件
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- void cb_SelectionChanged(object sender, SelectionChangedEventArgs e)
- {
- try
- {
- //获取下拉框选中项
Elements model = (Elements)((ComboBox)sender).SelectedItem;- //获取DTE实例
- DTE dte = ServiceProvider.GlobalProvider.GetService(typeof(DTE)) as DTE;
- //找出选中项在xml文件里的行数
- string[] lines = File.ReadAllLines(dte.ActiveDocument.FullName);
- int line = ;
- foreach (var item in lines)
- {
- line++;
- if (item != "" && item.Contains(model.Value))
- {
- break;
- }
- }
- //滚动条滚动到指定行数并显示光标
- TextSelection selection = dte.ActiveDocument.Selection as TextSelection;
- if (selection != null)
- {
- selection.MoveToLineAndOffset(line, );
- selection.ActivePoint.TryToShow();
- }
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message, "提示", MessageBoxButton.OK, MessageBoxImage.Error);
- }
- }
如果要开发的导航插件式针对cs文件的话可以通过下面的代码获取cs文件里的字段、函数、事件、属性等的相关信息:
- dte.ActiveDocument.ProjectItem.FileCodeModel
以下的代码是针对ComboBox的美化样式
- <UserControl.Resources>
- <ControlTemplate x:Key="ComboBoxToggleButton" TargetType="{x:Type ToggleButton}">
- <Grid>
- <Grid.ColumnDefinitions>
- <ColumnDefinition />
- <ColumnDefinition Width="" />
- </Grid.ColumnDefinitions>
- <Border
- x:Name="Border"
- Grid.ColumnSpan=""
- CornerRadius=""
- Background="#FCFCFC"
- BorderBrush="#9BA7B7"
- BorderThickness="1 1 1 1" />
- <Border
- Grid.Column=""
- CornerRadius=""
- Margin=""
- Background="#FCFCFC"
- BorderBrush="#9BA7B7"
- BorderThickness="" />
- <Path
- x:Name="Arrow"
- Grid.Column=""
- Fill="Black"
- HorizontalAlignment="Center"
- VerticalAlignment="Center"
- Data="M 0 0 L 4 4 L 8 0 Z"/>
- </Grid>
- <ControlTemplate.Triggers>
- <Trigger Property="ToggleButton.IsMouseOver" Value="true">
- <Setter TargetName="Border" Property="Background" Value="#FDF4BF" />
- <Setter TargetName="Border" Property="BorderBrush" Value="#FFEC8B" />
- </Trigger>
- <Trigger Property="ToggleButton.IsChecked" Value="true">
- <Setter TargetName="Border" Property="Background" Value="#FFEC8B" />
- </Trigger>
- <Trigger Property="IsEnabled" Value="False">
- <Setter TargetName="Border" Property="Background" Value="#EEEEEE" />
- <Setter TargetName="Border" Property="BorderBrush" Value="#AAAAAA" />
- <Setter Property="Foreground" Value="#888888"/>
- <Setter TargetName="Arrow" Property="Fill" Value="#888888" />
- </Trigger>
- </ControlTemplate.Triggers>
- </ControlTemplate>
- <ControlTemplate x:Key="ComboBoxTextBox" TargetType="{x:Type TextBox}">
- <Border x:Name="PART_ContentHost" Focusable="False" Background="{TemplateBinding Background}" />
- </ControlTemplate>
- <Style x:Key="{x:Type ComboBox}" TargetType="{x:Type ComboBox}">
- <Setter Property="SnapsToDevicePixels" Value="true"/>
- <Setter Property="OverridesDefaultStyle" Value="true"/>
- <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
- <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
- <Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
- <Setter Property="Template">
- <Setter.Value>
- <ControlTemplate TargetType="{x:Type ComboBox}">
- <Grid>
- <ToggleButton
- Name="ToggleButton"
- Template="{StaticResource ComboBoxToggleButton}"
- Grid.Column=""
- Focusable="false"
- IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
- ClickMode="Press">
- </ToggleButton>
- <ContentPresenter
- Name="ContentSite"
- IsHitTestVisible="False"
- Content="{TemplateBinding SelectionBoxItem}"
- ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
- ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
- Margin="5,3,23,3"
- VerticalAlignment="Center"
- HorizontalAlignment="Left" />
- <TextBox x:Name="PART_EditableTextBox"
- Style="{x:Null}"
- Template="{StaticResource ComboBoxTextBox}"
- HorizontalAlignment="Left"
- VerticalAlignment="Center"
- Margin="5,3,23,3"
- Focusable="True"
- Background="Transparent"
- Visibility="Hidden"
- IsReadOnly="{TemplateBinding IsReadOnly}"/>
- <Popup
- Name="Popup"
- Placement="Bottom"
- IsOpen="{TemplateBinding IsDropDownOpen}"
- AllowsTransparency="True"
- Focusable="False"
- PopupAnimation="Slide">
- <Grid
- Name="DropDown"
- SnapsToDevicePixels="True"
- MinWidth="{TemplateBinding ActualWidth}"
- MaxHeight="{TemplateBinding MaxDropDownHeight}" >
- <Border
- x:Name="DropDownBorder"
- Background="#EFEFEF"
- BorderThickness="1 1 1 1"
- CornerRadius=""
- BorderBrush="Gray"/>
- <ScrollViewer Margin="5,6,4,6" SnapsToDevicePixels="True">
- <StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
- </ScrollViewer>
- </Grid>
- </Popup>
- </Grid>
- <ControlTemplate.Triggers>
- <Trigger Property="HasItems" Value="false">
- <Setter TargetName="DropDownBorder" Property="MinHeight" Value=""/>
- </Trigger>
- <Trigger Property="IsEnabled" Value="false">
- <Setter Property="Foreground" Value="#888888"/>
- </Trigger>
- <Trigger Property="IsGrouping" Value="true">
- <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
- </Trigger>
- <Trigger Property="IsEditable"
- Value="true">
- <Setter Property="IsTabStop" Value="false"/>
- <Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible"/>
- <Setter TargetName="ContentSite" Property="Visibility" Value="Hidden"/>
- </Trigger>
- </ControlTemplate.Triggers>
- </ControlTemplate>
- </Setter.Value>
- </Setter>
- <Style.Triggers>
- </Style.Triggers>
- </Style>
- <Style x:Key="{x:Type ComboBoxItem}" TargetType="{x:Type ComboBoxItem}">
- <Setter Property="SnapsToDevicePixels" Value="true"/>
- <Setter Property="OverridesDefaultStyle" Value="true"/>
- <Setter Property="Template">
- <Setter.Value>
- <ControlTemplate TargetType="{x:Type ComboBoxItem}">
- <Border
- Name="Border"
- Padding=""
- BorderThickness=""
- SnapsToDevicePixels="true">
- <ContentPresenter />
- </Border>
- <ControlTemplate.Triggers>
- <!--<Trigger Property="IsHighlighted" Value="true">
- <Setter TargetName="Border" Property="Background" Value="Gray"/>
- </Trigger>-->
- <Trigger Property="IsMouseOver" Value="true">
- <Setter TargetName="Border" Property="Background" Value="#FCFCFC" />
- <Setter TargetName="Border" Property="BorderBrush" Value="#E5C365" />
- </Trigger>
- <Trigger Property="IsEnabled" Value="false">
- <Setter Property="Foreground" Value="#888888"/>
- </Trigger>
- </ControlTemplate.Triggers>
- </ControlTemplate>
- </Setter.Value>
- </Setter>
- </Style>
- </UserControl.Resources>
VS2013Xml文件节点导航插件开发的更多相关文章
- 2.6 XML配置:XML文件节点说明
来源:http://blog.csdn.net/five3/article/details/25907693 TestNG的DTD检查文件:http://testng.org/testng-1.0.d ...
- Android学习笔记(二)Manifest文件节点详解
在上一篇博文中简单介绍了Manifest文件及其存放位置,本篇就来详细介绍一下Manifest文件中的节点和一些节点的基本作用,首先看一下Manifest文件最基本的结构: <manifest ...
- linux设备驱动----利用mdev(udev)自动创建设备文件节点
1.mdev的使用方法和原理: mdev是busybox 自带的一个简化版的udev,适合于嵌入式的应用埸合.其具有使用简单的特点.它的作用,就是在系统启动和热插拔或动态加载驱动程序时,自动产生驱动程 ...
- 根据XPATH去查看修改xml文件节点的内容
首先给出xml文件解析的路径,然后去读取节点的内容. package com.inetpsa.eqc.threads; import java.util.List; import java.io.Fi ...
- 使用cat读取和echo写内核文件节点的一些问题
span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }.CodeMirror ...
- linux下自动创建设备文件节点---class
在驱动模块初始化函数中实现设备节点的自动创建 我们在刚开始写Linux设备驱动程序的时候,很多时候都是利用mknod命令手动创建设备节点,实际上Linux内核为我们提供了一组函数,可以用来在模块加载的 ...
- 如何在Sublime中打开左侧文件夹导航
Sublime中我们可以通过菜单栏的View->Side Bar->Hide Side Bar(Show Side Bar)来显示和隐藏左侧的导航栏,如下图所示. 但是,这里只会显示当前打 ...
- linux 下文件节点索引
最近发现一个奇怪的问题,就是一个pyhton 后台的服务一直打印日志文件,在中间我用vim看日志文件,关闭时习惯性的:wq退出,在此之后日志文件就不输出了. 1 对于这个现象我开始认为是python ...
- [maven] settings 文件节点配置详解
基本结构 <settings xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3. ...
随机推荐
- 【dp】codeforces C. Vladik and Memorable Trip
http://codeforces.com/contest/811/problem/C [题意] 给定一个自然数序列,在这个序列中找出几个不相交段,使得每个段的异或值之和相加最大. 段的异或值这样定义 ...
- docker容器的导入导出
导出容器docker export 导出容器快照到本地文件$ sudo docker ps -aCONTAINER ID IMAGE COMMAND ...
- 蓝桥杯 算法提高 金属采集 [ 树形dp 经典 ]
传送门 算法提高 金属采集 时间限制:1.0s 内存限制:256.0MB 锦囊1 锦囊2 锦囊3 问题描述 人类在火星上发现了一种新的金属!这些金属分布在一些奇怪的地方,不妨叫 ...
- Windows Server 2003的一些优化设置 (转至网络)
2003序列号:JCHKR-888KX-27HVK-DT88X-T767M1.禁用配置服务器向导: 禁止“配置你的服务器”(Manage Your Server)向导的出现:在控制面板(Control ...
- python学习之-- 事件驱动模型
目前主流的网络驱动模型:事件驱动模型 事件驱动模型:也属于生产者/消费者结构,通过一个队列,保存生产者触发的事件,队列另一头是一个循环从队列里不断的提取事件.大致流程如下:1:首先生成一个事件消息队列 ...
- hdu - 5074 Hatsune Miku (简单dp)
有m种不同的句子要组成一首n个句子的歌,每首歌都有一个美丽值,美丽值是由相邻的句子种类决定的,给出m*m的矩阵map[i][j]表示第i种句子和第j种句子的最大得分,一首歌的美丽值是由sum(map[ ...
- 洛谷——P1551 亲戚
题目背景 若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系. 题目描述 规定:x和y是亲戚,y和z是亲戚,那么x和z也是亲戚.如 ...
- POJ 2240 【这题貌似可以直接FLOYD 屌丝用SPFA通过枚举找正权值环 顺便学了下map】
题意: 给了n种硬币的名称,给了m种硬币间的转换关系. 从任意兑换地点开始兑换,看是否能够通过兑换的方式增加金钱. 思路: 用SPFA不断对各个点进行松弛操作,寻找正权值的环.如果找到则输出Yes. ...
- 关键字检索高亮标出-javasript/jQuery代码实现
原文:http://www.open-open.com/code/view/1454504432089 此方法传入2个参数,一个是被检索内容所在的表单或者HTML元素的ID,另一为关键字,多个关键字的 ...
- 使用nginx代理weblogic负载方案
之前一直用apache来做weblogic的前端,由于nginx对静态内容的出色性能,不得不转投nginx.这里就不 再写weblogic的安装了. 安装nginx nginx需要pcre做支持,一般 ...