Cara menggunakan B-0101 pada JavaScript

Lompati ke konten utama

Browser ini sudah tidak didukung.

Mutakhirkan ke Microsoft Edge untuk memanfaatkan fitur, pembaruan keamanan, dan dukungan teknis terkini.

Panduan: Membuat hiasan tampilan, perintah, dan pengaturan (panduan kolom)

  • Artikel
  • 09/27/2022
  • 32 menit untuk membaca

Dalam artikel ini

Berlaku untuk:

Cara menggunakan B-0101 pada JavaScript
Visual Studio
Cara menggunakan B-0101 pada JavaScript
Visual Studio untuk Mac
Cara menggunakan B-0101 pada JavaScript
Visual Studio Code

Anda dapat memperluas editor teks/kode Visual Studio dengan perintah dan melihat efek. Artikel ini memperlihatkan kepada Anda cara memulai fitur ekstensi populer, panduan kolom. Panduan kolom adalah garis terang visual yang digambar pada tampilan editor teks untuk membantu Anda mengelola kode ke lebar kolom tertentu. Secara khusus, kode yang diformat bisa penting untuk sampel yang Anda sertakan dalam dokumen, posting blog, atau laporan bug.

Dalam panduan ini, Anda:

  • Membuat proyek VSIX

  • Menambahkan hiasan tampilan editor

  • Menambahkan dukungan untuk menyimpan dan mendapatkan pengaturan (tempat menggambar panduan kolom dan warnanya)

  • Tambahkan perintah (tambahkan/hapus panduan kolom, ubah warnanya)

  • Tempatkan perintah pada menu Edit dan menu konteks dokumen teks

  • Menambahkan dukungan untuk memanggil perintah dari Jendela Perintah Visual Studio

    Anda dapat mencoba versi fitur panduan kolom denganekstensi Visual Studio Gallery ini.

    Catatan

    Dalam panduan ini, Anda menempelkan sejumlah besar kode ke dalam beberapa file yang dihasilkan oleh templat ekstensi Visual Studio. Tetapi, segera panduan ini akan merujuk ke solusi lengkap di GitHub dengan contoh ekstensi lainnya. Kode yang diselesaikan sedikit berbeda karena memiliki ikon perintah nyata alih-alih menggunakan ikon generiktemplate.

Mulai

Mulai dari Visual Studio 2015, Anda tidak menginstal Visual Studio SDK dari pusat unduhan. Ini disertakan sebagai fitur opsional dalam penyiapan Visual Studio. Anda juga dapat menginstal VS SDK nanti. Untuk informasi selengkapnya, lihat Menginstal Visual Studio SDK.

Menyiapkan solusi

Pertama, Anda membuat proyek VSIX, menambahkan hiasan tampilan editor, lalu menambahkan perintah (yang menambahkan VSPackage untuk memiliki perintah). Arsitektur dasarnya adalah sebagai berikut:

  • Anda memiliki pendengar pembuatan tampilan teks yang membuat ColumnGuideAdornment objek per tampilan. Objek ini mendengarkan peristiwa tentang perubahan tampilan atau pengaturan yang mengubah, memperbarui, atau menggambar ulang panduan kolom seperlunya.

  • Ada GuidesSettingsManager yang menangani pembacaan dan penulisan dari penyimpanan pengaturan Visual Studio. Manajer pengaturan juga memiliki operasi untuk memperbarui pengaturan yang mendukung perintah pengguna (tambahkan kolom, hapus kolom, ubah warna).

  • Ada paket VSIP yang diperlukan jika Anda memiliki perintah pengguna, tetapi hanya kode boilerplate yang menginisialisasi objek implementasi perintah.

  • Ada ColumnGuideCommands objek yang menjalankan perintah pengguna dan menghubungkan handler perintah untuk perintah yang dideklarasikan dalam file .vsct .

    VSIX. Gunakan | File Baru... perintah untuk membuat proyek. Pilih simpul Ekstensibilitas di bawah C# di panel navigasi kiri dan pilih Proyek VSIX di panel kanan. Masukkan nama ColumnGuides dan pilih OK untuk membuat proyek.

    Lihat hiasan. Tekan tombol penunjuk kanan pada simpul proyek di Penjelajah Solusi. Pilih tambahkan | Item Baru ... perintah untuk menambahkan item hiasan tampilan baru. Pilih | Ekstensibilitas Editor di panel navigasi kiri dan pilih Hiasan Tampilan Editor di panel kanan. Masukkan nama ColumnGuideAdornment sebagai nama item dan pilih Tambahkan untuk menambahkannya.

    Anda dapat melihat templat item ini menambahkan dua file ke proyek (serta referensi, dan sebagainya): ColumnGuideAdornment.cs dan ColumnGuideAdornmentTextViewCreationListener.cs. Templat menggambar persegi panjang ungu pada tampilan. Di bagian berikut, Anda mengubah beberapa baris dalam pendengar pembuatan tampilan dan mengganti konten ColumnGuideAdornment.cs.

    Perintah. Di Penjelajah Solusi, tekan tombol penunjuk kanan pada simpul proyek. Pilih tambahkan | Item Baru ... perintah untuk menambahkan item hiasan tampilan baru. Pilih | Ekstensibilitas VSPackage di panel navigasi kiri dan pilih Perintah Kustom di panel kanan. Masukkan nama ColumnGuideCommands sebagai nama item dan pilih Tambahkan. Selain beberapa referensi, menambahkan perintah dan paket juga menambahkan ColumnGuideCommands.cs, ColumnGuideCommandsPackage.cs, dan ColumnGuideCommandsPackage.vsct. Di bagian berikut, Anda mengganti konten file pertama dan terakhir untuk menentukan dan mengimplementasikan perintah.

Menyiapkan pendengar pembuatan tampilan teks

Buka ColumnGuideAdornmentTextViewCreationListener.cs di editor. Kode ini mengimplementasikan handler untuk setiap kali Visual Studio membuat tampilan teks. Ada atribut yang mengontrol kapan handler dipanggil tergantung pada karakteristik tampilan.

Kode juga harus mendeklarasikan lapisan hiasan. Ketika editor memperbarui tampilan, editor mendapatkan lapisan hiasan untuk tampilan dan dari yang mendapatkan elemen hiasan. Anda dapat mendeklarasikan pengurutan lapisan Anda relatif terhadap orang lain dengan atribut. Ganti baris berikut:

[Order(After = PredefinedAdornmentLayers.Caret)]

dengan dua baris ini:

[Order(Before = PredefinedAdornmentLayers.Text)]
[TextViewRole(PredefinedTextViewRoles.Document)]

