程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 實現Visual Studio 2010一個很簡單的很酷的擴展

實現Visual Studio 2010一個很簡單的很酷的擴展

編輯:關於.NET

基本介紹篇

在實現這個擴展之前,讓我們先弄清楚這個擴展實現什麼功能。這個擴展實際上是在你的VS窗口的右上角創建了一個信息框代碼。該信息框顯示您的源代碼的統計信息。這些信息包括:

1、文件的代碼行數

2、文件的字符數

3、命名空間的個數

4、字段個數

5、接口個數

6、類的個數

7、函數個數

8、屬性個數

9、注釋的數量

10、統計文件的大小(Bytes, KB, MB等)。

當您鍵入您的代碼,你會看到信息窗口中的數據會即時更新。

這個信息窗口,是利用可擴展面板。你可以把它看成兩個部分,每一個部分都可以根據您的需要展開和折疊。這樣,當你不需要它時,你將它可以折疊起來,需要的時候,將它展開。下面演示如何展開/折疊這個控件。

這個控件有三個特殊的狀態。第一個狀態是一個很小的擴展按鈕。如上圖的第一部分。只需點擊它,就會打開控件右側的面板,這個面板顯示文件的基本數據,如上圖的第二部分。這個控件還有一個可擴展面板,如果點擊擴展,就會看到下面的面板,其中顯示其他的統計數據,如上圖的第三部分。

實現篇:

需要軟件:

1、 Microsoft Visual Studio 2010

2、 Visual Studio 2010 SDK

你安裝 Visual Studio SDK之後,你的Visual Studio 2010中會多出下面這些模板:

這篇文章中,我們使用模板Editor ViewPort Adornment實現這個擴展,此模板將為你的代碼編輯器的帶來一個裝飾品。

其實這個擴展包一個WPF用戶控件,我把它放進VS的視窗中就成了信息框。它還含有兩個類,一個類用來解析代碼,獲取代碼的相關信息;另一個類用來處理自定義編輯器的事件和當頁以及加載的時候將WPF控件添加到頁面中。

第一步:創建一個Viewport Adornment項目

我們從Extensibility中選擇Viewport Adornment模板創建一個項目。這將生成一個SourceManifest文件和兩個類文件。一個是Adornment類本身,另外一個是AdornmentFactory類。

第二步:添加一個WPF用戶控件

右鍵單擊項目,選擇添加一個新的WPF用戶控件。為了簡單起見,我使用了一個用戶控件。這個用戶控件實際上包含一個Expander控件,設置它的 ExpandDirection = Left,它裡面又包含了一些TextBlock控件和另外一個Expander ,設置裡面的這個Expander的ExpandDirection = Down。看下面的代碼(我刪除不必要的元素,使其更簡單):

1   <Expander ExpandDirection="Left" Style="{DynamicResource ExpanderStyle1}"
2            x:Name="expMain" >
3   <StackPanel>
4                 <TextBlock x:Name="txtNoLines"
5                            Text="No of Lines : {0}"
6                            Margin="25 25 25 0"
7                            FontSize="12"
8                            FontFamily="Verdana"
9                            FontWeight="Bold"
10                            Foreground="Yellow"></TextBlock>
11                 <TextBlock x:Name="txtNoCharacters"
12                            Text="No of Characters : {0}"
13                            Margin="25 5 25 15"
14                            FontSize="12"
15                            FontFamily="Verdana"
16                            FontWeight="Bold"
17                            Foreground="Yellow"></TextBlock>
18                 <Expander x:Name="expCodeInfo" ExpandDirection="Down"
19                                      Header="Code Information">
20                     <StackPanel>
21                         <TextBlock x:Name="txtClassInfo"
22                                    Margin="25 25 25 0"
23                                    FontSize="12"
24                                    FontFamily="Verdana"
25                                    FontWeight="Bold"
26                                    Foreground="LightYellow"/>
27                         <Line
28                               Margin="0,4"
29                               SnapsToDevicePixels="True"
30                               Stroke="Gold"
31                               Stretch="Fill"
32                               X1="0" X2="1"
33                               />
34                         <TextBlock x:Name="txtFileSize"
35                                    Margin="25 5 25 15"
36                                    FontSize="12"
37                                    FontFamily="Verdana"
38                                    FontWeight="Bold"
39                                    Foreground="AliceBlue"/>
40                     </StackPanel>
41                 </Expander>
42             </StackPanel>
43          </Expander>

