Mengelola proyek Universal Windows
Aplikasi Universal Windows adalah aplikasi yang menargetkan Windows 8.1 dan Windows Telepon 8.1, memungkinkan pengembang untuk menggunakan kode dan aset lain di kedua platform. Kode dan sumber daya bersama disimpan dalam proyek bersama, sementara kode dan sumber daya khusus platform disimpan dalam proyek terpisah, satu untuk Windows dan yang lainnya untuk Windows Telepon. Untuk informasi selengkapnya tentang aplikasi Windows universal, lihat Aplikasi Universal Windows. Ekstensi Visual Studio yang mengelola proyek harus menyadari bahwa proyek aplikasi Windows universal memiliki struktur yang berbeda dari aplikasi platform tunggal. Panduan ini menunjukkan kepada Anda cara menavigasi proyek bersama dan mengelola item bersama.
Menavigasi proyek bersama
Buat proyek C# VSIX bernama TestUniversalProject. (File>Proyek Baru>lalu C#>Ekstensibilitas>Paket Visual Studio). Tambahkan templat item proyek Perintah Kustom (pada Penjelajah Solusi, klik kanan simpul proyek dan pilih Tambahkan>Item Baru, lalu buka Ekstensibilitas). Beri nama file TestUniversalProject.
Tambahkan referensi ke Microsoft.VisualStudio.Shell.Interop.12.1.DesignTime.dll dan Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.dll (di bagian Ekstensi).
Buka TestUniversalProject.cs dan tambahkan arahan berikut
using
:using EnvDTE; using EnvDTE80; using Microsoft.VisualStudio; using Microsoft.VisualStudio.PlatformUI; using Microsoft.Internal.VisualStudio.PlatformUI; using System.Collections.Generic; using System.IO; using System.Windows.Forms;
TestUniversalProject
Di kelas tambahkan bidang privat yang menunjuk ke jendela Output.public sealed class TestUniversalProject { IVsOutputWindowPane output; . . . }
Atur referensi ke panel output di dalam konstruktor TestUniversalProject:
private TestUniversalProject(Package package) { if (package == null) { throw new ArgumentNullException("package"); } this.package = package; OleMenuCommandService commandService = this.ServiceProvider.GetService(typeof(IMenuCommandService)) as OleMenuCommandService; if (commandService != null) { CommandID menuCommandID = new CommandID(MenuGroup, CommandId); EventHandler eventHandler = this.ShowMessageBox; MenuCommand menuItem = new MenuCommand(eventHandler, menuCommandID); commandService.AddCommand(menuItem); } // get a reference to the Output window output = (IVsOutputWindowPane)ServiceProvider.GetService(typeof(SVsGeneralOutputWindowPane)); }
Hapus kode yang ada dari
ShowMessageBox
metode :private void ShowMessageBox(object sender, EventArgs e) { }
Dapatkan objek DTE, yang akan kita gunakan untuk beberapa tujuan berbeda dalam panduan ini. Selain itu, pastikan solusi dimuat saat tombol menu diklik.
private void ShowMessageBox(object sender, EventArgs e) { var dte = (EnvDTE.DTE)this.ServiceProvider.GetService(typeof(EnvDTE.DTE)); if (dte.Solution != null) { . . . } else { MessageBox.Show("No solution is open"); return; } }
Temukan proyek bersama. Proyek bersama adalah kontainer murni; tidak membangun atau menghasilkan output. Metode berikut menemukan proyek bersama pertama dalam solusi dengan mencari IVsHierarchy objek yang memiliki kemampuan proyek bersama.
private IVsHierarchy FindSharedProject() { var sln = (IVsSolution)this.ServiceProvider.GetService(typeof(SVsSolution)); Guid empty = Guid.Empty; IEnumHierarchies enumHiers; //get all the projects in the solution ErrorHandler.ThrowOnFailure(sln.GetProjectEnum((uint)__VSENUMPROJFLAGS.EPF_LOADEDINSOLUTION, ref empty, out enumHiers)); foreach (IVsHierarchy hier in ComUtilities.EnumerableFrom(enumHiers)) { if (PackageUtilities.IsCapabilityMatch(hier, "SharedAssetsProject")) { return hier; } } return null; }
Dalam metode ,
ShowMessageBox
keluarkan keterangan (nama proyek yang muncul di Penjelajah Solusi) proyek bersama.private void ShowMessageBox(object sender, EventArgs e) { var dte = (DTE)this.ServiceProvider.GetService(typeof(DTE)); if (dte.Solution != null) { var sharedHier = this.FindSharedProject(); if (sharedHier != null) { string sharedCaption = HierarchyUtilities.GetHierarchyProperty<string>(sharedHier, (uint)VSConstants.VSITEMID.Root, (int)__VSHPROPID.VSHPROPID_Caption); output.OutputStringThreadSafe(string.Format("Found shared project: {0}\n", sharedCaption)); } else { MessageBox.Show("Solution has no shared project"); return; } } else { MessageBox.Show("No solution is open"); return; } }
Dapatkan proyek platform aktif. Proyek platform adalah proyek yang berisi kode dan sumber daya khusus platform. Metode berikut menggunakan bidang VSHPROPID_SharedItemContextHierarchy baru untuk mendapatkan proyek platform aktif.
private IVsHierarchy GetActiveProjectContext(IVsHierarchy hierarchy) { IVsHierarchy activeProjectContext; if (HierarchyUtilities.TryGetHierarchyProperty(hierarchy, (uint)VSConstants.VSITEMID.Root, (int)__VSHPROPID7.VSHPROPID_SharedItemContextHierarchy, out activeProjectContext)) { return activeProjectContext; } else { return null; } }
Dalam metode ,
ShowMessageBox
keluarkan keterangan proyek platform aktif.private void ShowMessageBox(object sender, EventArgs e) { var dte = (DTE)this.ServiceProvider.GetService(typeof(DTE)); if (dte.Solution != null) { var sharedHier = this.FindSharedProject(); if (sharedHier != null) { string sharedCaption = HierarchyUtilities.GetHierarchyProperty<string>(sharedHier, (uint)VSConstants.VSITEMID.Root, (int)__VSHPROPID.VSHPROPID_Caption); output.OutputStringThreadSafe(string.Format("Shared project: {0}\n", sharedCaption)); var activePlatformHier = this.GetActiveProjectContext(sharedHier); if (activePlatformHier != null) { string activeCaption = HierarchyUtilities.GetHierarchyProperty<string>(activePlatformHier, (uint)VSConstants.VSITEMID.Root, (int)__VSHPROPID.VSHPROPID_Caption); output.OutputStringThreadSafe(string.Format("Active platform project: {0}\n", activeCaption)); } else { MessageBox.Show("Shared project has no active platform project"); } } else { MessageBox.Show("Solution has no shared project"); } } else { MessageBox.Show("No solution is open"); } }
Iterasi melalui proyek platform. Metode berikut mendapatkan semua proyek impor (platform) dari proyek bersama.
private IEnumerable<IVsHierarchy> EnumImportingProjects(IVsHierarchy hierarchy) { IVsSharedAssetsProject sharedAssetsProject; if (HierarchyUtilities.TryGetHierarchyProperty(hierarchy, (uint)VSConstants.VSITEMID.Root, (int)__VSHPROPID7.VSHPROPID_SharedAssetsProject, out sharedAssetsProject) && sharedAssetsProject != null) { foreach (IVsHierarchy importingProject in sharedAssetsProject.EnumImportingProjects()) { yield return importingProject; } } }
Penting
Jika pengguna telah membuka proyek aplikasi Windows universal C++ dalam instans eksperimental, kode di atas akan memberikan pengecualian. Ini adalah masalah yang sudah diketahui. Untuk menghindari pengecualian, ganti blok di
foreach
atas dengan yang berikut:var importingProjects = sharedAssetsProject.EnumImportingProjects(); for (int i = 0; i < importingProjects.Count; ++i) { yield return importingProjects[i]; }
Dalam metode ini
ShowMessageBox
, keluarkan keterangan setiap proyek platform. Masukkan kode berikut setelah baris yang menghasilkan keterangan proyek platform aktif. Hanya proyek platform yang dimuat yang muncul dalam daftar ini.output.OutputStringThreadSafe("Platform projects:\n"); IEnumerable<IVsHierarchy> projects = this.EnumImportingProjects(sharedHier); bool isActiveProjectSet = false; foreach (IVsHierarchy platformHier in projects) { string platformCaption = HierarchyUtilities.GetHierarchyProperty<string>(platformHier, (uint)VSConstants.VSITEMID.Root, (int)__VSHPROPID.VSHPROPID_Caption); output.OutputStringThreadSafe(string.Format(" * {0}\n", platformCaption)); }
Ubah proyek platform aktif. Metode berikut mengatur proyek aktif menggunakan SetProperty.
private int SetActiveProjectContext(IVsHierarchy hierarchy, IVsHierarchy activeProjectContext) { return hierarchy.SetProperty((uint)VSConstants.VSITEMID.Root, (int)__VSHPROPID7.VSHPROPID_SharedItemContextHierarchy, activeProjectContext); }
Dalam metode ini
ShowMessageBox
, ubah proyek platform aktif. Masukkan kode ini keforeach
dalam blok.bool isActiveProjectSet = false; string platformCaption = null; foreach (IVsHierarchy platformHier in projects) { platformCaption = HierarchyUtilities.GetHierarchyProperty<string>(platformHier, (uint)VSConstants.VSITEMID.Root, (int)__VSHPROPID.VSHPROPID_Caption); output.OutputStringThreadSafe(string.Format(" * {0}\n", platformCaption)); // if this project is neither the shared project nor the current active platform project, // set it to be the active project if (!isActiveProjectSet && platformHier != activePlatformHier) { this.SetActiveProjectContext(sharedHier, platformHier); activePlatformHier = platformHier; isActiveProjectSet = true; } } output.OutputStringThreadSafe("set active project: " + platformCaption +'\n');
Sekarang cobalah. Tekan F5 untuk meluncurkan instans eksperimental. Buat proyek aplikasi hub universal C# di instans eksperimental (dalam kotak dialog Proyek Baru, Aplikasi Universal>Hub Visual C#>Windows>Windows 8).> Setelah solusi dimuat, buka menu Alat dan klik Panggil TestUniversalProject, lalu periksa teks di panel Output . Anda akan melihat seperti berikut ini:
Found shared project: HubApp.Shared The active platform project: HubApp.Windows Platform projects: * HubApp.Windows * HubApp.WindowsPhone set active project: HubApp.WindowsPhone
Mengelola item bersama dalam proyek platform
Temukan item bersama dalam proyek platform. Item dalam proyek bersama muncul di proyek platform sebagai item bersama. Anda tidak dapat melihatnya di Penjelajah Solusi, tetapi Anda dapat berjalan hierarki proyek untuk menemukannya. Metode berikut ini memandu hierarki dan mengumpulkan semua item bersama. Ini secara opsional menghasilkan keterangan dari setiap item, . Item bersama diidentifikasi oleh properti VSHPROPID_IsSharedItembaru .
private void InspectHierarchyItems(IVsHierarchy hier, uint itemid, int level, List<uint> itemIds, bool getSharedItems, bool printItems) { string caption = HierarchyUtilities.GetHierarchyProperty<string>(hier, itemid, (int)__VSHPROPID.VSHPROPID_Caption); if (printItems) output.OutputStringThreadSafe(string.Format("{0}{1}\n", new string('\t', level), caption)); // if getSharedItems is true, inspect only shared items; if it's false, inspect only unshared items bool isSharedItem; if (HierarchyUtilities.TryGetHierarchyProperty(hier, itemid, (int)__VSHPROPID7.VSHPROPID_IsSharedItem, out isSharedItem) && (isSharedItem == getSharedItems)) { itemIds.Add(itemid); } uint child; if (HierarchyUtilities.TryGetHierarchyProperty(hier, itemid, (int)__VSHPROPID.VSHPROPID_FirstChild, Unbox.AsUInt32, out child) && child != (uint)VSConstants.VSITEMID.Nil) { this.InspectHierarchyItems(hier, child, level + 1, itemIds, isSharedItem, printItems); while (HierarchyUtilities.TryGetHierarchyProperty(hier, child, (int)__VSHPROPID.VSHPROPID_NextSibling, Unbox.AsUInt32, out child) && child != (uint)VSConstants.VSITEMID.Nil) { this.InspectHierarchyItems(hier, child, level + 1, itemIds, isSharedItem, printItems); } } }
Dalam metode ,
ShowMessageBox
tambahkan kode berikut untuk memanjakan item hierarki proyek platform. Masukkan ke dalamforeach
blok.output.OutputStringThreadSafe("Walk the active platform project:\n"); var sharedItemIds = new List<uint>(); this.InspectHierarchyItems(activePlatformHier, (uint)VSConstants.VSITEMID.Root, 1, sharedItemIds, true, true);
Baca item bersama. Item bersama muncul dalam proyek platform sebagai file tertaut tersembunyi, dan Anda dapat membaca semua properti sebagai file tertaut biasa. Kode berikut membaca jalur lengkap item bersama pertama.
var sharedItemId = sharedItemIds[0]; string fullPath; ErrorHandler.ThrowOnFailure(((IVsProject)activePlatformHier).GetMkDocument(sharedItemId, out fullPath)); output.OutputStringThreadSafe(string.Format("Shared item full path: {0}\n", fullPath));
Sekarang cobalah. Tekan F5 untuk meluncurkan instans eksperimental. Buat proyek aplikasi hub universal C# di instans eksperimental (dalam kotak dialog Proyek Baru, Aplikasi Universal>Hub Visual C#>Windows>Windows 8>) masuk ke menu Alat dan klik Panggil TestUniversalProject, lalu periksa teks di panel Output. Anda akan melihat seperti berikut ini:
Found shared project: HubApp.Shared The active platform project: HubApp.Windows Platform projects: * HubApp.Windows * HubApp.WindowsPhone set active project: HubApp.WindowsPhone Walk the active platform project: HubApp.WindowsPhone <HubApp.Shared> App.xaml App.xaml.cs Assets DarkGray.png LightGray.png MediumGray.png Common NavigationHelper.cs ObservableDictionary.cs RelayCommand.cs SuspensionManager.cs DataModel SampleData.json SampleDataSource.cs HubApp.Shared.projitems Strings en-US Resources.resw Assets HubBackground.theme-dark.png HubBackground.theme-light.png Logo.scale-240.png SmallLogo.scale-240.png SplashScreen.scale-240.png Square71x71Logo.scale-240.png StoreLogo.scale-240.png WideLogo.scale-240.png HubPage.xaml HubPage.xaml.cs ItemPage.xaml ItemPage.xaml.cs Package.appxmanifest Properties AssemblyInfo.cs References .NET for Windows Store apps HubApp.Shared Windows Phone 8.1 SectionPage.xaml SectionPage.xaml.cs
Mendeteksi perubahan dalam proyek platform dan proyek bersama
Anda dapat menggunakan hierarki dan peristiwa proyek untuk mendeteksi perubahan dalam proyek bersama, seperti yang Anda bisa untuk proyek platform. Namun, item proyek dalam proyek bersama tidak terlihat, yang berarti bahwa peristiwa tertentu tidak diaktifkan saat item proyek bersama diubah.
Pertimbangkan urutan peristiwa saat file dalam proyek diganti namanya:
Nama file diubah pada disk.
File proyek diperbarui untuk menyertakan nama baru file.
Peristiwa hierarki (misalnya, IVsHierarchyEvents) umumnya melacak perubahan yang ditampilkan di UI, seperti dalam Penjelajah Solusi. Peristiwa hierarki mempertimbangkan operasi penggantian nama file untuk terdiri dari penghapusan file lalu penambahan file. Namun, ketika item yang tidak terlihat diubah, sistem peristiwa hierarki menembakkan OnItemDeleted peristiwa tetapi bukan peristiwa OnItemAdded . Oleh karena itu, jika Anda mengganti nama file dalam proyek platform, Anda mendapatkan dan OnItemDeletedOnItemAdded, tetapi jika Anda mengganti nama file dalam proyek bersama, Anda hanya OnItemDeletedmendapatkan .
Untuk melacak perubahan dalam item proyek, Anda dapat menangani peristiwa item proyek DTE (yang ditemukan di ProjectItemsEventsClass). Namun, jika Anda menangani sejumlah besar peristiwa, Anda bisa mendapatkan performa yang lebih baik menangani peristiwa di IVsTrackProjectDocuments2. Dalam panduan ini, kami hanya menampilkan peristiwa hierarki dan peristiwa DTE. Dalam prosedur ini Anda menambahkan pendengar peristiwa ke proyek bersama dan proyek platform. Kemudian, ketika Anda mengganti nama satu file dalam proyek bersama dan file lain dalam proyek platform, Anda dapat melihat peristiwa yang diaktifkan untuk setiap operasi penggantian nama.
Dalam prosedur ini Anda menambahkan pendengar peristiwa ke proyek bersama dan proyek platform. Kemudian, ketika Anda mengganti nama satu file dalam proyek bersama dan file lain dalam proyek platform, Anda dapat melihat peristiwa yang diaktifkan untuk setiap operasi penggantian nama.
Tambahkan pendengar peristiwa. Tambahkan file kelas baru ke proyek dan sebut saja HierarchyEventListener.cs.
Buka file HierarchyEventListener.cs dan tambahkan yang berikut ini menggunakan direktif:
using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio; using System.IO;
Memiliki kelas mengimplementasikan
HierarchyEventListener
IVsHierarchyEvents:class HierarchyEventListener : IVsHierarchyEvents { }
Terapkan anggota IVsHierarchyEvents, seperti pada kode di bawah ini.
class HierarchyEventListener : IVsHierarchyEvents { private IVsHierarchy hierarchy; IVsOutputWindowPane output; internal HierarchyEventListener(IVsHierarchy hierarchy, IVsOutputWindowPane outputWindow) { this.hierarchy = hierarchy; this.output = outputWindow; } int IVsHierarchyEvents.OnInvalidateIcon(IntPtr hIcon) { return VSConstants.S_OK; } int IVsHierarchyEvents.OnInvalidateItems(uint itemIDParent) { return VSConstants.S_OK; } int IVsHierarchyEvents.OnItemAdded(uint itemIDParent, uint itemIDSiblingPrev, uint itemIDAdded) { output.OutputStringThreadSafe("IVsHierarchyEvents.OnItemAdded: " + itemIDAdded + "\n"); return VSConstants.S_OK; } int IVsHierarchyEvents.OnItemDeleted(uint itemID) { output.OutputStringThreadSafe("IVsHierarchyEvents.OnItemDeleted: " + itemID + "\n"); return VSConstants.S_OK; } int IVsHierarchyEvents.OnItemsAppended(uint itemIDParent) { output.OutputStringThreadSafe("IVsHierarchyEvents.OnItemsAppended\n"); return VSConstants.S_OK; } int IVsHierarchyEvents.OnPropertyChanged(uint itemID, int propID, uint flags) { output.OutputStringThreadSafe("IVsHierarchyEvents.OnPropertyChanged: item ID " + itemID + "\n"); return VSConstants.S_OK; } }
Di kelas yang sama tambahkan penanganan aktivitas lain untuk peristiwa ItemRenamedDTE , yang terjadi setiap kali item proyek diganti namanya.
public void OnItemRenamed(EnvDTE.ProjectItem projItem, string oldName) { output.OutputStringThreadSafe(string.Format("[Event] Renamed {0} to {1} in project {2}\n", oldName, Path.GetFileName(projItem.get_FileNames(1)), projItem.ContainingProject.Name)); }
Daftar untuk peristiwa hierarki. Anda perlu mendaftar secara terpisah untuk setiap proyek yang Anda lacak. Tambahkan kode berikut di
ShowMessageBox
, satu untuk proyek bersama, dan yang lainnya untuk salah satu proyek platform.// hook up the event listener for hierarchy events on the shared project HierarchyEventListener listener1 = new HierarchyEventListener(sharedHier, output); uint cookie1; sharedHier.AdviseHierarchyEvents(listener1, out cookie1); // hook up the event listener for hierarchy events on the active project HierarchyEventListener listener2 = new HierarchyEventListener(activePlatformHier, output); uint cookie2; activePlatformHier.AdviseHierarchyEvents(listener2, out cookie2);
Daftar untuk peristiwa ItemRenameditem proyek DTE . Tambahkan kode berikut setelah Anda menghubungkan listener kedua.
// hook up DTE events for project items Events2 dteEvents = (Events2)dte.Events; dteEvents.ProjectItemsEvents.ItemRenamed += listener1.OnItemRenamed;
Ubah item bersama. Anda tidak dapat mengubah item bersama dalam proyek platform; sebagai gantinya, Anda harus mengubahnya dalam proyek bersama yang merupakan pemilik sebenarnya dari item ini. Anda bisa mendapatkan ID item yang sesuai di proyek bersama dengan IsDocumentInProject, memberinya jalur lengkap item bersama. Kemudian Anda dapat mengubah item bersama. Perubahan disebarluaskan ke proyek platform.
Penting
Anda harus mencari tahu apakah item proyek adalah item bersama atau tidak sebelum mengubahnya.
Metode berikut memodifikasi nama file item proyek.
private void ModifyFileNameInProject(IVsHierarchy project, string path) { int found; uint projectItemID; VSDOCUMENTPRIORITY[] priority = new VSDOCUMENTPRIORITY[1]; if (ErrorHandler.Succeeded(((IVsProject)project).IsDocumentInProject(path, out found, priority, out projectItemID)) && found != 0) { var name = DateTime.Now.Ticks.ToString() + Path.GetExtension(path); project.SetProperty(projectItemID, (int)__VSHPROPID.VSHPROPID_EditLabel, name); output.OutputStringThreadSafe(string.Format("Renamed {0} to {1}\n", path,name)); } }
Panggil metode ini setelah semua kode lain masuk
ShowMessageBox
untuk mengubah nama file item dalam proyek bersama. Sisipkan ini setelah kode yang mendapatkan jalur lengkap item dalam proyek bersama.// change the file name of an item in a shared project this.InspectHierarchyItems(activePlatformHier, (uint)VSConstants.VSITEMID.Root, 1, sharedItemIds, true, true); ErrorHandler.ThrowOnFailure(((IVsProject)activePlatformHier).GetMkDocument(sharedItemId, out fullPath)); output.OutputStringThreadSafe(string.Format("Shared project item ID = {0}, full path = {1}\n", sharedItemId, fullPath)); this.ModifyFileNameInProject(sharedHier, fullPath);
Buat dan jalankan proyek. Buat aplikasi hub universal C# di instans eksperimental, buka menu Alat dan klik Panggil TestUniversalProject, dan periksa teks di panel output umum. Nama item pertama dalam proyek bersama (kami mengharapkannya menjadi file App.xaml ) harus diubah, dan Anda akan melihat bahwa ItemRenamed peristiwa telah diaktifkan. Dalam hal ini, karena mengganti nama App.xaml menyebabkan App.xaml.cs juga diganti namanya, Anda akan melihat empat peristiwa (dua untuk setiap proyek platform). (Peristiwa DTE tidak melacak item dalam proyek bersama.) Anda akan melihat dua OnItemDeleted peristiwa (satu untuk setiap proyek platform), tetapi tidak ada OnItemAdded peristiwa.
Sekarang coba ganti nama file dalam proyek platform, dan Anda dapat melihat perbedaan dalam peristiwa yang ditembakkan. Tambahkan kode berikut setelah
ShowMessageBox
panggilan keModifyFileName
.// change the file name of an item in a platform project var unsharedItemIds = new List<uint>(); this.InspectHierarchyItems(activePlatformHier, (uint)VSConstants.VSITEMID.Root, 1, unsharedItemIds, false, false); var unsharedItemId = unsharedItemIds[0]; string unsharedPath; ErrorHandler.ThrowOnFailure(((IVsProject)activePlatformHier).GetMkDocument(unsharedItemId, out unsharedPath)); output.OutputStringThreadSafe(string.Format("Platform project item ID = {0}, full path = {1}\n", unsharedItemId, unsharedPath)); this.ModifyFileNameInProject(activePlatformHier, unsharedPath);
Buat dan jalankan proyek. Buat Proyek Universal C# di instans eksperimental, buka menu Alat dan klik Panggil TestUniversalProject, dan periksa teks di panel output umum. Setelah file dalam proyek platform diganti namanya, Anda akan melihat OnItemAdded peristiwa dan OnItemDeleted peristiwa. Karena mengubah file tidak menyebabkan file lain diubah, dan karena perubahan pada item dalam proyek platform tidak disebarluaskan di mana pun, hanya ada satu dari masing-masing peristiwa ini.