• 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>
     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="2" 
     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="0"
    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="95"/>
    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="2"
    145                             BorderThickness="1"
    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>
    View Code
  • 相关阅读:
    nodejs创建路由
    node,js 使用express 生成站点的命令
    Ajax异步同步原理
    jquery问题总结
    JS正则表达式
    幻灯片缓冲效果
    转:offsetParent的理解
    微信小程序左右滑动切换页面示例代码--转载
    python正则表达式
    Django笔记(番外):虚拟环境
  • 原文地址:https://www.cnblogs.com/jiangjun0817/p/4105493.html
Copyright © 2020-2023  润新知