Baris yang Anda ganti berada dalam sekelompok atribut yang mendeklarasikan lapisan hiasan. Baris pertama yang Anda ubah hanya mengubah tempat baris panduan kolom muncul. Menggambar baris "sebelum" teks dalam tampilan berarti teks muncul di belakang atau di bawah teks. Baris kedua menyatakan bahwa hiasan panduan kolom berlaku untuk entitas teks yang sesuai dengan gagasan Anda tentang dokumen, tetapi Anda dapat mendeklarasikan hiasan, misalnya, untuk hanya berfungsi untuk teks yang dapat diedit. Ada informasi lebih lanjut dalam layanan Bahasa dan titik ekstensi editor

Menerapkan pengelola pengaturan

Ganti konten GuidesSettingsManager.cs dengan kode berikut (dijelaskan di bawah):

using Microsoft.VisualStudio.Settings;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Settings;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;

namespace ColumnGuides
{
    internal static class GuidesSettingsManager
    {
        // Because my code is always called from the UI thred, this succeeds.
        internal static SettingsManager VsManagedSettingsManager =
            new ShellSettingsManager(ServiceProvider.GlobalProvider);

        private const int _maxGuides = 5;
        private const string _collectionSettingsName = "Text Editor";
        private const string _settingName = "Guides";
        // 1000 seems reasonable since primary scenario is long lines of code
        private const int _maxColumn = 1000;

        static internal bool AddGuideline(int column)
        {
            if (! IsValidColumn(column))
                throw new ArgumentOutOfRangeException(
                    "column",
                    "The paramenter must be between 1 and " + _maxGuides.ToString());
            var offsets = GuidesSettingsManager.GetColumnOffsets();
            if (offsets.Count() >= _maxGuides)
                return false;
            // Check for duplicates
            if (offsets.Contains(column))
                return false;
            offsets.Add(column);
            WriteSettings(GuidesSettingsManager.GuidelinesColor, offsets);
            return true;
        }

        static internal bool RemoveGuideline(int column)
        {
            if (!IsValidColumn(column))
                throw new ArgumentOutOfRangeException(
                    "column", "The paramenter must be between 1 and 10,000");
            var columns = GuidesSettingsManager.GetColumnOffsets();
            if (! columns.Remove(column))
            {
                // Not present.  Allow user to remove the last column
                // even if they're not on the right column.
                if (columns.Count != 1)
                    return false;

                columns.Clear();
            }
            WriteSettings(GuidesSettingsManager.GuidelinesColor, columns);
            return true;
        }

        static internal bool CanAddGuideline(int column)
        {
            if (!IsValidColumn(column))
                return false;
            var offsets = GetColumnOffsets();
            if (offsets.Count >= _maxGuides)
                return false;
            return ! offsets.Contains(column);
        }

        static internal bool CanRemoveGuideline(int column)
        {
            if (! IsValidColumn(column))
                return false;
            // Allow user to remove the last guideline regardless of the column.
            // Okay to call count, we limit the number of guides.
            var offsets = GuidesSettingsManager.GetColumnOffsets();
            return offsets.Contains(column) || offsets.Count() == 1;
        }

        static internal void RemoveAllGuidelines()
        {
            WriteSettings(GuidesSettingsManager.GuidelinesColor, new int[0]);
        }

        private static bool IsValidColumn(int column)
        {
            // zero is allowed (per user request)
            return 0 <= column && column <= _maxColumn;
        }

        // This has format "RGB(, , )  ...".
        // There can be any number of ints following the RGB part,
        // and each int is a column (char offset into line) where to draw.
        static private string _guidelinesConfiguration;
        static private string GuidelinesConfiguration
        {
            get
            {
                if (_guidelinesConfiguration == null)
                {
                    _guidelinesConfiguration =
                        GetUserSettingsString(
                            GuidesSettingsManager._collectionSettingsName,
                            GuidesSettingsManager._settingName)
                        .Trim();
                }
                return _guidelinesConfiguration;
            }

            set
            {
                if (value != _guidelinesConfiguration)
                {
                    _guidelinesConfiguration = value;
                    WriteUserSettingsString(
                        GuidesSettingsManager._collectionSettingsName,
                        GuidesSettingsManager._settingName, value);
                    // Notify ColumnGuideAdornments to update adornments in views.
                    var handler = GuidesSettingsManager.SettingsChanged;
                    if (handler != null)
                        handler();
                }
            }
        }

        internal static string GetUserSettingsString(string collection, string setting)
        {
            var store = GuidesSettingsManager
                            .VsManagedSettingsManager
                            .GetReadOnlySettingsStore(SettingsScope.UserSettings);
            return store.GetString(collection, setting, "RGB(255,0,0) 80");
        }

        internal static void WriteUserSettingsString(string key, string propertyName,
                                                     string value)
        {
            var store = GuidesSettingsManager
                            .VsManagedSettingsManager
                            .GetWritableSettingsStore(SettingsScope.UserSettings);
            store.CreateCollection(key);
            store.SetString(key, propertyName, value);
        }

        // Persists settings and sets property with side effect of signaling
        // ColumnGuideAdornments to update.
        static private void WriteSettings(Color color, IEnumerable columns)
        {
            string value = ComposeSettingsString(color, columns);
            GuidelinesConfiguration = value;
        }

        private static string ComposeSettingsString(Color color,
                                                    IEnumerable columns)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("RGB({0},{1},{2})", color.R, color.G, color.B);
            IEnumerator columnsEnumerator = columns.GetEnumerator();
            if (columnsEnumerator.MoveNext())
            {
                sb.AppendFormat(" {0}", columnsEnumerator.Current);
                while (columnsEnumerator.MoveNext())
                {
                    sb.AppendFormat(", {0}", columnsEnumerator.Current);
                }
            }
            return sb.ToString();
        }

        // Parse a color out of a string that begins like "RGB(255,0,0)"
        static internal Color GuidelinesColor
        {
            get
            {
                string config = GuidelinesConfiguration;
                if (!String.IsNullOrEmpty(config) && config.StartsWith("RGB("))
                {
                    int lastParen = config.IndexOf(')');
                    if (lastParen > 4)
                    {
                        string[] rgbs = config.Substring(4, lastParen - 4).Split(',');

                        if (rgbs.Length >= 3)
                        {
                            byte r, g, b;
                            if (byte.TryParse(rgbs[0], out r) &&
                                byte.TryParse(rgbs[1], out g) &&
                                byte.TryParse(rgbs[2], out b))
                            {
                                return Color.FromRgb(r, g, b);
                            }
                        }
                    }
                }
                return Colors.DarkRed;
            }

            set
            {
                WriteSettings(value, GetColumnOffsets());
            }
        }