你可以看到,代碼很簡單,兩個Expanders,一個用來顯示基本的統計信息和另外一個顯示擴展的統計信息。我還使用StackPanel來固定TextBlocks布局。

現在,如果你看一下後台代碼,發現它也一樣簡單。其實我已經創建了一個CodeInfoTracker類,用它來為我們分析源代碼文件。我只是為我們的用戶控件添加了一個構造函數,使用戶控件更具擴展性而已。

1 private CodeInfoTracker _cinfo;
2 private CodeInfoTracker.Calculators _calculator;
3 public ucInfoBox(CodeInfoTracker cinfo)
4             : this()
5 {
6         this._cinfo = cinfo;
7 }
8  public void UpdateInfo(CodeInfoTracker info)
9  {
10             _calculator = info.PerFormCalculate();
11             this.txtNoLines.Text = string.Format("No of Lines : {0}",
12                                     _calculator.no_of_lines);
13             this.txtNoCharacters.Text = string.Format("No of Characters : {0}",
14                                                        _calculator.no_of_characters);
15             this.txtFileSize.Text = string.Format("Total File Size : {0}",
16                                                        _calculator.totalfilesize);
17
18             StringBuilder builder = new StringBuilder();
19             if (this._calculator.interfaces != 0)
20                 builder.AppendFormat("Interfaces : {0}\n\r",
21                                           this._calculator.interfaces);
22             if (this._calculator.namespaces != 0)
23                 builder.AppendFormat("NameSpaces : {0}\n\r",
24                                             this._calculator.namespaces);
25             if (this._calculator.classes != 0)
26                 builder.AppendFormat("Classes : {0}\n\r",
27                                             this._calculator.classes);
28             if (this._calculator.methods != 0)
29                 builder.AppendFormat("Methods : {0}\n\r", this._calculator.methods);
30             if (this._calculator.properties != 0)
31                 builder.AppendFormat("Properties : {0}\n\r",
32                                                this._calculator.properties);
33             if (this._calculator.fields != 0)
34                 builder.AppendFormat("Fields : {0}\n\r", this._calculator.fields);
35             if (this._calculator.comments != 0)
36                 builder.AppendFormat("Comments : {0}\n\r", this._calculator.comments);
37
38             if (builder.Length > 0)
39             {
40                 this.txtClassInfo.Visibility = System.Windows.Visibility.Visible;
41                 this.txtClassInfo.Text = builder.ToString();
42             }
43             else
44             {
45                 this.txtClassInfo.Text = "";
46                 this.txtClassInfo.Visibility = System.Windows.Visibility.Hidden;
47        }
48   }

使用了一個結構體Calculators ,這個結構體放置在我們的自定義類中,它有幾個int屬性用來保存分析源文件獲取的所有信息。 info.PerFormCalculate(); 給出分析的結果。這裡使用的所有獲取的信息來更新了UIElements。

第三步:創建獲取源文件信息的類

雖然代碼存在一些復雜性,但是這個類其實很簡單。我很感謝CS Parser [^],它幫助我自動地解析源代碼。

這個類需要一個IWpfTextView對象,它代表著Visual Studio文本編輯器。實際上WpfTextView實現了IWpfTextView。在執行期間這個類接受這個對象。我可以從WPFTextView.TextSnapshot.GetText()獲得到了源代碼。

在我調用的這個分析的時候,我只需要檢測的代碼是什麼語言寫的。開始我想自己來實現,但是感謝上帝,我在WPFTextView中發現已經存在這個對象了。

1 public enum Language
2 {
3         CSharp, VisualBasic, Indeterminate
4 }
5 internal Language DetectLanguage
6 {
7             get
8             {
9                 string langtype = 
10         this._view.FormattedLineSource.TextAndAdornmentSequencer.
11         SourceBuffer.ContentType.DisplayName;
12                 if(langtype.Equals("CSHARP",
13             StringComparison.InvariantCultureIgnoreCase))
14                     return Language.CSharp;
15                 else if(langtype.Equals("BASIC",
16                               StringComparison.InvariantCultureIgnoreCase))
17                     return Language.VisualBasic;
18                 else
19                     return Language.Indeterminate;
20             }
21 }

DetectLanguage妥善地利用WPFTextView對象的FormattedLineSource.TextAndAdornmentSequencer.

