Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Universella Windows-appar är appar som riktar sig till både Windows 8.1 och Windows Phone 8.1, vilket gör det möjligt för utvecklare att använda kod och andra tillgångar på båda plattformarna. Den delade koden och resurserna sparas i ett delat projekt, medan den plattformsspecifika koden och resurserna sparas i separata projekt, en för Windows och den andra för Windows Phone. Mer information om universella Windows-appar finns i Universella Windows-appar. Visual Studio-tillägg som hanterar projekt bör vara medvetna om att universella Windows-appprojekt har en struktur som skiljer sig från appar med en plattform. Den här genomgången visar hur du navigerar i det delade projektet och hanterar de delade objekten.
Navigera i det delade projektet
Skapa ett C#VSIX-projekt med namnet TestUniversalProject. (Fil>Ny>Project och sedan C#>Extensibility>Visual Studio Package). Lägg till en projektobjektmall för anpassat kommando (högerklicka på projektnoden i Solution Explorer och välj Lägg till>nytt objekt och gå sedan till Utökningsbarhet). Ge filen namnet TestUniversalProject.
Lägg till en referens till Microsoft.VisualStudio.Shell.Interop.12.1.DesignTime.dll och Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.dll (i avsnittet Tillägg ).
Öppna TestUniversalProject.cs och lägg till följande
usingdirektiv: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;I klassen
TestUniversalProjectlägger du till ett privat fält som pekar på utdatafönstret .public sealed class TestUniversalProject { IVsOutputWindowPane output; . . . }Ange referensen till utdatafönstret i konstruktorn 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)); }Ta bort den befintliga koden från
ShowMessageBoxmetoden:private void ShowMessageBox(object sender, EventArgs e) { }Hämta DTE-objektet, som vi kommer att använda för flera olika syften i den här genomgången. Kontrollera också att en lösning läses in när menyknappen klickas.
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; } }Hitta det delade projektet. Det delade projektet är en ren container. den skapar eller producerar inte utdata. Följande metod hittar det första delade projektet i lösningen genom att leta efter objektet IVsHierarchy som har funktionen delat projekt.
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; }ShowMessageBoxI -metoden matar du ut undertexten (projektnamnet som visas i Solution Explorer) för det delade projektet.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; } }Hämta det aktiva plattformsprojektet. Plattformsprojekt är de projekt som innehåller plattformsspecifik kod och resurser. Följande metod använder det nya fältet VSHPROPID_SharedItemContextHierarchy för att hämta det aktiva plattformsprojektet.
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; } }ShowMessageBoxI -metoden matar du ut beskrivningen av det aktiva plattformsprojektet.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"); } }Iterera genom plattformsprojekten. Följande metod hämtar alla importprojekt (plattform) från det delade projektet.
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; } } }Viktigt!
Om användaren har öppnat ett C++-universellt Windows-appprojekt i den experimentella instansen utlöser koden ovan ett undantag. Det här är ett känt problem. Undvik undantaget genom att
foreachersätta blocket ovan med följande:var importingProjects = sharedAssetsProject.EnumImportingProjects(); for (int i = 0; i < importingProjects.Count; ++i) { yield return importingProjects[i]; }ShowMessageBox-metoden, mata ut rubriken för varje plattformsprojekt. Infoga följande kod efter raden som matar ut beskrivningen av det aktiva plattformsprojektet. Endast de plattformsprojekt som läses in visas i den här listan.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)); }Ändra det aktiva plattformsprojektet. Följande metod anger det aktiva projektet med .SetProperty
private int SetActiveProjectContext(IVsHierarchy hierarchy, IVsHierarchy activeProjectContext) { return hierarchy.SetProperty((uint)VSConstants.VSITEMID.Root, (int)__VSHPROPID7.VSHPROPID_SharedItemContextHierarchy, activeProjectContext); }ShowMessageBoxI metoden ändrar du det aktiva plattformsprojektet. Infoga den här koden iforeachblocket.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');Prova nu. Tryck på F5 för att starta den experimentella instansen. Skapa ett C# universal hub-appprojekt i den experimentella instansen (i dialogrutan Nytt projekt , Visual C#>Windows>Windows 8>Universal>Hub App). När lösningen har lästs in går du till menyn Verktyg och klickar på Anropa TestUniversalProject och kontrollerar sedan texten i fönstret Utdata . Du bör se något som liknar följande:
Found shared project: HubApp.Shared The active platform project: HubApp.Windows Platform projects: * HubApp.Windows * HubApp.WindowsPhone set active project: HubApp.WindowsPhone
Hantera delade objekt i plattformsprojektet
Hitta de delade objekten i plattformsprojektet. Objekten i det delade projektet visas i plattformsprojektet som delade objekt. Du kan inte se dem i Solution Explorer, men du kan gå till projekthierarkin för att hitta dem. Följande metod går igenom hierarkin och samlar in alla delade element. Du kan välja att mata ut etiketten för varje objekt. De delade objekten identifieras av den nya egenskapen 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); } } }ShowMessageBoxI-metoden lägger du till följande kod för att gå igenom projekthierarkiobjekten för plattformen. Infoga den iforeachblocket.output.OutputStringThreadSafe("Walk the active platform project:\n"); var sharedItemIds = new List<uint>(); this.InspectHierarchyItems(activePlatformHier, (uint)VSConstants.VSITEMID.Root, 1, sharedItemIds, true, true);Läs de delade objekten. De delade objekten visas i plattformsprojektet som dolda länkade filer och du kan läsa alla egenskaper som vanliga länkade filer. Följande kod läser den fullständiga sökvägen för det första delade objektet.
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));Prova nu. Tryck på F5 för att starta den experimentella instansen. Skapa ett C#-universellt hubbprogramprojekt i den experimentella instansen (i dialogrutan Nytt projekt går Visual C#>Windows>Windows 8>Universal>Hub App) till menyn Verktyg och klickar på Anropa TestUniversalProject och markerar sedan texten i fönstret Utdata . Du bör se något som liknar följande:
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
Identifiera ändringar i plattformsprojekt och delade projekt
Du kan använda hierarki- och projekthändelser för att identifiera ändringar i delade projekt, precis som för plattformsprojekt. Projektobjekten i det delade projektet visas dock inte, vilket innebär att vissa händelser inte utlöses när delade projektobjekt ändras.
Överväg händelsesekvensen när en fil i ett projekt byter namn:
Filnamnet ändras på disken.
Projektfilen uppdateras så att den innehåller det nya namnet på filen.
Hierarkihändelser (till exempel IVsHierarchyEvents) spårar vanligtvis de ändringar som visas i användargränssnittet, som i Solution Explorer. Hierarkihändelser anser att en filbytesåtgärd består av en filborttagning och sedan ett filtillägg. Men när osynliga objekt ändras utlöser hierarkihändelsesystemet en OnItemDeleted händelse men inte en OnItemAdded händelse. Om du byter namn på en fil i ett plattformsprojekt får du därför både OnItemDeleted och OnItemAdded, men om du byter namn på en fil i ett delat projekt får du bara OnItemDeleted.
Om du vill spåra ändringar i projektobjekt kan du hantera DTE-projektobjekthändelser (de som finns i ProjectItemsEventsClass). Men om du hanterar ett stort antal händelser kan du få bättre prestanda när du hanterar händelserna i IVsTrackProjectDocuments2. I den här genomgången visar vi bara hierarkihändelserna och DTE-händelserna. I den här proceduren lägger du till en händelselyssnare i ett delat projekt och ett plattformsprojekt. När du sedan byter namn på en fil i ett delat projekt och en annan fil i ett plattformsprojekt kan du se de händelser som utlöses för varje namnbytesåtgärd.
I den här proceduren lägger du till en händelselyssnare i ett delat projekt och ett plattformsprojekt. När du sedan byter namn på en fil i ett delat projekt och en annan fil i ett plattformsprojekt kan du se de händelser som utlöses för varje namnbytesåtgärd.
Lägg till en händelselyssnare. Lägg till en ny klassfil i projektet och anropa den HierarchyEventListener.cs.
Öppna filen HierarchyEventListener.cs och lägg till följande med hjälp av direktiv:
using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio; using System.IO;HierarchyEventListenerLåt klassen implementera IVsHierarchyEvents:class HierarchyEventListener : IVsHierarchyEvents { }Implementera medlemmarna i IVsHierarchyEvents, som i koden nedan.
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; } }I samma klass lägger du till en annan händelsehanterare för DTE-händelsen ItemRenamed, som inträffar när ett projektobjekt byter namn.
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)); }Registrera dig för hierarkievenemangen. Du måste registrera dig separat för varje projekt som du spårar. Lägg till följande kod i
ShowMessageBox, en för det delade projektet och den andra för ett av plattformsprojekten.// 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);Registrera dig för DTE-projektobjekthändelsen ItemRenamed. Lägg till följande kod när du har kopplat in den andra lyssnaren.
// hook up DTE events for project items Events2 dteEvents = (Events2)dte.Events; dteEvents.ProjectItemsEvents.ItemRenamed += listener1.OnItemRenamed;Ändra det delade objektet. Du kan inte ändra delade objekt i ett plattformsprojekt. I stället måste du ändra dem i det delade projektet som är den faktiska ägaren av dessa objekt. Du kan hämta motsvarande objekt-ID i det delade projektet med IsDocumentInProject, vilket ger det det delade objektets fullständiga sökväg. Sedan kan du ändra det delade objektet. Ändringen sprids till plattformsprojekten.
Viktigt!
Du bör ta reda på om ett projektobjekt är ett delat objekt innan du ändrar det.
Följande metod ändrar namnet på en projektobjektfil.
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)); } }Anropa den här metoden efter all annan kod i
ShowMessageBoxför att ändra filnamnet för objektet i det delade projektet. Infoga detta efter koden som hämtar den fullständiga sökvägen för objektet i det delade projektet.// 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);Skapa och kör projektet. Skapa en universell C#-hubbapp i den experimentella instansen, gå till menyn Verktyg och klicka på Anropa TestUniversalProject och kontrollera texten i fönstret allmänna utdata. Namnet på det första objektet i det delade projektet (vi förväntar oss att det är Filen App.xaml ) bör ändras och du bör se att ItemRenamed händelsen har utlösts. I det här fallet, eftersom byta namn på App.xaml gör att App.xaml.cs också ska byta namn, bör du se fyra händelser (två för varje plattformsprojekt). (DTE-händelser spårar inte objekten i det delade projektet.) Du bör se två OnItemDeleted händelser (en för vart och ett av plattformsprojekten), men inga OnItemAdded händelser.
Försök nu att byta namn på en fil i ett plattformsprojekt, så kan du se skillnaden i de händelser som utlöses. Lägg till följande kod i
ShowMessageBoxefter anropet tillModifyFileName.// 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);Skapa och kör projektet. Skapa ett C#-universellt projekt i den experimentella instansen, gå till menyn Verktyg och klicka på Anropa TestUniversalProject och kontrollera texten i fönstret allmänna utdata. När filen i plattformsprojektet har bytt namn bör du se både en OnItemAdded händelse och en OnItemDeleted händelse. Eftersom ändringen av filen inte påverkade andra filer, och eftersom ändringar av objekt i ett plattformsprojekt inte sprids till andra delar, finns det bara en sådan händelse.