        // Parse a list of integer values out of a string that looks like
        // "RGB(255,0,0) 1, 5, 10, 80"
        static internal List GetColumnOffsets()
        {
            var result = new List();
            string settings = GuidesSettingsManager.GuidelinesConfiguration;
            if (String.IsNullOrEmpty(settings))
                return new List();

            if (!settings.StartsWith("RGB("))
                return new List();

            int lastParen = settings.IndexOf(')');
            if (lastParen <= 4)
                return new List();

            string[] columns = settings.Substring(lastParen + 1).Split(',');

            int columnCount = 0;
            foreach (string columnText in columns)
            {
                int column = -1;
                // VS 2008 gallery extension didn't allow zero, so per user request ...
                if (int.TryParse(columnText, out column) && column >= 0)
                {
                    columnCount++;
                    result.Add(column);
                    if (columnCount >= _maxGuides)
                        break;
                }
            }
            return result;
        }

        // Delegate and Event to fire when settings change so that ColumnGuideAdornments
        // can update.  We need nothing special in this event since the settings manager
        // is statically available.
        //
        internal delegate void SettingsChangedHandler();
        static internal event SettingsChangedHandler SettingsChanged;

    }
}

Sebagian besar kode ini membuat dan mengurai format pengaturan: "RGB(><>) , , ...". Bilangan bulat di akhir adalah kolom berbasis satu tempat Anda menginginkan panduan kolom. Ekstensi panduan kolom mengambil semua pengaturannya dalam satu string nilai pengaturan.

Ada beberapa bagian dari kode yang layak disorot. Baris kode berikut mendapatkan pembungkus yang dikelola Visual Studio untuk penyimpanan pengaturan. Untuk sebagian besar, ini mengabstraksi registri Windows, tetapi API ini independen dari mekanisme penyimpanan.

internal static SettingsManager VsManagedSettingsManager =
    new ShellSettingsManager(ServiceProvider.GlobalProvider);

Penyimpanan pengaturan Visual Studio menggunakan pengidentifikasi kategori dan pengidentifikasi pengaturan untuk mengidentifikasi semua pengaturan secara unik:

private const string _collectionSettingsName = "Text Editor";
private const string _settingName = "Guides";

Anda tidak perlu menggunakan "Text Editor" sebagai nama kategori. Anda dapat memilih apa pun yang Anda suka.

Beberapa fungsi pertama adalah titik masuk untuk mengubah pengaturan. Mereka memeriksa batasan tingkat tinggi seperti jumlah maksimum panduan yang diizinkan. Kemudian, mereka memanggil WriteSettings, yang menyusun string pengaturan dan mengatur properti GuideLinesConfiguration. Mengatur properti ini menyimpan nilai pengaturan ke penyimpanan pengaturan Visual Studio dan mengaktifkan SettingsChanged peristiwa untuk memperbarui semua ColumnGuideAdornment objek, masing-masing terkait dengan tampilan teks.

Ada beberapa fungsi titik masuk, seperti CanAddGuideline, yang digunakan untuk mengimplementasikan perintah yang mengubah pengaturan. Saat Visual Studio menampilkan menu, visual Studio meminta implementasi perintah untuk melihat apakah perintah saat ini diaktifkan, apa namanya, dan sebagainya. Di bawah ini Anda melihat cara menghubungkan titik masuk ini untuk implementasi perintah. Untuk informasi selengkapnya tentang perintah, lihat Memperluas menu dan perintah.

Menerapkan kelas ColumnGuideAdornment

Kelas ColumnGuideAdornment ini dibuat untuk setiap tampilan teks yang dapat memiliki hiasan. Kelas ini mendengarkan peristiwa tentang perubahan tampilan atau perubahan pengaturan, dan panduan kolom pembaruan atau penguraian ulang seperlunya.

Ganti konten ColumnGuideAdornment.cs dengan kode berikut (dijelaskan di bawah):

using System;
using System.Windows.Media;
using Microsoft.VisualStudio.Text.Editor;
using System.Collections.Generic;
using System.Windows.Shapes;
using Microsoft.VisualStudio.Text.Formatting;
using System.Windows;

namespace ColumnGuides
{
    /// 
    /// Adornment class, one instance per text view that draws a guides on the viewport
    /// 
    internal sealed class ColumnGuideAdornment
    {
        private const double _lineThickness = 1.0;
        private IList _guidelines;
        private IWpfTextView _view;
        private double _baseIndentation;
        private double _columnWidth;

        /// 
        /// Creates editor column guidelines
        /// 
        /// The  upon
        /// which the adornment will be drawn
        public ColumnGuideAdornment(IWpfTextView view)
        {
            _view = view;
            _guidelines = CreateGuidelines();
            GuidesSettingsManager.SettingsChanged +=
                new GuidesSettingsManager.SettingsChangedHandler(SettingsChanged);
            view.LayoutChanged +=
                new EventHandler(OnViewLayoutChanged);
            _view.Closed += new EventHandler(OnViewClosed);
        }

        void SettingsChanged()
        {
            _guidelines = CreateGuidelines();
            UpdatePositions();
            AddGuidelinesToAdornmentLayer();
        }

        void OnViewClosed(object sender, EventArgs e)
        {
            _view.LayoutChanged -= OnViewLayoutChanged;
            _view.Closed -= OnViewClosed;
            GuidesSettingsManager.SettingsChanged -= SettingsChanged;
        }

        private bool _firstLayoutDone;

        void OnViewLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
        {
            bool fUpdatePositions = false;

            IFormattedLineSource lineSource = _view.FormattedLineSource;
            if (lineSource == null)
            {
                return;
            }
            if (_columnWidth != lineSource.ColumnWidth)
            {
                _columnWidth = lineSource.ColumnWidth;
                fUpdatePositions = true;
            }
            if (_baseIndentation != lineSource.BaseIndentation)
            {
                _baseIndentation = lineSource.BaseIndentation;
                fUpdatePositions = true;
            }
            if (fUpdatePositions ||
                e.VerticalTranslation ||
                e.NewViewState.ViewportTop != e.OldViewState.ViewportTop ||
                e.NewViewState.ViewportBottom != e.OldViewState.ViewportBottom)
            {
                UpdatePositions();
            }
            if (!_firstLayoutDone)
            {
                AddGuidelinesToAdornmentLayer();
                _firstLayoutDone = true;
            }
        }

        private static IList CreateGuidelines()
        {
            Brush lineBrush = new SolidColorBrush(GuidesSettingsManager.GuidelinesColor);
            DoubleCollection dashArray = new DoubleCollection(new double[] { 1.0, 3.0 });
            IList result = new List();
            foreach (int column in GuidesSettingsManager.GetColumnOffsets())
            {
                Line line = new Line()
                {
                    // Use the DataContext slot as a cookie to hold the column
                    DataContext = column,
                    Stroke = lineBrush,
                    StrokeThickness = _lineThickness,
                    StrokeDashArray = dashArray
                };
                result.Add(line);
            }
            return result;
        }

