天天看點

實作Visual Studio 2010一個很簡單的很酷的擴充

基本介紹篇

    在實作這個擴充之前,讓我們先弄清楚這個擴充實作什麼功能。這個擴充實際上是在你的VS視窗的右上角建立了一個資訊框代碼。該資訊框顯示您的源代碼的統計資訊。這些資訊包括:

    1、檔案的代碼行數

    2、檔案的字元數

    3、命名空間的個數

    4、字段個數

    5、接口個數

    6、類的個數

    7、函數個數

    8、屬性個數

    9、注釋的數量

   10、統計檔案的大小(Bytes, KB, MB等)。

實作Visual Studio 2010一個很簡單的很酷的擴充

    當您鍵入您的代碼,你會看到資訊視窗中的資料會即時更新。

    這個資訊視窗,是利用可擴充面闆。你可以把它看成兩個部分,每一個部分都可以根據您的需要展開和折疊。這樣,當你不需要它時,你将它可以折疊起來,需要的時候,将它展開。下面示範如何展開/折疊這個控件。

實作Visual Studio 2010一個很簡單的很酷的擴充

    這個控件有三個特殊的狀态。第一個狀态是一個很小的擴充按鈕。如上圖的第一部分。隻需點選它,就會打開控件右側的面闆,這個面闆顯示檔案的基本資料,如上圖的第二部分。這個控件還有一個可擴充面闆,如果點選擴充,就會看到下面的面闆,其中顯示其他的統計資料,如上圖的第三部分。

實作篇:

    需要軟體:

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

實作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。看下面的代碼(我删除不必要的元素,使其更簡單):

實作Visual Studio 2010一個很簡單的很酷的擴充

 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>

實作Visual Studio 2010一個很簡單的很酷的擴充

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

    現在,如果你看一下背景代碼,發現它也一樣簡單。其實我已經建立了一個CodeInfoTracker類,用它來為我們分析源代碼檔案。我隻是為我們的使用者控件添加了一個構造函數,使使用者控件更具擴充性而已。

實作Visual Studio 2010一個很簡單的很酷的擴充

 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   }

實作Visual Studio 2010一個很簡單的很酷的擴充

    使用了一個結構體Calculators ,這個結構體放置在我們的自定義類中,它有幾個int屬性用來儲存分析源檔案擷取的所有資訊。 <code>info.PerFormCalculate();</code> 給出分析的結果。這裡使用的所有擷取的資訊來更新了UIElements。

第三步:建立擷取源檔案資訊的類

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

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

實作Visual Studio 2010一個很簡單的很酷的擴充

 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 }

實作Visual Studio 2010一個很簡單的很酷的擴充

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

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

第四步:建立 Adornment Factory 類

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

實作Visual Studio 2010一個很簡單的很酷的擴充

 1 [Export(typeof(IWpfTextViewCreationListener))]

 2 [ContentType("text")]

 3 [TextViewRole(PredefinedTextViewRoles.Document)] 

 4 internal sealed class InfoBoxAdornmentFactory : IWpfTextViewCreationListener

 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  } 

實作Visual Studio 2010一個很簡單的很酷的擴充

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

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

第五步:建立Adornment 類

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

實作Visual Studio 2010一個很簡單的很酷的擴充

 1 public AlwaysVisibleInfoBox(IWpfTextView view)

 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 }

實作Visual Studio 2010一個很簡單的很酷的擴充

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

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

安裝和解除安裝這個擴充:

    安裝和解除安裝這個擴充是非常容易的。當您編譯項目後,它會産生一個VSIX檔案。您可以隻需輕按兩下這個檔案,它會自動安裝到Visual Studio。

實作Visual Studio 2010一個很簡單的很酷的擴充

    要解除安裝的檔案,您打開Visual Studio,轉到 Tools - &gt; Extension Manager,然後選擇解除安裝該擴充。

釋出您的擴充:

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

本文轉自麒麟部落格園部落格,原文連結:http://www.cnblogs.com/zhuqil/archive/2010/04/15/Visual-Studio-Extension.html,如需轉載請自行聯系原作者