首页 > 学院 > 开发设计 > 正文

VS2013Xml文件节点导航插件开发

2019-11-17 02:45:20
字体:
来源:转载
供稿:网友

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 = 0;    //订阅选项改变时的事件    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 = 25;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 = 0;    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, 3);      selection.ActivePoint.TryToShow();    }  }  catch (Exception ex)  {    MessageBox.Show(ex.Message, "提示", MessageBoxButton.OK, MessageBoxImage.Error);  }}

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

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="15" />  7                 </Grid.ColumnDefinitions>  8                 <Border  9   x:Name="Border"  10   Grid.ColumnSpan="2" 11   CornerRadius="0" 12   Background="#FCFCFC" 13   BorderBrush="#9BA7B7" 14   BorderThickness="1 1 1 1" /> 15                 <Border  16   Grid.Column="0" 17   CornerRadius="0"  18   Margin="1"  19   Background="#FCFCFC"  20   BorderBrush="#9BA7B7" 21   BorderThickness="0" /> 22                 <Path  23   x:Name="Arrow" 24   Grid.Column="1"      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>
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表