        void UpdatePositions()
        {
            foreach (Line line in _guidelines)
            {
                int column = (int)line.DataContext;
                line.X2 = _baseIndentation + 0.5 + column * _columnWidth;
                line.X1 = line.X2;
                line.Y1 = _view.ViewportTop;
                line.Y2 = _view.ViewportBottom;
            }
        }

        void AddGuidelinesToAdornmentLayer()
        {
            // Grab a reference to the adornment layer that this adornment
            // should be added to
            // Must match exported name in ColumnGuideAdornmentTextViewCreationListener
            IAdornmentLayer adornmentLayer =
                _view.GetAdornmentLayer("ColumnGuideAdornment");
            if (adornmentLayer == null)
                return;
            adornmentLayer.RemoveAllAdornments();
            // Add the guidelines to the adornment layer and make them relative
            // to the viewport
            foreach (UIElement element in _guidelines)
                adornmentLayer.AddAdornment(AdornmentPositioningBehavior.OwnerControlled,
                                            null, null, element, null);
        }
    }

}

Instans kelas ini berpegang pada terkait IWpfTextView dan daftar Line objek yang digambar pada tampilan.

Konstruktor (dipanggil dari ColumnGuideAdornmentTextViewCreationListener saat Visual Studio membuat tampilan baru) membuat objek panduan Line kolom. Konstruktor juga menambahkan handler untuk SettingsChanged peristiwa (ditentukan dalam GuidesSettingsManager) dan melihat peristiwa LayoutChanged dan Closed.

Peristiwa ini LayoutChanged diaktifkan karena beberapa jenis perubahan dalam tampilan, termasuk saat Visual Studio membuat tampilan. Handler OnViewLayoutChanged memanggil AddGuidelinesToAdornmentLayer untuk mengeksekusi. Kode dalam OnViewLayoutChanged menentukan apakah perlu memperbarui posisi baris berdasarkan perubahan seperti perubahan ukuran font, melihat selokan, pengguliran horizontal, dan sebagainya. Kode dalam menyebabkan garis panduan menggambar di UpdatePositions antara karakter atau tepat setelah kolom teks yang berada dalam offset karakter yang ditentukan di baris teks.

Setiap kali pengaturan mengubah SettingsChanged fungsi hanya membuat ulang semua Line objek dengan pengaturan baru apa pun. Setelah mengatur posisi baris, kode menghapus semua objek sebelumnya Line dari ColumnGuideAdornment lapisan hiasan dan menambahkan yang baru.

Menentukan perintah, menu, dan penempatan menu

Mungkin ada banyak hal untuk mendeklarasikan perintah dan menu, menempatkan grup perintah atau menu di berbagai menu lainnya, dan menghubungkan penangan perintah. Panduan ini menyoroti cara kerja perintah dalam ekstensi ini, tetapi untuk informasi yang lebih mendalam, lihat Memperluas menu dan perintah.

Pengantar kode

Ekstensi Panduan Kolom memperlihatkan mendeklarasikan sekelompok perintah yang dimiliki bersama-sama (tambahkan kolom, hapus kolom, ubah warna garis), lalu tempatkan grup tersebut pada sub menu konteks editor. Ekstensi Panduan Kolom juga menambahkan perintah ke menu Edit utama tetapi membuatnya tidak terlihat, dibahas sebagai pola umum di bawah ini.

Ada tiga bagian untuk implementasi perintah: ColumnGuideCommandsPackage.cs, ColumnGuideCommandsPackage.vsct, dan ColumnGuideCommands.cs. Kode yang dihasilkan oleh templat menempatkan perintah pada menu Alat yang memunculkan kotak dialog sebagai implementasi. Anda dapat melihat bagaimana itu diimplementasikan dalam file .vsct dan ColumnGuideCommands.cs karena mudah. Anda mengganti kode dalam file-file ini di bawah ini.

Kode paket berisi deklarasi boilerplate yang diperlukan agar Visual Studio menemukan bahwa ekstensi menawarkan perintah dan untuk menemukan tempat menempatkan perintah. Ketika paket diinisialisasi, itu membuat instans kelas implementasi perintah. Untuk informasi selengkapnya tentang paket yang berkaitan dengan perintah, lihat Memperluas menu dan perintah.

Pola perintah umum

Perintah dalam ekstensi Panduan Kolom adalah contoh pola yang sangat umum di Visual Studio. Anda menempatkan perintah terkait dalam grup, dan Anda menempatkan grup tersebut pada menu utama, sering kali dengan "CommandWellOnly" diatur untuk membuat perintah tidak terlihat. Menempatkan perintah pada menu utama (seperti Edit) memberi mereka nama yang bagus (seperti Edit.AddColumnGuide), yang berguna untuk menemukan perintah saat menetapkan kembali pengikatan kunci di Opsi Alat. Ini juga berguna untuk menyelesaikan saat memanggil perintah dari Jendela Perintah.

Anda kemudian menambahkan grup perintah ke menu konteks atau sub menu tempat Anda mengharapkan pengguna menggunakan perintah. Visual Studio memperlakukan CommandWellOnly sebagai bendera tidak terlihat hanya untuk menu utama. Saat Anda menempatkan grup perintah yang sama pada menu konteks atau sub menu, perintah akan terlihat.

Sebagai bagian dari pola umum, ekstensi Panduan Kolom membuat grup kedua yang menyimpan satu sub menu. Sub menu pada gilirannya berisi grup pertama dengan perintah panduan empat kolom. Grup kedua yang menyimpan sub menu adalah aset yang dapat digunakan kembali yang Anda tempatkan di berbagai menu konteks, yang menempatkan sub menu pada menu konteks tersebut.

File .vsct

File .vsct mendeklarasikan perintah dan ke mana mereka pergi, bersama dengan ikon dan sebagainya. Ganti konten file .vsct dengan kode berikut (dijelaskan di bawah):




  

  

  
  

  
  

  
  
    

    
    

      
      
      
        
      

      
      
        
      

    

    
      
        
        
          &Column Guides
        
      
    

    
    
    
      

      

      

      

      
    

    
    
      
      
    

  

  

    

    
    
      
    

    
    
      
    

    
    
      
    

    
    
      
    

    
    
      
    

    
    
      
    

  

  
  
    
    

    
    
      
      
      
      
      
      
      
    

    
      
      
      
    

    
      
    

    
      
      
      
    

    
      
    
  



GUIDS. Agar Visual Studio menemukan penangan perintah Anda dan memanggilnya, Anda perlu memastikan GUID paket yang dideklarasikan dalam file ColumnGuideCommandsPackage.cs (dihasilkan dari templat item proyek) cocok dengan GUID paket yang dideklarasikan dalam file .vsct (disalin dari atas). Jika Anda menggunakan kembali kode sampel ini, Anda harus memastikan Anda memiliki GUID yang berbeda sehingga Anda tidak berkonflik dengan orang lain yang mungkin telah menyalin kode ini.

