Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Os aplicativos universais do Windows são aplicativos destinados ao Windows 8.1 e ao Windows Phone 8.1, permitindo que os desenvolvedores usem código e outros ativos em ambas as plataformas. O código compartilhado e os recursos são mantidos em um projeto compartilhado, enquanto o código e os recursos específicos da plataforma são mantidos em projetos separados, um para Windows e outro para Windows Phone. Para obter mais informações sobre aplicativos universais do Windows, consulte Aplicativos universais do Windows. As extensões do Visual Studio que gerenciam projetos devem estar cientes de que os projetos de aplicativos universais do Windows têm uma estrutura diferente dos aplicativos de plataforma única. Este passo a passo mostra como navegar no projeto compartilhado e gerenciar os itens compartilhados.
Navegar no projeto compartilhado
Crie um projeto C# VSIX chamado TestUniversalProject. (Arquivo>Novo>Projeto e, em seguida, C#>Extensibilidade>Pacote do Visual Studio). Adicione um modelo de item de projeto Comando Personalizado (no Gerenciador de Soluções, clique com o botão direito do mouse no nó do projeto e selecione Adicionar>Novo Item e vá para Extensibilidade). Nomeie o arquivo TestUniversalProject.
Adicione uma referência a Microsoft.VisualStudio.Shell.Interop.12.1.DesignTime.dll e Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.dll (na seção Extensões ).
Abra TestUniversalProject.cs e adicione as seguintes
usingdiretivas: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;Na classe,
TestUniversalProjectadicione um campo privado apontando para a janela Saída .public sealed class TestUniversalProject { IVsOutputWindowPane output; . . . }Defina a referência para o painel de saída dentro do construtor 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)); }Remova o código existente do
ShowMessageBoxmétodo:private void ShowMessageBox(object sender, EventArgs e) { }Obtenha o objeto DTE, que usaremos para várias finalidades diferentes neste passo a passo. Além disso, certifique-se de que uma solução é carregada quando o botão de menu é clicado.
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; } }Encontre o projeto compartilhado. O projeto compartilhado é um recipiente puro; não constrói nem produz resultados. O método a seguir localiza o primeiro projeto compartilhado na solução procurando o IVsHierarchy objeto que tem a capacidade de projeto compartilhado.
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; }No
ShowMessageBoxmétodo, exiba a legenda (o nome do projeto que aparece no Explorador de Soluções) do projeto compartilhado.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; } }Obtenha o projeto de plataforma ativa. Projetos de plataforma são os projetos que contêm código e recursos específicos da plataforma. O método a seguir usa o novo campo VSHPROPID_SharedItemContextHierarchy para obter o projeto de plataforma ativo.
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; } }No método
ShowMessageBox, exiba a legenda do projeto de plataforma ativa.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"); } }Percorra os projetos da plataforma. O método a seguir obtém todos os projetos de importação (plataforma) do projeto compartilhado.
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; } } }Importante
Se o usuário tiver aberto um projeto de aplicativo universal do Windows em C++ na instância experimental, o código acima lançará uma exceção. Este é um problema conhecido. Para evitar a exceção, substitua o
foreachbloco acima pelo seguinte:var importingProjects = sharedAssetsProject.EnumImportingProjects(); for (int i = 0; i < importingProjects.Count; ++i) { yield return importingProjects[i]; }No método
ShowMessageBox, produza a legenda de cada projeto de plataforma. Insira o código a seguir após a linha que gera a legenda do projeto de plataforma ativo. Apenas os projetos de plataforma que são carregados aparecem nesta lista.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)); }Altere o projeto da plataforma ativa. O método seguinte define o projeto ativo usando SetProperty.
private int SetActiveProjectContext(IVsHierarchy hierarchy, IVsHierarchy activeProjectContext) { return hierarchy.SetProperty((uint)VSConstants.VSITEMID.Root, (int)__VSHPROPID7.VSHPROPID_SharedItemContextHierarchy, activeProjectContext); }No método
ShowMessageBox, altere o projeto de plataforma ativa. Insira este código dentro doforeachbloco .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');Agora experimente. Pressione F5 para iniciar a instância experimental. Crie um projeto de aplicativo de hub universal C# na instância experimental (na caixa de diálogo Novo Projeto , Visual C#>Windows>Windows 8>Universal>Hub App). Depois que a solução for carregada, vá para o menu Ferramentas e clique em Invocar TestUniversalProject e, em seguida, verifique o texto no painel Saída . Você deve ver algo como o seguinte:
Found shared project: HubApp.Shared The active platform project: HubApp.Windows Platform projects: * HubApp.Windows * HubApp.WindowsPhone set active project: HubApp.WindowsPhone
Gerenciar os itens compartilhados no projeto da plataforma
Encontre os itens compartilhados no projeto da plataforma. Os itens no projeto compartilhado aparecem no projeto de plataforma como itens compartilhados. Você não pode vê-los no Gerenciador de Soluções, mas pode percorrer a hierarquia do projeto para localizá-los. O método a seguir percorre a hierarquia e coleta todos os itens compartilhados. Opcionalmente, ele produz a legenda de cada item,. Os itens compartilhados são identificados pela nova propriedade 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); } } }No método
ShowMessageBox, adicione o código a seguir para percorrer os elementos de hierarquia do projeto da plataforma. Insira-o dentro doforeachbloco.output.OutputStringThreadSafe("Walk the active platform project:\n"); var sharedItemIds = new List<uint>(); this.InspectHierarchyItems(activePlatformHier, (uint)VSConstants.VSITEMID.Root, 1, sharedItemIds, true, true);Leia os itens compartilhados. Os itens compartilhados aparecem no projeto da plataforma como arquivos vinculados ocultos, e você pode ler todas as propriedades como arquivos vinculados comuns. O código a seguir lê o caminho completo do primeiro item compartilhado.
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));Agora experimente. Pressione F5 para iniciar a instância experimental. Crie um projeto de aplicativo de hub universal C# na instância experimental (na caixa de diálogo Novo Projeto , Visual C#>Windows>Windows 8>Universal>Hub App) vá para o menu Ferramentas e clique em Invocar TestUniversalProject e, em seguida, verifique o texto no painel Saída . Você deve ver algo como o seguinte:
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
Detetar alterações em projetos de plataforma e projetos compartilhados
Você pode usar eventos de hierarquia e projeto para detetar alterações em projetos compartilhados, assim como pode fazer para projetos de plataforma. No entanto, os itens de projeto no projeto compartilhado não são visíveis, o que significa que certos eventos não são acionados quando os itens de projeto compartilhados são alterados.
Considere a sequência de eventos quando um arquivo em um projeto é renomeado:
O nome do arquivo é alterado no disco.
O arquivo de projeto é atualizado para incluir o novo nome do arquivo.
Os eventos de hierarquia (por exemplo, IVsHierarchyEvents) geralmente controlam as alterações exibidas na interface do usuário, como no Gerenciador de Soluções. Os eventos de hierarquia consideram uma operação de renomeação de arquivo para consistir em uma exclusão de arquivo e, em seguida, uma adição de arquivo. No entanto, quando itens invisíveis são alterados, o sistema de eventos de hierarquia dispara um OnItemDeleted evento, mas não um OnItemAdded evento. Portanto, se você renomear um arquivo em um projeto de plataforma, obterá ambos e OnItemDeletedOnItemAdded, mas se renomear um arquivo em um projeto compartilhado, obterá apenas OnItemDeleted.
Para controlar alterações em itens de projeto, você pode manipular eventos de item de projeto DTE (os encontrados em ProjectItemsEventsClass). No entanto, se você estiver lidando com um grande número de eventos, poderá obter um melhor desempenho ao lidar com os eventos no IVsTrackProjectDocuments2. Neste passo a passo, mostramos apenas os eventos de hierarquia e os eventos DTE. Neste procedimento, você adiciona um ouvinte de eventos a um projeto compartilhado e a um projeto de plataforma. Em seguida, quando você renomeia um arquivo em um projeto compartilhado e outro arquivo em um projeto de plataforma, você pode ver os eventos que são disparados para cada operação de renomeação.
Neste procedimento, você adiciona um ouvinte de eventos a um projeto compartilhado e a um projeto de plataforma. Em seguida, quando você renomeia um arquivo em um projeto compartilhado e outro arquivo em um projeto de plataforma, você pode ver os eventos que são disparados para cada operação de renomeação.
Adicione um ouvinte de eventos. Adicione um novo arquivo de classe ao projeto e chame-o de HierarchyEventListener.cs.
Abra o arquivo HierarchyEventListener.cs e adicione o seguinte usando diretivas:
using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio; using System.IO;Faça a classe
HierarchyEventListenerimplementar IVsHierarchyEvents:class HierarchyEventListener : IVsHierarchyEvents { }Implemente os membros do IVsHierarchyEvents, como no código abaixo.
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; } }Na mesma classe, adicione outro manipulador de eventos para o evento ItemRenamedDTE , que ocorre sempre que um item de projeto é renomeado.
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)); }Inscreva-se nos eventos hierárquicos. Você precisa se inscrever separadamente para cada projeto que está acompanhando. Adicione o seguinte código no
ShowMessageBox, um para o projeto compartilhado e o outro para um dos projetos da plataforma.// 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);Inscreva-se no evento de item do projeto DTE ItemRenamed. Adicione o seguinte código depois de conectar o segundo ouvinte.
// hook up DTE events for project items Events2 dteEvents = (Events2)dte.Events; dteEvents.ProjectItemsEvents.ItemRenamed += listener1.OnItemRenamed;Modifique o item compartilhado. Não é possível modificar itens compartilhados em um projeto de plataforma; em vez disso, você deve modificá-los no projeto compartilhado que é o proprietário real desses itens. Você pode obter o ID do item correspondente no projeto partilhado com IsDocumentInProject, fornecendo o caminho completo do item partilhado. Em seguida, você pode modificar o item compartilhado. A mudança é disseminada pelos projetos da plataforma.
Importante
Você deve descobrir se um item de projeto é ou não um item compartilhado antes de modificá-lo.
O método a seguir modifica o nome de um arquivo de item de projeto.
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)); } }Chame este método após todo o restante do código em
ShowMessageBoxpara modificar o nome do arquivo do item no projeto compartilhado. Insira isso após o código que obtém o caminho completo do item no projeto compartilhado.// 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);Crie e execute o projeto. Crie um aplicativo de hub universal C# na instância experimental, vá para o menu Ferramentas e clique em Invocar TestUniversalProject e verifique o texto no painel de saída geral. O nome do primeiro item no projeto compartilhado (esperamos que seja o arquivo App.xaml ) deve ser alterado e você deve ver que o ItemRenamed evento foi acionado. Nesse caso, como renomear App.xaml faz com que App.xaml.cs também seja renomeado, você verá quatro eventos (dois para cada projeto de plataforma). (Os eventos DTE não controlam os itens no projeto compartilhado.) Você deve ver dois OnItemDeleted eventos (um para cada um dos projetos da plataforma), mas nenhum OnItemAdded evento.
Agora tente renomear um arquivo em um projeto de plataforma e você pode ver a diferença nos eventos que são acionados. Adicione o seguinte código em
ShowMessageBoxapós a chamada aModifyFileName.// 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);Crie e execute o projeto. Crie um projeto Universal C# na instância experimental, vá para o menu Ferramentas e clique em Invocar TestUniversalProject e verifique o texto no painel de saída geral. Depois que o arquivo no projeto da plataforma for renomeado, você verá um OnItemAdded evento e um OnItemDeleted evento. Como a alteração do arquivo fez com que nenhum outro arquivo fosse alterado, e como as alterações em itens em um projeto de plataforma não são propagadas em nenhum lugar, há apenas um desses eventos.