Este artigo foi traduzido por máquina.

Telefone de Windows 7

Sterling para armazenamento isolado no telefone Windows 7

Jeremy Likness

Baixar o código de exemplo

O lançamento do Windows 7 telefone fornecido um milhão estimado Silverlight aos desenvolvedores a oportunidade de se tornar móveis coders praticamente durante a noite.

Aplicativos para Windows Phone 7 são escritos no mesmo idioma (c# ou Visual Basic) e relativa a um quadro que é quase idêntico à versão de navegador do Silverlight 3, que inclui a capacidade de dispor telas usando XAML e editá-los com o Expression Blend. Desenvolvendo para o telefone fornece seus próprios desafios únicos, no entanto, incluindo gerenciamento especial necessário quando o usuário alterna aplicativos (chamados de "Desactivar") combinado com suporte limitado para gerenciamento de Estado.

Sterling é um projeto de banco de dados de código aberto baseado no armazenamento isolado que irá ajudá-lo gerenciar objetos locais e recursos no seu aplicativo Windows Phone 7, bem como simplificar o processo de marcação para exclusão. O banco de dados orientado a objeto é projetado para ser leve, rápido e fácil de usar, resolução de problemas, como gerenciamento de persistência, cache e Estado. É não intrusiva e funciona com suas definições de tipo existentes sem exigir que você altera ou mapeá-los.

Neste artigo, os desenvolvedores do Windows Phone 7 vão aprender como utilizar a biblioteca Sterling para persistir e consultar dados localmente no telefone com o mínimo esforço, juntamente com uma simple estratégia de gerenciamento de estado quando um aplicativo é desativado durante a marcação para exclusão.

Noções básicas de marcação para exclusão

Silverlight no navegador e no telefone é executado em um especial "proteção de segurança" que isola o sistema host do ambiente de tempo de execução do aplicativo. O ambiente de telefone adiciona uma camada de complexidade porque vários aplicativos podem coexistir na plataforma. Enquanto o sistema operacional subjacente do telefone suporta multitarefa, aplicativos de terceiros não são fornecidos com o acesso a esta camada. Em vez disso, os aplicativos têm a oportunidade de correr "em primeiro plano" mas podem ser permutados rapidamente para abrir caminho para outros aplicativos, as chamadas telefônicas ou recursos de hardware como o botão Voltar e pesquisa. Quando o aplicativo é desactivado, há uma possibilidade que pode ser "morto," com a oportunidade de ser relançado, se e quando o usuário navega de volta. Este é o processo conhecido como marcação para exclusão.

A atualização de "Manga" para Windows Phone 7 limitará cenários de marca para exclusão fornecendo "switches de aplicação rápida". Aplicativos não serão marcados para exclusão automaticamente. Enquanto essa funcionalidade já está presente no Windows 7 telefone Developer Tools, é importante reconhecer que isso não elimina o cenário de marca para exclusão. Fatores como outros aplicativos em execução e memória disponível influenciará se o aplicativo é marcado para exclusão.

O problema com a marcação para exclusão é que quando o aplicativo é revivido, são criadas novas instâncias das páginas que fazem parte do aplicativo. Portanto, qualquer coisa que o usuário estava trabalhando em quando ocorreu o evento — tais como selecionar um item de uma lista de opções ou inserindo texto — é perdido. Cabe a você, desenvolvedor, para manter este Estado e restaurá-lo quando o aplicativo retorna para fornecer uma experiência perfeita para o usuário. Imagine a confusão de um usuário típico que está no meio do preenchimento de um formulário e clica em Pesquisar para pesquisar um termo, só para voltar e encontrar que o aplicativo tem navegado para uma página separada, em branco!

Salvando o estado no telefone

Felizmente, o Windows Phone 7 fornecem diversos mecanismos para salvar o Estado. Para trabalhar com aplicativos no sistema operacional, você precisará se familiarizar com esses métodos. As opções incluem SQL CE (com a atualização de manga), um dicionário de estado de página, o dicionário de estado de aplicativo e armazenamento isolado. Falarei sobre a última opção, armazenamento isolado, mas uma rápida revisão dos três primeiros ajudará a lançar luz sobre por que Sterling é útil no telefone.

SQL CE update The Mango fornecerá SQL CE, uma versão compacta do popular banco de dados do SQL Server. A diferença entre esse banco de dados e outras opções listadas aqui é que SQL é um banco de dados relacional. Ele se baseia em formatos de tabela especial que devem ser mapeados de seus controles e classes. Bancos de dados orientados a objeto podem tomar as estruturas de classe existentes — mesmo quando incluem classes aninhadas, listas e outros tipos — e serializá-los sem qualquer mapeamento adicional ou modificações.

Página Estado página cada objeto fornece uma propriedade de Estado que apresenta um dicionário que tem definido por nomes de chave e objetos relacionados. Qualquer chave ou objeto pode ser usado, mas o objeto deve ser serializável e, em seguida, ocorre apenas serialização superficial (nível superior). Além disso, o estado de página só permite até 2 MB de dados por página (4 MB para o aplicativo inteiro) e só pode ser usado depois do início do OnNavigatedTo e antes dos métodos de OnNavigatedFrom na página. Isso limita o uso prático para tipos de valor simples. O fato que ele só pode funcionar dentro os métodos de navegação de página faz uma má escolha de padrões como o Model-View-ViewModel (MVVM) que sincronizam o estado de exibição usando um ViewModel separado.

O estado do aplicativo este é também um dicionário. Como o estado de página, que leva uma Cadeia de caracteres chave e um valor de objeto e o objeto deve ser serializável. O objeto de aplicativo no telefone tem um evento Deactivated chamado quando ocorre a marcação para exclusão e um evento Activated chamado quando o aplicativo retorna ao Estado de marca para exclusão. O estado do aplicativo pode ser acessado a qualquer momento entre a ativação e desativação. Ele é acessado usando a classe estática de PhoneApplicationService (há uma propriedade atual que faz referência a uma única instância do aplicativo-wide). Não há limite para o tamanho do dicionário de estado de aplicativo documentada, mas em algum momento tentar armazenar muitos itens resultará em uma exceção COM sendo lançada.

Armazenamento isolado esta é opção de longe o mais flexível para a manutenção do Estado. Armazenamento isolado não é exclusivo para o telefone e na verdade funciona quase exatamente da mesma maneira no Silverlight e no Microsoft.NET Framework runtime. Armazenamento isolado fornece uma camada de abstração do host de sistema de arquivos, portanto, em vez de lidar com o armazenamento de arquivos direto, você interface com um mecanismo indireto que fornece pastas e arquivos em uma sandbox isolado. No Windows Phone 7, esse seguro é isolado para o nível de seu aplicativo de telefone. Você pode acessar o armazenamento em qualquer lugar de dentro do aplicativo, mas não de qualquer outro aplicativo no telefone.

Armazenamento isolado também tem algumas vantagens poderosas. Enquanto ele fornece um dicionário de configurações semelhante para as configurações de página e aplicativo descritas anteriormente, também permite que você organizar dados em pastas e arquivos. Na verdade, qualquer tipo de arquivo — XML, binário ou texto — podem ser criados e acessados no armazenamento isolado. Não há nenhuma cota para o tamanho de armazenamento isolado no telefone, assim você efetivamente é limitado pela quantidade de memória e armazenamento disponível no telefone. O único inconveniente é que o processo de escrita para armazenamento e recuperação de armazenamento é um pouco mais lento do que os outros métodos que armazenam as listas na memória ativa.

Opções de serialização

Outro benefício do armazenamento isolado é que você pode escolher várias estratégias de serialização. Ao contrário das configurações que permitem que você atribua uma chave e um objeto, o mecanismo de armazenamento isolado fornece um fluxo de arquivo que você pode gravar usando texto, XML, JSON ou código mesmo binário. Isso permite fácil e simples de serialização de muitos tipos de objetos, incluindo serialização "profunda" que pode manipular um objeto complexo gráfico e serializar os filhos e netos e assim por diante da instância que você está trabalhando com.

JSON e XML estas são as duas estratégias principais serialização disponíveis no Silverlight. XML está disponível usando o DataContractSerializer (que emite XML) ou o XMLSerializer. O primeiro é familiar aos desenvolvedores que usam o Windows Communication Foundation (WCF) e é o que a estrutura usa para hidratar e desidratar mensagens enviadas via Web services. Ele requer que os dados são marcados usando os atributos DataContract e DataMember. Isso é essencialmente uma abordagem "opt-in" porque você explicitamente sinaliza os campos desejados serializado. O XmlSerializer serializa todas as propriedades públicas com getters e setters e você pode alterar o comportamento usando atributos específicos de XML especiais. Para obter mais informações sobre o DataContractSerializer, consulte bit.ly/fUDPha. Para obter mais informações sobre o XmlSerializer, consulte bit.ly/fCIa6q.

JSON significa JavaScript Object Notation e é popular na Web, porque é um formato que é facilmente convertido em objetos JavaScript. Alguns desenvolvedores preferem este método porque ele fornece um texto legível no objeto serializado em uma forma mais compacta que XML. Serialização JSON é feita usando uma versão especial do serializador de contrato de dados chamado o DataContractJsonSerializer. A saída que produz ocupa muito menos espaço em disco do que XML. Para obter mais informações sobre o DataContractJsonSerializer, consulte bit.ly/8cFyjV.

Binário Silverlight e Windows Phone 7 também podem usar a serialização binária. Não há nenhum BinaryFormatter disponíveis no Silverlight (Esta é a classe que ajuda automaticamente serializar objetos para binário) então você deve manipular a serialização yourself. Para usar a serialização binária, você simplesmente criar um gravador binário e gravar o fluxo. O escritor manipula muitos primitivos, portanto, na maioria das vezes você pode escrever fora as propriedades em sua classe para serializar a instância, em seguida, criar uma instância e preencher as propriedades usando o leitor. Para projectos com um monte de classes, no entanto, isso pode se tornar bastante complicado. Isto é onde Sterling insere a imagem.

Sterling esterlina foi projetada especificamente para aliviar a dor de serializar e desserializar objetos em Silverlight. Originalmente criado para o Silverlight (4) no navegador, Sterling evoluiu para um quase idêntico codebase que suporta Windows Phone 7. Nos bastidores, Sterling usa serialização binária, que resulta em um formato muito compacto no disco. Sterling pode serializar quase qualquer classe e organiza instâncias usando as teclas que você fornece (qualquer propriedade na instância pode ser designada como chave). Sterling também fornece índices que podem ser consultados na memória para a velocidade antes de carregar a instance inteira do disco. Sterling dá-lhe total controle sobre o fluxo de serialização subjacente. Você pode criptografar, comprimir ou até mesmo substituir o fluxo binário para serializar tipos exatamente como você quer.

A Sterling vantagem fornece é uma maneira rápida e fácil para serializar objetos juntamente com a capacidade de chaves de consulta e índices com velocidade relâmpago usando LINQ para objetos. Ele lida com relações e chaves estrangeiras bem. Todos estes benefícios têm apenas uma ligeira velocidade custo quando serialização e desserialização.

Figura 1 compara várias estratégias de serialização e o tamanho relativo no disco.

Size-on-Disk Comparison of Various Serialization Strategies

Figura 1 Tamanho em disco comparação das várias estratégias de serialização

Para gerar esses números, uma coleção de contatos de 2000 foi criada usando endereços e nomes aleatórios. Os registos de contacto cada contêm um nome completo, endereço e uma ID exclusiva (consulte Figura 2).

The Contact Class

Figura 2 A classe contato

Estes, em seguida, foram salvos usando os serializers diversos, incluindo Sterling. O tamanho calculado é o tamanho total do disco, incluindo os arquivos adicionais que Sterling necessita para manter o controle de índices e chaves.

Serialização completa para e do disco é apenas ligeiramente mais lenta para Sterling devido à sobrecarga de pé o gráfico do objeto e manipulação de índices e chaves. O gráfico em Figura 3 compara rapidez cada opção pode salvar e carregar todos os contatos de 2000.

Comparison of Speed

Figura 3 comparação de velocidade

O show de estatísticas de consulta final onde Sterling fornece a maioria dos alavancagem na digitalização da coleção para contatos com nomes que começam com um "L" e, em seguida, carregar esses contatos completos. Em executar o exemplo, a consulta produziu 65 contatos da 2000. Sterling filtrada e carregado-los em apenas 110 milissegundos em comparação com mais de 2 segundos para outros formatos.

A aplicação de receita

Para demonstrar o uso de Sterling no Windows Phone 7, eu escrevi um aplicativo pequeno receita que permite que você navegue, editar e adicionar novas receitas. Cada receita consiste em um nome, um conjunto de instruções, uma categoria (por exemplo, almoço ou jantar) e um conjunto de ingredientes. Ingredientes podem ter um valor, uma medida e um item alimentar. Alimentos podem ser adicionados em tempo real. Figura 4 mostra uma página de exemplo da aplicação.

Edit Recipe Screen

Figura 4 Editar tela de receita

Para esta aplicação, Sterling tem três finalidades distintas. Em primeiro lugar, ele ajuda frontais os dados de referência usados pelo aplicativo, como categorias, medições, alimentos iniciais e receitas de amostra. Em segundo lugar, ele preserva os dados que os usuários digitam quando eles adicionarem suas próprias receitas personalizadas e alimentos. Finalmente, ele facilita a marcação para exclusão por serializar o estado do aplicativo quando ele é desativado. O aplicativo de exemplo usa o padrão MVVM e demonstra como a desativação de dentro de um ViewModel.

O primeiro passo, é claro, adicionar Sterling ao projeto. Isso pode ser feito usando NuGet (apenas procure por Sterling) ou baixando os binários e completo da fonte do CodePlex at sterling.codeplex.com.

Como configurar o banco de dados

A próxima etapa é configurar o banco de dados. A configuração de banco de dados define quais tipos estão indo para ser persistente e que chaves e índices serão usados. O banco de dados de Sterling é uma classe criada derivando de BaseDatabaseInstance. Há duas sobrecargas, você deve fornecer: um nome exclusivo para o banco de dados (o nome é exclusivo por aplicativo — você pode hospedar vários bancos de dados para separar os dados ou gerenciar versões diferentes) e uma lista de definições de tabela. A classe base fornece métodos auxiliar para definir tabelas, chaves e índices.

Índices e chaves este aplicativo define uma tabela do tipo FoodModel usando o objeto Id como a chave com um índice sobre a propriedade de FoodName. Isso cria uma lista na memória de objetos que podem ser rapidamente consultados e filtrado.

O código a seguir define o alimento "tabela" com uma chave de inteiro e um índice de Cadeia de caracteres:

CreateTableDefinition<FoodModel, int>(f => f.Id)
.WithIndex<FoodModel, string, int>(IDX_FOOD_NAME, f=>f.FoodName)

A chamada para criar a definição da tabela leva o tipo de classe e o tipo de chave e é passada uma expressão lambda usada para resolver a chave. Você pode usar qualquer valor não-null exclusivo na classe como sua chave. O método de extensão do índice requer o tipo de tabela, o tipo de índice e o tipo de chave. Aqui, uma constante define o nome do índice e a expressão lambda fornece o valor que usará o índice.

Identidade usando disparadoresSterling suporta qualquer tipo de chave, portanto não há nenhum recurso interno para automaticamente gerar novas chaves. Em vez disso, Sterling permite que você especificar como você gostaria que as chaves a serem gerados pelo uso de disparadores. Disparadores são registrados com o banco de dados de Sterling e são chamados antes de salvar, após um salvamento e uma exclusão. A chamada antes de salvar permite que você inspecione a instância e gerar uma chave se um já não existe.

No aplicativo de exemplo no download de código que acompanha este artigo, todas as entidades de usam uma chave de inteiro. Portanto, é possível criar um disparador genérico com base no tipo de instância para gerar a chave. Quando o gatilho é instanciado pela primeira vez, ele consulta o banco de dados para as chaves existentes e localiza o um mais alto. Não se existir nenhum registro, ele será definido a chave inicial para 1. Cada vez que uma instância é salvo que tem uma chave menor ou igual a zero, ele irá atribuir o próximo número e incrementar a chave. O código para este desencadeamento de base é em Figura 5.

Figura 5 desencadeamento de Base para a geração de Auto-chave

public class IdentityTrigger<T> : BaseSterlingTrigger<T,int>  
  where T: class, IBaseModel, new()
{
  private static int _idx = 1;

  public IdentityTrigger(ISterlingDatabaseInstance database)
  {
    // If a record exists, set it to the highest value plus 1
    if (database.Query<T,int>().Any())
    {
      _idx = database.Query<T, int>().Max(key => key.Key) + 1;
    }
  }

  public override bool BeforeSave(T instance)
  {
    if (instance.Id < 1)
    {
      instance.Id = _idx++;
    }

    return true;
  }

  public override void AfterSave(T instance)
  {
    return;
  }

  public override bool BeforeDelete(int key)
  {
    return true;
  }
}

Observe que a consulta pode usar expressões LINQ, como um padrão e Max. Além disso, o desenvolvedor é responsável por fornecer segurança do thread no âmbito do mecanismo de gatilho.

Usar um disparador é fácil: basta registrar o gatilho com o banco de dados e passar uma instância (Isso permite que você passar quaisquer parâmetros de construtor que são necessários). Você pode usar uma chamada semelhante para cancelar o registro um gatilho.

Serializador personalizado Sterling suporta uma variedade de tipos de caixa. Quando classes e structs são encontrados, as propriedades públicas e campos dessas classes são iterados para serializar o conteúdo. Subclasses e estruturas são recursivamente iterada também. Sterling não pode serializar directly alguns tipos básicos. Por exemplo, System. Type é definido como uma classe abstrata que tem muitas possíveis classes derivadas. Sterling diretamente não é possível serializar ou desserializar este tipo. Para oferecer suporte a marcação para exclusão, uma classe especial será criada que lojas ViewModel propriedades e usa o tipo de ViewModel como a chave. Para lidar com o tipo, Sterling permite que você crie um serializador personalizado.

Para criar um serializador Personalizar, derivar da classe BaseSerializer e manipular as sobrecargas. Para a classe personalizada TypeSerializer, qualquer classe que derives de Type é suportado, e a serialização simplesmente grava o nome de tipo qualificado do assembly. Desserialização usa o método GetType estático na classe de tipo para o tipo de retorno do nome qualificado do assembly. O resultado é mostrado na Figura 6. Observe que ele suporta explicitamente qualquer tipo que deriva (é atribuído a) Type.

Figura 6 TypeSerializer

public class TypeSerializer : BaseSerializer 
{
  /// <summary>
  ///     Return true if this serializer can handle the object, 
  ///     that is, if it can be cast to type
    /// </summary>
  /// <param name="targetType">The target</param>
  /// <returns>True if it can be serialized</returns>
  public override bool CanSerialize(Type targetType)
  {
    return typeof (Type).IsAssignableFrom(targetType);
  }

  /// <summary>
  ///     Serialize the object
  /// </summary>
  /// <param name="target">The target</param>
  /// <param name="writer">The writer</param>
  public override void Serialize(object target, 
    BinaryWriter writer)
  {
    var type = target as Type;
    if (type == null)
    {
      throw new SterlingSerializerException(
        this, target.GetType());
    }
    writer.Write(type.AssemblyQualifiedName);
  }

  /// <summary>
  ///     Deserialize the object
  /// </summary>
  /// <param name="type">The type of the object</param>
  /// <param name="reader">A reader to deserialize from</param>
  /// <returns>The deserialized object</returns>
  public override object Deserialize(
    Type type, BinaryReader reader)
  {
    return Type.GetType(reader.ReadString());
  }
}

Qualquer serializers Personalizars são registrados com o mecanismo de Sterling antes de ele é ativado.

A propagação e salvar dados

Uma vez que o banco de dados é definido, é comum para fornecer "dados sementes". No aplicativo de exemplo, uma lista de categorias, medidas padrão e alimentos são fornecidos para ajudar o usuário começar — uma receita de exemplo também está incluída. Há várias maneiras para incorporar os dados, mas é a maneira mais fácil de incluir os dados como um recurso no arquivo XAP. Os dados, em seguida, podem ser analisados como um fluxo de recursos a primeira vez que o aplicativo é executado e armazenado no banco de dados.

Para trabalhar com o processo de desativação, o mecanismo de banco de dados de Sterling é ativado quando o próprio aplicativo é ativado e desativado quando ele é marcado para exclusão ou exited. Isso garante que as chaves de banco de dados e índices são liberadas para o disco e o banco de dados está em um estado estável quando usado novamente. No arquivo App.xaml.cs, esses eventos podem ser conectados para o ciclo de vida do telefone. Para configurar o banco de dados, são necessárias apenas algumas linhas de código, conforme mostrado aqui:

_engine = new SterlingEngine();
_engine.SterlingDatabase.RegisterSerializer<TypeSerializer>();
_engine.Activate();
Database =  
  _engine.SterlingDatabase.RegisterDatabase<RecipeDatabase>();

O trecho de código anterior demonstra as etapas que criam o motor, registrar o serializador personalizado e, em seguida, ativar o mecanismo e preparar o banco de dados para uso. O código a seguir mostra como desligar o motor e o banco de dados quando o aplicativo é marcado para exclusão ou exited:

Database.Flush();
_engine.Dispose();
Database = null;
_engine = null;

Depois que o banco de dados tiver sido ativado, ele está pronto para receber dados. A maneira mais comum de dados de pacote é para incluí-lo como um recurso incorporado em um formato legível, tais como XML, JSON ou CSV. Uma consulta ao banco de dados pode determinar se dados já existem, e se isso não acontecer, os dados são carregados. Salvar dados em Sterling é simples: você simplesmente passe a instância para salvar, e Sterling cuida do resto. Figura 7 mostra uma consulta que verifica a existência de categorias. Se nenhuma categoria existir, é ler os dados de arquivos de recurso incorporado para propagar o banco de dados. Observe o uso da operação truncate para limpar as tabelas primeiro.

Figura 7 propagação de dados

if (database.Query<CategoryModel, int>().Any()) return;

// Get rid of old data
database.Truncate(typeof(MeasureModel));
database.Truncate(typeof(FoodModel));
                
var idx = 0;

foreach(var measure in ParseFromResource(FILE_MEASURES,
  line =>
  new MeasureModel
  { Id = ++idx, Abbreviation = line[0], FullMeasure = line[1]} ))
{
  database.Save(measure);
}

// Sample foods auto-generate the id
foreach (var food in
  ParseFromResource(FILE_FOOD, line 
    => new FoodModel { FoodName = line[0] })
    .Where(food => !string.IsNullOrEmpty(food.FoodName)))
{
  database.Save(food);
}

var idx1 = 0;

foreach (var category in ParseFromResource(FILE_CATEGORIES,
  line =>
  new CategoryModel { Id = ++idx1, CategoryName = line[0] }))
{
  database.Save(category);
}

O ViewModel principal: Categorias e receitas

Com o banco de dados semeado analisado e carregado, o restante do aplicativo pode usar os dados existentes para fornecer listas e pede para o usuário, bem como salvar todas as informações inseridas pelo usuário. Aqui está um exemplo de como os dados semeados são disponibilizados para o aplicativo. O seguinte trecho de código carrega todas as categorias em uma coleção observável em ViewModel principal:

Categories = new ObservableCollection<CategoryModel>();
foreach(var category in App.Database.Query<CategoryModel,int>())
{
  Categories.Add(category.LazyValue.Value);
}

A coleção de categorias agora pode ser ligada diretamente a um controle de pivô. Um uso comum do controle pivô é fornecer exibições filtradas sobre grandes conjuntos de dados. As categorias indicam o tipo de refeição (se ele é uma refeição de pequeno-almoço, almoço refeição ou outra categoria) e o pivô exibe as receitas relevantes quando se selecciona uma categoria. As receitas de cada categoria são expostas por uma consulta que filtra com base na categoria selecionada no momento.

O seguinte trecho de XAML mostra como o Controlarar está diretamente ligado à coleção e categoria selecionada:

<controls:Pivot        
  x:Name="pivotMain"
  Title="Sterling Recipes"
  ItemsSource="{Binding Categories}"
  SelectedItem="{Binding CurrentCategory,Mode=TwoWay}">

Edição de ingredientes: Chaves estrangeiras

A chave para receitas é, naturalmente, seus ingredientes. O aplicativo contém uma lista de"mestre" de itens alimentares e medições. Cada receita pode ter uma lista de "ingredientes" que incluem a quantidade, tipo de item de medição e alimentos. O botão de ingredientes (back in Figura 4) leva o usuário para uma lista de ingredientes, onde o usuário pode adicionar, excluir ou editar ingredientes existentes.

Esta funcionalidade é possível devido a uma característica importante da Sterling: o suporte para propriedades de navegação que atuam como chaves estrangeiras. Figura 8 mostra a hierarquia de modelos usados no aplicativo.

Recipe Class Hierarchy

Figura 8 receita classe hierarquia

Receitas contêm listas de ingredientes que tem uma referência circular para a receita do pai. Ingredientes também contêm um modelo de "quantidade" que inclui unidades e medida.

Quando você salva uma receita, Sterling reconhecerá automaticamente cada ingrediente como uma entrada separada em uma definição de tabela separada. Em vez de serialização o ingrediente com o objeto de receita, Sterling irá serializar a chave para o índice e, em seguida, salve o ingrediente separadamente. Também reconhecer a referência circular com a receita e parar de recursão sobre o gráfico do objeto. Incluindo a receita com o ingrediente permite consultas diretamente sobre o ingrediente que pode, em seguida, carregar a receita correspondente.

Quando você modificar ou adicionar um ingrediente, salvar operação salvará automaticamente as tabelas relacionadas. Quando carregado, tabelas externas sempre são retiradas do disco, garantindo que eles estão sempre em sincronia com a versão mais recente.

Pesquisa de alimentos: Consultando com índices

Sterling utiliza chaves na memória e índices para facilitar consultas e filtros. A busca de alimento fornece um exemplo de filtragem e consulta. A caixa de texto está vinculada para o ViewModel e atualizará o texto sendo digitado como o usuário insere-lo. Os usuários verão os resultados (alimentos que contêm o texto que estão digitando o nome) instantaneamente como eles estão escrevendo. Isto torna mais fácil para o usuário restringir a pesquisa e selecione um alimento existente ou digite um novo nome. Você pode ver a página de pesquisa de alimentos em Figura 9, com itens selecionados que contêm as letras "pe".

Food Search for Items that Include the Letters “pe”

Figura 9 Pesquisa de alimentos para itens que incluem as letras "pe"

Sempre que o usuário digita, a propriedade setter em ViewModel é atualizada com o texto de pesquisa. Este setter, por sua vez aumenta o evento de propriedade alterada para a lista de alimentos. A lista de alimentos executa uma nova consulta no banco de alimentos e retorna os resultados usando LINQ para objetos. Figura 10 mostra a consulta, que usa um índice para filtro e a ordem dos dados. Para acessar a consulta, o banco de dados é chamado com o tipo de classe, o tipo de índice e o tipo de chave e, em seguida, é passado o nome do índice. Observe que um novo modelo de alimentos é criado com base no valor de chave e índice retornado do índice.

Figura 10 alimentar consulta

public IEnumerable<FoodModel> Food
{
  get
  {
    if (string.IsNullOrEmpty(_foodText))
    {
      return Enumerable.Empty<FoodModel>();
    }
    var foodTextLower = _foodText.ToLower();
    return from f in App.Database.Query<FoodModel, 
      string, int>(RecipeDatabase.IDX_FOOD_NAME)
      where f.Index.ToLower().Contains(foodTextLower)
      orderby f.Index
      select new FoodModel { Id = f.Key, FoodName = f.Index };
  }
}

A marcação para exclusão prática

Para desactivar a trabalhar, o estado atual do aplicativo deve ser salvos e restaurado quando o usuário retorna para o aplicativo. Às vezes, esta exigência pode ser complexa porque o usuário também pode navegar para trás através do aplicativo após ele retornou ao Estado para exclusão. Portanto, todas as páginas devem ser capazes de manter seus valores para a experiência permanecer sem costura.

O padrão MVVM assume a responsabilidade para a marcação para exclusão do Vista-centric XAML e Code-behind, porque o estado de exibição é sincronizado com o ViewModel através de ligação de dados. Portanto, cada ViewModel pode ser responsável por salvar e restaurar seu próprio Estado. As ligações irão atualizar a exibição em conformidade. Para facilitar a marcação para exclusão, foi criada uma classe chamada TombstoneModel.

Ele é codificado com base em um tipo (que será a interface para o ViewModel sendo salvo) e contém um dicionário de chaves e objetos. Isso proporciona a máxima flexibilidade para armazenar tipos ou classes conforme necessário para preservar o estado de ViewModel.

Sterling suporta isso porque independentemente de como uma propriedade é definida-se como um objeto genérico, uma interface ou uma classe base abstrata — a serialização gravará fora o objeto como tipo implementado. Isso não é possível com os built-in serializadores. Para fornecer uma interface comum, uma interface ITombstoneFriendly é fornecida pela estrutura MVVM leve. Essa interface define ativar e desativar os métodos que são chamados quando o modo de exibição vinculado é navegado para e partir (marcação para exclusão irá disparar uma navegação "de", por exemplo).

A marcação para exclusão, em seguida, torna-se tão simple como criar o modelo, definindo o tipo e, em seguida, definir os valores que deve ser persistentes. Retornando de eventos de tombstone envolve carregando o modelo, ler os valores e restaurar o estado no ViewModel. Figura 11 ilustra estes passos no editor de texto ViewModel que deve preservar o título que foi passado e o texto que o usuário tenha entrado.

Figura 11 a marcação para exclusão

/// <summary>
///     Tombstone
/// </summary>
public void Deactivate()
{
  var tombstone = new TombstoneModel 
    {SyncType = typeof (ITextEditorViewModel)};
  tombstone.State.Add(ExtractPropertyName(()=>Title), Title);
  tombstone.State.Add(ExtractPropertyName(() =>Text), Text);
  App.Database.Save(tombstone);
}

/// <summary>
///     Returned from tombstone
/// </summary>
public void Activate()
{
  var tombstone = App.Database.Load<TombstoneModel>
    (typeof(ITextEditorViewModel));
  if (tombstone == null) return;
  Title = tombstone.TryGet(ExtractPropertyName(() => 
    Title), string.Empty);
  Text = tombstone.TryGet(ExtractPropertyName(() => 
    Text), string.Empty);
}

Quando o modo de exibição é fechado através de meios normais (não marcação para exclusão) o registro facilmente pode ser excluído. Quando o aplicativo é fechado, a tabela será truncada para remover todos os registros, porque o Estado não deve ser preservado quando o aplicativo é relançado.

Leve e flexível

Como você pode ver, Sterling remove a carga de estratégias complexas de serialização do desenvolvedor. Para persistir entidades é tão simples quanto definindo um tipo de classe e uma expressão lambda que retorna uma chave exclusiva. Leve (menos de 100 KB DLL como da redação deste texto) e flexível (com ganchos para disparadores, criptografia, compactação e serialização personalizada), ele deve tratar a maioria das necessidades relacionadas a bancos de dados locais, incorporados, cache e marcação para exclusão. A aplicação de receita demonstra como Sterling se integra ao Windows 7 de telefone para facilmente e efetivamente atender essas necessidades.

Jeremy Likness é um consultor sênior e gerente de projetos na Wintellect LLC em Atlanta. Ele é um MVP da Microsoft Silverlight e um certificado MCTS Silverlight developer. Likness freqüentemente apresenta tópicos relacionados a aplicativos de linha de negócios de Silverlight em grupos de usuários e conferências. Ele também regularmente atualiza seu blog de Silverlight em csharperimage.jeremylikness.com.

Graças aos seguintes especialistas técnicos para revisão deste artigo: Rob Cameron, John Garland e Jeff prosise