Temukan baris ini di ColumnGuideCommandsPackage.cs dan salin GUID dari antara tanda kutip:

public const string PackageGuidString = "ef726849-5447-4f73-8de5-01b9e930f7cd";

Kemudian, tempelkan GUID dalam file .vsct sehingga Anda memiliki baris berikut dalam deklarasi Anda Symbols :


GUID untuk set perintah dan file gambar bitmap harus unik untuk ekstensi Anda juga:



Tetapi, Anda tidak perlu mengubah set perintah dan GUID gambar bitmap dalam panduan ini agar kode berfungsi. Set perintah GUID perlu mencocokkan deklarasi dalam file ColumnGuideCommands.cs , tetapi Anda juga mengganti konten file tersebut; oleh karena itu, GUID akan cocok.

GUID lain dalam file .vsct mengidentifikasi menu yang sudah ada sebelumnya tempat perintah panduan kolom ditambahkan, sehingga tidak pernah berubah.

Bagian file. .vsct memiliki tiga bagian luar: perintah, penempatan, dan simbol. Bagian perintah menentukan grup perintah, menu, tombol atau item menu, dan bitmap untuk ikon. Bagian penempatan mendeklarasikan tempat grup membuka menu atau penempatan tambahan ke menu yang sudah ada sebelumnya. Bagian simbol mendeklarasikan pengidentifikasi yang digunakan di tempat lain dalam file .vsct , yang membuat kode .vsct lebih mudah dibaca daripada memiliki GUID dan angka heksa di mana-mana.

Bagian perintah, definisi grup. Bagian perintah pertama-tama menentukan grup perintah. Grup perintah adalah perintah yang Anda lihat di menu dengan sedikit garis abu-abu yang memisahkan grup. Grup juga dapat mengisi seluruh sub menu, seperti dalam contoh ini, dan Anda tidak melihat garis pemisah abu-abu dalam kasus ini. File .vsct mendeklarasikan dua grup, GuidesMenuItemsGroup yang diindukkan ke IDM_VS_MENU_EDIT (menu Edit utama) dan GuidesContextMenuGroup yang diindukkan ke IDM_VS_CTXT_CODEWIN (menu konteks editor kode).

Deklarasi grup kedua memiliki 0x0600 prioritas:


Idenya adalah untuk menempatkan sub menu panduan kolom di akhir menu konteks apa pun yang Anda tambahkan grup sub menu. Tapi, Anda tidak boleh berasumsi Anda tahu yang terbaik dan memaksa sub menu untuk selalu menjadi yang terakhir dengan menggunakan prioritas 0xFFFF. Anda harus bereksperimen dengan nomor untuk melihat di mana sub menu Anda terletak pada menu konteks tempat Anda menempatkannya. Dalam hal ini, 0x0600 cukup tinggi untuk meletakkannya di akhir menu sejauh yang Anda lihat, tetapi meninggalkan ruang bagi orang lain untuk merancang ekstensi mereka agar lebih rendah dari ekstensi panduan kolom jika diinginkan.

Bagian perintah, definisi menu. Selanjutnya, bagian perintah menentukan sub menu GuidesSubMenu, diindukkan ke GuidesContextMenuGroup. GuidesContextMenuGroup adalah grup yang Anda tambahkan ke semua menu konteks yang relevan. Di bagian penempatan, kode menempatkan grup dengan perintah panduan empat kolom pada sub menu ini.

Bagian perintah, definisi tombol. Bagian perintah kemudian menentukan item menu atau tombol yang merupakan perintah panduan empat kolom. CommandWellOnly, yang dibahas di atas, berarti perintah tidak terlihat ketika ditempatkan pada menu utama. Dua deklarasi tombol item menu (tambahkan panduan dan hapus panduan) juga memiliki AllowParams bendera:

AllowParams

Bendera ini memungkinkan, bersama dengan penempatan menu utama, perintah untuk menerima argumen saat Visual Studio memanggil handler perintah. Jika pengguna menjalankan perintah dari Jendela Perintah, argumen diteruskan ke handler perintah dalam argumen peristiwa.

Bagian perintah, definisi bitmap. Terakhir, bagian perintah mendeklarasikan bitmap atau ikon yang digunakan untuk perintah. Bagian ini adalah deklarasi sederhana yang mengidentifikasi sumber daya proyek dan mencantumkan indeks berbasis satu ikon yang digunakan. Bagian simbol dari file .vsct mendeklarasikan nilai pengidentifikasi yang digunakan sebagai indeks. Panduan ini menggunakan strip bitmap yang disediakan dengan templat item perintah kustom yang ditambahkan ke proyek.

Bagian penempatan. Setelah bagian perintah adalah bagian penempatan. Yang pertama adalah tempat kode menambahkan grup pertama yang dibahas di atas yang menyimpan perintah panduan empat kolom ke sub menu tempat perintah muncul:


  

Semua penempatan lainnya menambahkan GuidesContextMenuGroup (yang berisi GuidesSubMenu) ke menu konteks editor lainnya. Ketika kode mendeklarasikan GuidesContextMenuGroup, kode tersebut diinduk ke menu konteks editor kode. Itulah sebabnya Anda tidak melihat penempatan untuk menu konteks editor kode.

Bagian simbol. Seperti yang dinyatakan di atas, bagian simbol menyatakan pengidentifikasi yang digunakan di tempat lain dalam file .vsct , yang membuat kode .vsct lebih mudah dibaca daripada memiliki GUID dan angka hex di mana-mana. Poin penting di bagian ini adalah bahwa GUID paket harus setuju dengan deklarasi di kelas paket. Dan, guid set perintah harus setuju dengan deklarasi di kelas implementasi perintah.

Menerapkan perintah

File ColumnGuideCommands.cs mengimplementasikan perintah dan menghubungkan handler. Saat Visual Studio memuat paket dan menginisialisasinya, paket pada gilirannya memanggil Initialize pada kelas implementasi perintah. Inisialisasi perintah hanya membuat instans kelas, dan konstruktor menghubungkan semua handler perintah.

Ganti konten file ColumnGuideCommands.cs dengan kode berikut (dijelaskan di bawah):

using System;
using System.ComponentModel.Design;
using System.Globalization;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio;

namespace ColumnGuides
{
    /// 
    /// Command handler
    /// 
    internal sealed class ColumnGuideCommands
    {

        const int cmdidAddColumnGuide = 0x0100;
        const int cmdidRemoveColumnGuide = 0x0101;
        const int cmdidChooseGuideColor = 0x0102;
        const int cmdidRemoveAllColumnGuides = 0x0103;