SourceBuffer.ContentType.DisplayName,這個屬性告訴我是使用了哪種語言。之後我創建了一個新的方法PerFormCalculate,用它來解析源代碼,它返回一個Calculation結構對象。

第四步:創建 Adornment Factory 類

回到這個擴展,我創建一個Adornment(InfoBoxAdornmentFactory)的Factory類。這個類繼承IWpfTextViewCreationListener,用來監聽WPF的編輯和創建事件。

1 [Export(typeof(IWpfTextViewCreationListener))]
2 [ContentType("text")]
3 [TextViewRole(PredefinedTextViewRoles.Document)] 
4 internal sealed class InfoBoxAdornmentFactory : IWpfTextViewCreationListener
5 {
6         [Export(typeof(AdornmentLayerDefinition))]
7         [Name("AlwaysVisibleInfoBox")]
8         [Order(After = PredefinedAdornmentLayers.Selection)]
9         [TextViewRole(PredefinedTextViewRoles.Interactive)]
10         public AdornmentLayerDefinition editorAdornmentLayer = null;
11         public void TextViewCreated(IWpfTextView textView)
12         {
13             new AlwaysVisibleInfoBox(textView);
14         }
15  } 

這裡,你可以看到我在這個類上使用了很多Attributes,像ContentType,它定義了我們只處理文本格式的編輯器;還有TextViewRole,它定義了將被這個類處理的textview的類型。

在這個類中,我創建了一個AdornmentLayerDefination對象。可能你想知道我們沒有使用它,無什麼還需要定義它呢,它只是用來配置屬性的。Order屬性指定,當,InfoBox在層被選之後監聽,Name是編輯擴展的名字。

第五步:創建Adornment 類

Adornment類實際創建了一個WPF用戶控件對象,並設置它的視圖畫布。在內部構造函數中,我處理 IWpfTextView.LayoutChanged事件,當代碼修改或者布局改變的時候,就觸發這個事件。因此,通過這一事件,當我們編輯的文檔時,我們可以很容易地得到回調。當浏覽器編輯器的大小改變時,我還通過處理 WPFTextView.ViewportHeightChanged,WPFTextView.ViewportWidthChanged得到回調,使我們可以重新定位相應的UserControl。

1 public AlwaysVisibleInfoBox(IWpfTextView view)
2 {
3           _view.LayoutChanged += this.OnLayoutChanged;
4           this.GetLayer();
5 }
6 private void GetLayer()
7  {
8             _adornmentLayer = this._view.GetAdornmentLayer("AlwaysVisibleInfoBox");
9             _view.ViewportHeightChanged += delegate { this.onSizeChange(); };
10             _view.ViewportWidthChanged += delegate { this.onSizeChange(); };
11 }
12  private void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
13 {
14             this._info = new CodeInfoTracker(_view);
15             this.infobox.UpdateInfo(this._info);
16  }
17  public void onSizeChange()
18  {
19
20             _adornmentLayer.RemoveAllAdornments();
21             Canvas.SetLeft(infobox, _view.ViewportRight - 255);
22             Canvas.SetTop(infobox, _view.ViewportTop + 10);
23             
24           _adornmentLayer.AddAdornment(AdornmentPositioningBehavior.ViewportRelative,
25           null, null,
26           infobox, null);
27 }

因此,構造函數只是調用GetLayer來獲取的Layer對象,發生在ViewportHeightChanged和ViewportWidthChanged ViewPortSizeChage事件。當一個布局改變時,我就能更新這個用戶的控件。

至此,我們成功地建立我們的擴展。你可以使用F5運行它,它會打開一個Visual Studio的Experimental實例。

安裝和卸載這個擴展:

安裝和卸載這個擴展是非常容易的。當您編譯項目後,它會產生一個VSIX文件。您可以只需雙擊這個文件,它會自動安裝到Visual Studio。

要卸載的文件,您打開Visual Studio,轉到 Tools - > Extension Manager,然後選擇卸載該擴展。

發布您的擴展:

發布你的擴展到Visual Studio庫的方式也非常的酷。只要你需要上傳VSIX文件到http://www.visualstudiogallery.com/。我已經上載我的這個擴展。

總結:這篇文章,從頭到尾一步一步教你實現一個很簡單很酷的VS2010的擴展

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved