Správa univerzálních projektů Windows
Univerzální aplikace pro Windows jsou aplikace, které cílí na Windows 8.1 i Windows Telefon 8.1, což vývojářům umožňuje používat kód a další prostředky na obou platformách. Sdílený kód a zdroje se uchovávají ve sdíleném projektu, zatímco kód a zdroje specifické pro platformu se uchovávají v samostatných projektech, jeden pro Windows a druhý pro Windows Telefon. Další informace o univerzálních aplikacích pro Windows najdete v tématu Univerzální aplikace pro Windows. Rozšíření sady Visual Studio, která spravují projekty, by měla vědět, že univerzální projekty aplikací pro Windows mají strukturu, která se liší od aplikací s jednou platformou. V tomto názorném postupu se dozvíte, jak procházet sdílený projekt a spravovat sdílené položky.
Navigace ve sdíleném projektu
Vytvořte projekt VSIX jazyka C# s názvem TestUniversalProject. (Soubor>nový>projekt a potom C#>Extensibility>Visual Studio Package). Přidejte šablonu vlastní položky projektu příkazu (na Průzkumník řešení klikněte pravým tlačítkem myši na uzel projektu a vyberte Přidat>novou položku a přejděte na Rozšiřitelnost). Pojmenujte soubor TestUniversalProject.
Přidejte odkaz na Microsoft.VisualStudio.Shell.Interop.12.1.DesignTime.dll a Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.dll (v části Rozšíření).
Otevřete TestUniversalProject.cs a přidejte následující
using
direktivy: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
Do třídy přidejte soukromé pole odkazující na okno Výstup.public sealed class TestUniversalProject { IVsOutputWindowPane output; . . . }
Nastavte odkaz na výstupní podokno uvnitř konstruktoru 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)); }
Odeberte existující kód z
ShowMessageBox
metody:private void ShowMessageBox(object sender, EventArgs e) { }
Získejte objekt DTE, který použijeme pro několik různých účelů v tomto názorném postupu. Také se ujistěte, že je při kliknutí na tlačítko nabídky načteno řešení.
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; } }
Najděte sdílený projekt. Sdílený projekt je čistý kontejner; nevytvářejí ani nevytvářejí výstupy. Následující metoda najde první sdílený projekt v řešení vyhledáním objektu IVsHierarchy , který má schopnost sdíleného projektu.
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; }
ShowMessageBox
V metodě zadejte výstup popis (název projektu, který se zobrazí v Průzkumník řešení) sdíleného projektu.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; } }
Získejte aktivní projekt platformy. Projekty platformy jsou projekty, které obsahují kód a prostředky specifické pro platformu. Následující metoda používá nové pole VSHPROPID_SharedItemContextHierarchy k získání aktivního projektu platformy.
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; } }
ShowMessageBox
V metodě zadejte výstup popis aktivního projektu platformy.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"); } }
Iterujte projekty platformy. Následující metoda získá všechny projekty importu (platformy) ze sdíleného projektu.
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; } } }
Důležité
Pokud uživatel otevřel projekt univerzální aplikace C++ pro Windows v experimentální instanci, vyvolá výše uvedený kód výjimku. Jedná se o známý problém. Pokud se chcete výjimce vyhnout, nahraďte
foreach
výše uvedený blok následujícím kódem:var importingProjects = sharedAssetsProject.EnumImportingProjects(); for (int i = 0; i < importingProjects.Count; ++i) { yield return importingProjects[i]; }
ShowMessageBox
V metodě zadejte výstup popis každého projektu platformy. Za řádek, který vypíše popis aktivního projektu platformy, vložte následující kód. V tomto seznamu se zobrazí pouze projekty platformy, které jsou načteny.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)); }
Změňte aktivní projekt platformy. Následující metoda nastaví aktivní projekt pomocí SetProperty.
private int SetActiveProjectContext(IVsHierarchy hierarchy, IVsHierarchy activeProjectContext) { return hierarchy.SetProperty((uint)VSConstants.VSITEMID.Root, (int)__VSHPROPID7.VSHPROPID_SharedItemContextHierarchy, activeProjectContext); }
ShowMessageBox
V metodě změňte aktivní projekt platformy. Vložte tento kód doforeach
bloku.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');
Teď to zkuste. Stisknutím klávesy F5 spusťte experimentální instanci. Vytvořte projekt aplikace univerzálního centra C# v experimentální instanci (v dialogovém okně Nový projekt, aplikace Visual C#>Windows Windows>8>Universal>Hub). Po načtení řešení přejděte do nabídky Nástroje a klepněte na tlačítko Invoke TestUniversalProject a pak zkontrolujte text v podokně Výstup . Mělo by se zobrazit něco podobného:
Found shared project: HubApp.Shared The active platform project: HubApp.Windows Platform projects: * HubApp.Windows * HubApp.WindowsPhone set active project: HubApp.WindowsPhone
Správa sdílených položek v projektu platformy
Najděte sdílené položky v projektu platformy. Položky ve sdíleném projektu se zobrazí v projektu platformy jako sdílené položky. V Průzkumník řešení je nevidíte, ale můžete je vyhledat v hierarchii projektu. Následující metoda provede hierarchii a shromažďuje všechny sdílené položky. Volitelně vypíše popis každé položky. Sdílené položky jsou identifikovány novou vlastností VSHPROPID_IsSharedItem.
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); } } }
ShowMessageBox
V metodě přidejte následující kód, který provede položky hierarchie projektů platformy. Vložte ho doforeach
bloku.output.OutputStringThreadSafe("Walk the active platform project:\n"); var sharedItemIds = new List<uint>(); this.InspectHierarchyItems(activePlatformHier, (uint)VSConstants.VSITEMID.Root, 1, sharedItemIds, true, true);
Přečtěte si sdílené položky. Sdílené položky se v projektu platformy zobrazí jako skryté propojené soubory a všechny vlastnosti můžete číst jako běžné propojené soubory. Následující kód přečte úplnou cestu první sdílené položky.
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));
Teď to zkuste. Stisknutím klávesy F5 spusťte experimentální instanci. V experimentální instanci vytvořte projekt aplikace univerzálního centra jazyka C# (v dialogovém okně Nový projekt, Visual C#>Windows Windows>8>Universal>Hub App) přejděte do nabídky Nástroje a klikněte na Vyvolat testUniversalProject a potom zkontrolujte text v podokně Výstup. Mělo by se zobrazit něco podobného:
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
Detekce změn v projektech platformy a sdílených projektech
Pomocí hierarchie a událostí projektu můžete detekovat změny ve sdílených projektech stejně jako u projektů platformy. Položky projektu ve sdíleném projektu však nejsou viditelné, což znamená, že se určité události neaktivují při změně sdílených položek projektu.
Při přejmenování souboru v projektu zvažte posloupnost událostí:
Název souboru se změní na disku.
Soubor projektu se aktualizuje tak, aby zahrnoval nový název souboru.
Události hierarchie (napříkladIVsHierarchyEvents) obecně sledují změny zobrazené v uživatelském rozhraní, jako v Průzkumník řešení. Události hierarchie považují operaci přejmenování souboru, která se skládá z odstranění souboru a následného přidání souboru. Pokud se však změní neviditelné položky, systém událostí hierarchie aktivuje OnItemDeleted událost, ale ne OnItemAdded událost. Proto pokud přejmenujete soubor v projektu platformy, získáte obojí OnItemDeleted a OnItemAdded, ale pokud přejmenujete soubor ve sdíleném projektu, získáte pouze OnItemDeleted.
Pokud chcete sledovat změny v položkách projektu, můžete zpracovat události položek projektu DTE (ty, které najdete v ProjectItemsEventsClasstématu). Pokud ale zpracováváte velký počet událostí, můžete dosáhnout lepšího výkonu zpracování událostí v IVsTrackProjectDocuments2. V tomto názorném postupu zobrazujeme pouze události hierarchie a události DTE. V tomto postupu přidáte naslouchací proces událostí do sdíleného projektu a projektu platformy. Když pak přejmenujete jeden soubor ve sdíleném projektu a jiném souboru v projektu platformy, uvidíte události, které se aktivují pro každou operaci přejmenování.
V tomto postupu přidáte naslouchací proces událostí do sdíleného projektu a projektu platformy. Když pak přejmenujete jeden soubor ve sdíleném projektu a jiném souboru v projektu platformy, uvidíte události, které se aktivují pro každou operaci přejmenování.
Přidejte naslouchací proces událostí. Přidejte do projektu nový soubor třídy a zavolejte ho HierarchyEventListener.cs.
Otevřete soubor HierarchyEventListener.cs a přidejte následující direktivy using:
using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio; using System.IO;
Mít třídu implementovat
HierarchyEventListener
IVsHierarchyEvents:class HierarchyEventListener : IVsHierarchyEvents { }
Implementujte členy , IVsHierarchyEventsstejně jako v kódu níže.
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; } }
Ve stejné třídě přidejte další obslužnou rutinu události pro událost ItemRenamedDTE, ke které dochází při každém přejmenování položky projektu.
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)); }
Zaregistrujte se k událostem hierarchie. Musíte se zaregistrovat samostatně pro každý projekt, který sledujete. Do souboru , jeden pro sdílený projekt a druhý pro jeden z projektů platformy přidejte následující kód
ShowMessageBox
.// 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);
Zaregistrujte se k události ItemRenamedpoložky projektu DTE . Po připojení druhého naslouchacího procesu přidejte následující kód.
// hook up DTE events for project items Events2 dteEvents = (Events2)dte.Events; dteEvents.ProjectItemsEvents.ItemRenamed += listener1.OnItemRenamed;
Upravte sdílenou položku. Sdílené položky v projektu platformy nelze upravovat; místo toho je nutné upravit ve sdíleném projektu, který je skutečným vlastníkem těchto položek. Můžete získat odpovídající ID položky ve sdíleném projektu a IsDocumentInProjectdát jí úplnou cestu ke sdílené položce. Sdílenou položku pak můžete upravit. Změna se rozšíří do projektů platformy.
Důležité
Před úpravou položky projektu byste měli zjistit, jestli je položka projektu sdílenou položkou.
Následující metoda upraví název souboru položky projektu.
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)); } }
Zavolat tuto metodu za všechny ostatní kód
ShowMessageBox
změnit název souboru položky ve sdíleném projektu. Vložte tento kód za kód, který získá úplnou cestu k položce ve sdíleném projektu.// 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);
Sestavte a spusťte projekt. V experimentální instanci vytvořte univerzální aplikaci centra jazyka C#, přejděte do nabídky Nástroje a klikněte na Invoke TestUniversalProject a zkontrolujte text v obecném podokně výstupu. Název první položky ve sdíleném projektu (očekáváme, že se jedná o soubor App.xaml ), by se měl změnit a měli byste vidět, že ItemRenamed se událost aktivovala. V tomto případě, protože přejmenování App.xaml způsobí přejmenování app.xaml.cs , měli byste vidět čtyři události (dva pro každý projekt platformy). (Události DTE nesledují položky ve sdíleném projektu.) Měly by se zobrazit dvě OnItemDeleted události (jedna pro každý z projektů platformy), ale žádné OnItemAdded události.
Teď zkuste přejmenovat soubor v projektu platformy a uvidíte rozdíl v událostech, které se aktivují. Přidejte následující kód
ShowMessageBox
za volání .ModifyFileName
// 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);
Sestavte a spusťte projekt. V experimentální instanci vytvořte univerzální projekt jazyka C#, přejděte do nabídky Nástroje a klikněte na Invoke TestUniversalProject a zkontrolujte text v obecném podokně výstupu. Po přejmenování souboru v projektu platformy by se měla zobrazit OnItemAdded událost i OnItemDeleted událost. Vzhledem k tomu, že změna souboru způsobila, že se nezměnily žádné jiné soubory, a protože změny položek v projektu platformy se nikde nešířily, existuje pouze jedna z těchto událostí.