        /// 
        /// Command menu group (command set GUID).
        /// 
        static readonly Guid CommandSet =
            new Guid("c2bc0047-8bfa-4e5a-b5dc-45af8c274d8e");

        /// 
        /// VS Package that provides this command, not null.
        /// 
        private readonly Package package;

        OleMenuCommand _addGuidelineCommand;
        OleMenuCommand _removeGuidelineCommand;

        /// 
        /// Initializes the singleton instance of the command.
        /// 
        /// Owner package, not null.
        public static void Initialize(Package package)
        {
            Instance = new ColumnGuideCommands(package);
        }

        /// 
        /// Gets the instance of the command.
        /// 
        public static ColumnGuideCommands Instance
        {
            get;
            private set;
        }

        /// 
        /// Initializes a new instance of the  class.
        /// Adds our command handlers for menu (commands must exist in the command
        /// table file)
        /// 
        /// Owner package, not null.
        private ColumnGuideCommands(Package package)
        {
            if (package == null)
            {
                throw new ArgumentNullException("package");
            }

            this.package = package;

            // Add our command handlers for menu (commands must exist in the .vsct file)

            OleMenuCommandService commandService =
                this.ServiceProvider.GetService(typeof(IMenuCommandService))
                    as OleMenuCommandService;
            if (commandService != null)
            {
                // Add guide
                _addGuidelineCommand =
                    new OleMenuCommand(AddColumnGuideExecuted, null,
                                       AddColumnGuideBeforeQueryStatus,
                                       new CommandID(ColumnGuideCommands.CommandSet,
                                                     cmdidAddColumnGuide));
                _addGuidelineCommand.ParametersDescription = "";
                commandService.AddCommand(_addGuidelineCommand);
                // Remove guide
                _removeGuidelineCommand =
                    new OleMenuCommand(RemoveColumnGuideExecuted, null,
                                       RemoveColumnGuideBeforeQueryStatus,
                                       new CommandID(ColumnGuideCommands.CommandSet,
                                                     cmdidRemoveColumnGuide));
                _removeGuidelineCommand.ParametersDescription = "";
                commandService.AddCommand(_removeGuidelineCommand);
                // Choose color
                commandService.AddCommand(
                    new MenuCommand(ChooseGuideColorExecuted,
                                    new CommandID(ColumnGuideCommands.CommandSet,
                                                  cmdidChooseGuideColor)));
                // Remove all
                commandService.AddCommand(
                    new MenuCommand(RemoveAllGuidelinesExecuted,
                                    new CommandID(ColumnGuideCommands.CommandSet,
                                                  cmdidRemoveAllColumnGuides)));
            }
        }

        /// 
        /// Gets the service provider from the owner package.
        /// 
        private IServiceProvider ServiceProvider
        {
            get
            {
                return this.package;
            }
        }

        private void AddColumnGuideBeforeQueryStatus(object sender, EventArgs e)
        {
            int currentColumn = GetCurrentEditorColumn();
            _addGuidelineCommand.Enabled =
                GuidesSettingsManager.CanAddGuideline(currentColumn);
        }

        private void RemoveColumnGuideBeforeQueryStatus(object sender, EventArgs e)
        {
            int currentColumn = GetCurrentEditorColumn();
            _removeGuidelineCommand.Enabled =
                GuidesSettingsManager.CanRemoveGuideline(currentColumn);
        }

        private int GetCurrentEditorColumn()
        {
            IVsTextView view = GetActiveTextView();
            if (view == null)
            {
                return -1;
            }

            try
            {
                IWpfTextView textView = GetTextViewFromVsTextView(view);
                int column = GetCaretColumn(textView);

                // Note: GetCaretColumn returns 0-based positions. Guidelines are 1-based
                // positions.
                // However, do not subtract one here since the caret is positioned to the
                // left of
                // the given column and the guidelines are positioned to the right. We
                // want the
                // guideline to line up with the current caret position. e.g. When the
                // caret is
                // at position 1 (zero-based), the status bar says column 2. We want to
                // add a
                // guideline for column 1 since that will place the guideline where the
                // caret is.
                return column;
            }
            catch (InvalidOperationException)
            {
                return -1;
            }
        }

        /// 
        /// Find the active text view (if any) in the active document.
        /// 
        /// The IVsTextView of the active view, or null if there is no active
        /// document or the
        /// active view in the active document is not a text view.
        private IVsTextView GetActiveTextView()
        {
            IVsMonitorSelection selection =
                this.ServiceProvider.GetService(typeof(IVsMonitorSelection))
                                                    as IVsMonitorSelection;
            object frameObj = null;
            ErrorHandler.ThrowOnFailure(
                selection.GetCurrentElementValue(
                    (uint)VSConstants.VSSELELEMID.SEID_DocumentFrame, out frameObj));

            IVsWindowFrame frame = frameObj as IVsWindowFrame;
            if (frame == null)
            {
                return null;
            }

            return GetActiveView(frame);
        }

        private static IVsTextView GetActiveView(IVsWindowFrame windowFrame)
        {
            if (windowFrame == null)
            {
                throw new ArgumentException("windowFrame");
            }

            object pvar;
            ErrorHandler.ThrowOnFailure(
                windowFrame.GetProperty((int)__VSFPROPID.VSFPROPID_DocView, out pvar));

            IVsTextView textView = pvar as IVsTextView;
            if (textView == null)
            {
                IVsCodeWindow codeWin = pvar as IVsCodeWindow;
                if (codeWin != null)
                {
                    ErrorHandler.ThrowOnFailure(codeWin.GetLastActiveView(out textView));
                }
            }
            return textView;
        }

        private static IWpfTextView GetTextViewFromVsTextView(IVsTextView view)
        {

            if (view == null)
            {
                throw new ArgumentNullException("view");
            }

            IVsUserData userData = view as IVsUserData;
            if (userData == null)
            {
                throw new InvalidOperationException();
            }

            object objTextViewHost;
            if (VSConstants.S_OK
                   != userData.GetData(Microsoft.VisualStudio
                                                .Editor
                                                .DefGuidList.guidIWpfTextViewHost,
                                       out objTextViewHost))
            {
                throw new InvalidOperationException();
            }

            IWpfTextViewHost textViewHost = objTextViewHost as IWpfTextViewHost;
            if (textViewHost == null)
            {
                throw new InvalidOperationException();
            }

            return textViewHost.TextView;
        }

