Há um typesafe forma de navegação entre as telas no Windows Phone?
-
20-12-2019 - |
Pergunta
Eu estou procurando uma forma de navegar entre as telas em meu aplicativo.Basicamente, o que eu vi até agora consiste em passar uma string URI para o NavigationService, completo com parâmetros de cadeia de consulta., exemplo:
NavigationService.Navigate(new Uri("/MainPage.xaml?selectedItem=" +bookName.Id, UriKind.Relative));
Eu realmente não estou interessado neste embora, em última análise, porque requer cordas mágicas, e podem levar a problemas na estrada.
Idealmente, eu gostaria de criar uma instância da classe eu quero navegar, passando os parâmetros como argumentos para o construtor.Isso é possível?Se sim, como?
Solução
Enquanto a navegação real terá que usar seqüências de caracteres, eventualmente, você pode criar ou usar um invólucro que é tipo de seguro.
Gostaria de sugerir olhando para Caliburn Micro mesmo se você só usou-o para o tipo de navegação segura.Aqui é um trecho a partir de um tutorial sobre como usar ele no WP8:
O NavigationService que vem com o kit de ferramentas oferece suporte a uma modelo de modo de exibição primeira abordagem:em vez de declarar que é a URL da página onde queremos levar o usuário (que é o padrão de abordagem), declaramos que é o ViewModel que queremos exibir. O serviço terá o cuidado de criar a URL correta e exibir o modo de exibição que está associado com o modelo de modo de exibição.
Alternativamente, você poderia olhar O Windows Phone MVC que também tem algum tipo de segurança de navegação.Você pode até mesmo ser capaz de puxar o código de navegação para usar em seu próprio país, já que é licenciado sob MS-PL.
Outras dicas
Basicamente, não, não, isto é built-in.Parâmetros complexos como IRepository instâncias são, infelizmente, além da capacidade das instalações de navegação no Silverlight;Eu costumo usar algum tipo de contêiner IoC para lidar com esses.Mais simples POCO parâmetros são facilmente serializado para uma seqüência de caracteres, mas que ainda requer cordas mágicas e manual de consulta-análise de cadeia de caracteres.
No entanto, você pode facilmente construir algo typesafe si mesmo.Por exemplo, aqui está a minha abordagem.
Para o parâmetro de dados, eu tenho uma classe que eu chamo de 'Extras', que envolve um Dictionary<string, object>
com métodos como GetBool(string)
, GetInt32(string)
, etc., e tem um estático método de fábrica CreateFromUri(Uri)
;isso é bom o suficiente para os meus objetivos.
Eu uso isso em conjunto com a segurança do tipo de navegação.Eu realmente gosto do padrão MVVM, e cada uma das minhas páginas tem um ViewModel englobando quase toda a lógica.O um-para-um relação de página para ViewModel faz o último, um ideal a tecla de navegação.Isso, combinado com atributos e reflexão, nos dá uma solução simples:
public class NavigationTargetAttribute : Attribute
{
private readonly Type target;
public ViewModelBase Target
{
get { return target; }
}
public NavigationTargetAttribute(Type target)
{
this.target = target;
}
}
Colocar um desses em cada uma de suas páginas, com a devida ViewModel tipo.
[NavigationTarget(typeof(LoginViewModel))]
public class LoginPage : PhoneApplicationPage
{ ... }
Em seguida, em um singleton NavigationManager-esque classe, você pode fazer:
GetType().Assembly
.GetTypes()
.Select(t => new { Type = t, Attr = t.GetCustomAttributes(false).FirstOrDefault(attr => attr is NavigationTargetAttribute) })
.Where(t => t.Attr != null);
E só assim, você tem uma coleção de todos os navegável tipo em seu aplicativo.A partir daí, não muito mais trabalho para colocá-los em um dicionário, por exemplo.Se você seguir uma convenção para onde você colocar as suas páginas, você pode, por exemplo, traduzir entre o tipo e Uri com bastante facilidade...por exemplo, new Uri("/Pages/" + myPageType.Name + ".xaml", UriKind.Relative)
.Não é muito mais para adicionar suporte a parâmetros de consulta.Finalmente, você vai acabar com um método, assim:
public void Navigate(Type target, Extras extras)
{
Type pageType;
if (navigationTargets.TryGetValue(target, out pageType))
{
var uri = CreateUri(pageType, extras);
navigationService.NavigateTo(uri);
}
// error handling here
}
Finalmente, na página do OnNavigatedTo
método de eu fazer algo como:
var extras = Extras.CreateFromUri(e.Uri);
((ViewModelBase) DataContext).OnNavigatedTo(extras);
Este, finalmente, dá uma aparência de rigidez de tipos de navegação.Este é um bare-bones abordagem;em cima da minha cabeça, isso poderia ser melhorado, adicionando parâmetros necessários na navegação atributo e validando-os em navegação de tempo.Ele também não suporta mais complexos tipos de navegação, onde o valor de nav argumentos iria determinar o destino final.No entanto, este atende as minhas 90% de casos de uso - talvez isso vai funcionar para você também.
Há definitivamente alguns detalhes omitidos aqui, como exatamente para obter uma instância de NavigationService
- Eu posso trabalhar até obter um exemplo mais completo, mais tarde, hoje à noite, mas isso deve ser o suficiente para começar.
Você pode usar PhoneApplicationService.State
É um Dictionary<String,Object>
PhoneApplicationService.State
é comumente utilizado na marcação para exclusão para armazenar o estado atual do aplicativo.No entanto, ele pode ser convenientemente utilizado para transmitir dados entre páginas.
Aplicativos do Windows Phone são desativados quando o usuário navega para outra aplicação.Quando o usuário retorna para o aplicativo, por usando o botão Voltar ou através do preenchimento de um Iniciador ou o Seletor de tarefa, o a aplicação é reativada.Um aplicativo pode armazenar transitórias o estado da aplicação no Estado de dicionário no manipulador para o Desativado evento.No manipulador de eventos Ativado, um aplicativo pode use os valores armazenados no dicionário de Estado para transitório de aplicação do estado.
Basicamente o que você deve fazer é
PhoneApplicationService.State.add(selectedName,yourobjectInstance);
NavigationService.Navigate((new Uri("/MainPage.xaml?selectedItem="+selectedName,UriKind.Relative));
Em seguida, no seu navegado muito método, você pode recuperá-lo
YourObject yourObjectInstance;
var yourObj = PhoneApplicationService.State["yourObjectName"];
yourObjectInstance = yourObj is YourObject ? (yourObj as YourObject) : null;
Aqui está uma olhada mais aprofundada de como usar esse recurso
O WPF oferece suporte a navegação para uma já criada objeto, mas WP8 falta que Navigate
sobrecarga.
Se você não deseja rígido código XAML página URIs, você pode, você pode usar o seguinte (um pouco sujo) função auxiliar para obter o .recurso xaml URI de alguma classe.
static Uri GetComponentUri<T>() where T : DependencyObject, new() {
return BaseUriHelper.GetBaseUri(new T());
}
Em seguida, você pode modificar a URL e navegue para:
var baseUri = GetComponentUri<SomePage>(); //Uri="pack://application:,,,/MyProject;component/MainWindow.xaml"
var pageUri = new UriBuilder(baseUri) { Query = "selectedItem=" + bookName.Id };
NavigationService.Navigate(pageUri);
Nossa solução que funciona muito bem:
1. Não usar seqüências de caracteres de consulta na Página Uris, isto é completamente contra MVVM, onde o modo de exibição deve apenas mostrar coisas, mas a lógica real para o carregamento e a seleção de itens é em ViewModel.
2.Criar classe com const nomes de Página e sempre que você quiser navegar, use apenas essa:
public static class P
{
public const string ArticlePage = "/Pages/ArticlePage.xaml";
public const string OnlineSectionPage = "/Pages/OnlineSectionPage.xaml";
public const string GalleryPage = "/Pages/GalleryPage.xaml";
...
}
// in our viewModel
NavigationService.Navigate(P.ArticlePage);
// In navigation service
public void Navigate(string pagePath)
{
if (EnsureMainFrame())
{
mainFrame.Navigate(new Uri(pagePath, UriKind.RelativeOrAbsolute));
}
}