        /// 
        /// Given an IWpfTextView, find the position of the caret and report its column
        /// number. The column number is 0-based
        /// 
        /// The text view containing the caret
        /// The column number of the caret's position. When the caret is at the
        /// leftmost column, the return value is zero.
        private static int GetCaretColumn(IWpfTextView textView)
        {
            // This is the code the editor uses to populate the status bar.
            Microsoft.VisualStudio.Text.Formatting.ITextViewLine caretViewLine =
                textView.Caret.ContainingTextViewLine;
            double columnWidth = textView.FormattedLineSource.ColumnWidth;
            return (int)(Math.Round((textView.Caret.Left - caretViewLine.Left)
                                       / columnWidth));
        }

        /// 
        /// Determine the applicable column number for an add or remove command.
        /// The column is parsed from command arguments, if present. Otherwise
        /// the current position of the caret is used to determine the column.
        /// 
        /// Event args passed to the command handler.
        /// The column number. May be negative to indicate the column number is
        /// unavailable.
        /// The column number parsed from event args
        /// was not a valid integer.
        private int GetApplicableColumn(EventArgs e)
        {
            var inValue = ((OleMenuCmdEventArgs)e).InValue as string;
            if (!string.IsNullOrEmpty(inValue))
            {
                int column;
                if (!int.TryParse(inValue, out column) || column < 0)
                    throw new ArgumentException("Invalid column");
                return column;
            }

            return GetCurrentEditorColumn();
        }

        /// 
        /// This function is the callback used to execute a command when the a menu item
        /// is clicked. See the Initialize method to see how the menu item is associated
        /// to this function using the OleMenuCommandService service and the MenuCommand
        /// class.
        /// 
        private void AddColumnGuideExecuted(object sender, EventArgs e)
        {
            int column = GetApplicableColumn(e);
            if (column >= 0)
            {
                GuidesSettingsManager.AddGuideline(column);
            }
        }

        private void RemoveColumnGuideExecuted(object sender, EventArgs e)
        {
            int column = GetApplicableColumn(e);
            if (column >= 0)
            {
                GuidesSettingsManager.RemoveGuideline(column);
            }
        }

        private void RemoveAllGuidelinesExecuted(object sender, EventArgs e)
        {
            GuidesSettingsManager.RemoveAllGuidelines();
        }

        private void ChooseGuideColorExecuted(object sender, EventArgs e)
        {
            System.Windows.Media.Color color = GuidesSettingsManager.GuidelinesColor;

            using (System.Windows.Forms.ColorDialog picker =
                new System.Windows.Forms.ColorDialog())
            {
                picker.Color = System.Drawing.Color.FromArgb(255, color.R, color.G,
                                                             color.B);
                if (picker.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    GuidesSettingsManager.GuidelinesColor =
                        System.Windows.Media.Color.FromRgb(picker.Color.R,
                                                           picker.Color.G,
                                                           picker.Color.B);
                }
            }
        }

    }
}

Perbaiki referensi. Anda kehilangan referensi saat ini. Tekan tombol penunjuk kanan pada simpul Referensi di Penjelajah Solusi. Pilih perintah Tambahkan ... . Dialog Tambahkan Referensi memiliki kotak pencarian di sudut kanan atas. Masukkan "editor" (tanpa tanda kutip ganda). Pilih item Microsoft.VisualStudio.Editor (Anda harus mencentang kotak di sebelah kiri item, bukan hanya memilih item) dan pilih OK untuk menambahkan referensi.

Inisialisasi. Ketika kelas paket diinisialisasi, kelas ini memanggil Initialize kelas implementasi perintah. Inisialisasi ColumnGuideCommands membuat instans kelas dan menyimpan instans kelas dan referensi paket di anggota kelas.

Mari kita lihat salah satu pengatur perintah hook-up dari konstruktor kelas:

_addGuidelineCommand =
    new OleMenuCommand(AddColumnGuideExecuted, null,
                       AddColumnGuideBeforeQueryStatus,
                       new CommandID(ColumnGuideCommands.CommandSet,
                                     cmdidAddColumnGuide));

Anda membuat OleMenuCommand. Visual Studio menggunakan sistem perintah Microsoft Office. Argumen kunci saat membuat instans adalah OleMenuCommand fungsi yang mengimplementasikan perintah (AddColumnGuideExecuted), fungsi yang akan dipanggil saat Visual Studio menampilkan menu dengan perintah (AddColumnGuideBeforeQueryStatus), dan ID perintah. Visual studio memanggil fungsi status kueri sebelum menampilkan perintah pada menu sehingga perintah dapat membuatnya tidak terlihat atau berwarna abu-abu untuk tampilan menu tertentu (misalnya, menonaktifkan Salin jika tidak ada pilihan), mengubah ikonnya, atau bahkan mengubah namanya (misalnya, dari Tambahkan Sesuatu untuk Menghapus Sesuatu), dan sebagainya. ID perintah harus cocok dengan ID perintah yang dideklarasikan dalam file .vsct . String untuk set perintah dan perintah tambahkan panduan kolom harus cocok antara file .vsct dan ColumnGuideCommands.cs.

Baris berikut memberikan bantuan saat pengguna memanggil perintah melalui Jendela Perintah (dijelaskan di bawah):

_addGuidelineCommand.ParametersDescription = "";

Status kueri. Status kueri berfungsi AddColumnGuideBeforeQueryStatus dan RemoveColumnGuideBeforeQueryStatus memeriksa beberapa pengaturan (seperti jumlah maksimum panduan atau kolom maks) atau jika ada panduan kolom untuk dihapus. Mereka mengaktifkan perintah jika kondisinya benar. Fungsi status kueri harus efisien karena berjalan setiap kali Visual Studio menampilkan menu dan untuk setiap perintah pada menu.

Tambahkan fungsiColumnGuideExecuted. Bagian menarik dari menambahkan panduan adalah mencari tahu tampilan editor saat ini dan lokasi tanda sisipan. Pertama, fungsi ini memanggil GetApplicableColumn, yang memeriksa apakah ada argumen yang disediakan pengguna dalam argumen peristiwa handler perintah, dan jika tidak ada, fungsi memeriksa tampilan editor:

private int GetApplicableColumn(EventArgs e)
{
    var inValue = ((OleMenuCmdEventArgs)e).InValue as string;
    if (!string.IsNullOrEmpty(inValue))
    {
        int column;
        if (!int.TryParse(inValue, out column) || column < 0)
            throw new ArgumentException("Invalid column");
        return column;
    }

    return GetCurrentEditorColumn();
}

GetCurrentEditorColumn harus menggali sedikit untuk mendapatkan IWpfTextView tampilan kode. Jika Anda melacak melalui GetActiveTextView, , GetActiveViewdan GetTextViewFromVsTextView, Anda dapat melihat cara melakukannya. Kode berikut adalah kode yang relevan yang diabstraksi, dimulai dengan pilihan saat ini, lalu mendapatkan bingkai pilihan, lalu mendapatkan DocView bingkai sebagai IVsTextView, lalu mendapatkan IVsUserData dari IVsTextView, lalu mendapatkan host tampilan, dan akhirnya IWpfTextView:

   IVsMonitorSelection selection =
       this.ServiceProvider.GetService(typeof(IVsMonitorSelection))
           as IVsMonitorSelection;
   object frameObj = null;

ErrorHandler.ThrowOnFailure(selection.GetCurrentElementValue(
                                (uint)VSConstants.VSSELELEMID.SEID_DocumentFrame,
                                out frameObj));

   IVsWindowFrame frame = frameObj as IVsWindowFrame;
   if (frame == null)
       <>;

...
   object pvar;
   ErrorHandler.ThrowOnFailure(frame.GetProperty((int)__VSFPROPID.VSFPROPID_DocView,
                                                  out pvar));

   IVsTextView textView = pvar as IVsTextView;
   if (textView == null)
   {
       IVsCodeWindow codeWin = pvar as IVsCodeWindow;
       if (codeWin != null)
       {
           ErrorHandler.ThrowOnFailure(codeWin.GetLastActiveView(out textView));
       }
   }

...
   if (textView == null)
       <>

   IVsUserData userData = textView as IVsUserData;
   if (userData == null)
       <>

   object objTextViewHost;
   if (VSConstants.S_OK
           != userData.GetData(Microsoft.VisualStudio.Editor.DefGuidList
                                                            .guidIWpfTextViewHost,
                                out objTextViewHost))
   {
       <>
   }

   IWpfTextViewHost textViewHost = objTextViewHost as IWpfTextViewHost;
   if (textViewHost == null)
       <>

   IWpfTextView textView = textViewHost.TextView;

Setelah Anda memiliki IWpfTextView, Anda bisa mendapatkan kolom tempat tanda sisipan berada:

private static int GetCaretColumn(IWpfTextView textView)
{
    // This is the code the editor uses to populate the status bar.
    Microsoft.VisualStudio.Text.Formatting.ITextViewLine caretViewLine =
        textView.Caret.ContainingTextViewLine;
    double columnWidth = textView.FormattedLineSource.ColumnWidth;
    return (int)(Math.Round((textView.Caret.Left - caretViewLine.Left)
                                / columnWidth));
}

Dengan kolom saat ini di tangan tempat pengguna mengklik, kode hanya memanggil manajer pengaturan untuk menambahkan atau menghapus kolom. Manajer pengaturan mengaktifkan peristiwa yang didengarkan semua ColumnGuideAdornment objek. Saat peristiwa diaktifkan, objek ini memperbarui tampilan teks terkait dengan pengaturan panduan kolom baru.

Memanggil perintah dari Jendela Perintah

Sampel panduan kolom memungkinkan pengguna untuk memanggil dua perintah dari Jendela Perintah sebagai bentuk ekstensibilitas. Jika Anda menggunakan | Tampilan | Windows lainnya Perintah Jendela Perintah , Anda dapat melihat Jendela Perintah. Anda dapat berinteraksi dengan Jendela Perintah dengan memasukkan "edit.", dan dengan penyelesaian nama perintah dan menyediakan argumen 120, Anda memiliki hasil berikut:

> Edit.AddColumnGuide 120
>

Potongan sampel yang mengaktifkan perilaku ini ada dalam deklarasi file .vsct , ColumnGuideCommands konstruktor kelas saat menghubungkan handler perintah, dan implementasi handler perintah yang memeriksa argumen peristiwa.

Anda melihat "CommandWellOnly" dalam file .vsct serta penempatan di menu utama Edit meskipun perintah tidak ditampilkan di UI menu Edit . Memilikinya di menu Edit utama memberi mereka nama seperti Edit.AddColumnGuide. Deklarasi grup perintah yang menyimpan empat perintah menempatkan grup pada menu Edit secara langsung:


        
      

Bagian tombol kemudian mendeklarasikan perintah CommandWellOnly agar tidak terlihat pada menu utama dan mendeklarasikannya dengan AllowParams:

Anda melihat kode hook up handler perintah di ColumnGuideCommands konstruktor kelas memberikan deskripsi parameter yang diizinkan:

_addGuidelineCommand.ParametersDescription = "";

Anda melihat GetApplicableColumn fungsi memeriksa OleMenuCmdEventArgs nilai sebelum memeriksa tampilan editor untuk kolom saat ini:

private int GetApplicableColumn(EventArgs e)
{
    var inValue = ((OleMenuCmdEventArgs)e).InValue as string;
    if (!string.IsNullOrEmpty(inValue))
    {
        int column;
        if (!int.TryParse(inValue, out column) || column < 0)
            throw new ArgumentException("Invalid column");
        return column;
    }

Coba ekstensi Anda

Sekarang Anda dapat menekan F5 untuk menjalankan ekstensi Panduan Kolom Anda. Buka file teks dan gunakan menu konteks editor untuk menambahkan baris panduan, menghapusnya, dan mengubah warnanya. Klik teks (bukan spasi kosong melewati akhir baris) untuk menambahkan panduan kolom, atau editor menambahkannya ke kolom terakhir pada baris. Jika Anda menggunakan Jendela Perintah dan memanggil perintah dengan argumen, Anda dapat menambahkan panduan kolom di mana saja.

Jika Anda ingin mencoba penempatan perintah yang berbeda, mengubah nama, mengubah ikon, dan sebagainya, dan Anda memiliki masalah dengan Visual Studio yang menunjukkan kode terbaru di menu, Anda dapat mengatur ulang sarang eksperimental tempat Anda melakukan debugging. Munculkan Menu Mulai Windows dan ketik "reset". Cari dan jalankan perintah, Reset Instans Eksperimental Visual Studio Berikutnya. Perintah ini membersihkan sarang registri eksperimental dari semua komponen ekstensi. Ini tidak membersihkan pengaturan dari komponen, jadi panduan apa pun yang Anda miliki ketika Anda mematikan sarang eksperimental Visual Studio masih ada ketika kode Anda membaca penyimpanan pengaturan pada peluncuran berikutnya.

Proyek kode selesai

Akan segera ada proyek GitHub dari sampel Ekstensibilitas Visual Studio, dan proyek yang telah selesai akan berada di sana. Artikel ini akan diperbarui untuk menunjuk ke sana ketika itu terjadi. Proyek sampel yang selesai mungkin memiliki guid yang berbeda dan akan memiliki strip bitmap yang berbeda untuk ikon perintah.

Anda dapat mencoba versi fitur panduan kolom denganekstensi Visual Studio Gallery ini.

Lihat juga

  • Di dalam editor
  • Memperluas layanan editor dan bahasa
  • Layanan bahasa dan titik ekstensi editor
  • Perluas menu dan perintah
  • Menambahkan submenu ke menu
  • Membuat ekstensi dengan templat item editor