Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Se você tiver projetado uma interface do usuário com imagens de espaço reservado e texto clichê, este tutorial mostra como conectá-la a dados reais usando associações de dados. Aprenda a formatar dados, manter a interface do usuário e os dados em sincronia e melhorar a manutenção do código.
Neste tutorial, você aprenderá a substituir sua clichê por associações de dados e criar outros links diretos entre a interface do usuário e seus dados. Você também aprenderá a formatar ou converter seus dados para exibição e manter a interface do usuário e os dados sincronizados. Ao concluir este tutorial, você pode melhorar a simplicidade e a organização do código XAML e C#, facilitando a manutenção e a extensão.
Você começa com uma versão simplificada do exemplo do PhotoLab. Esta versão inicial inclui a camada de dados completa mais os layouts de página XAML básicos e deixa de fora muitos recursos para facilitar a navegação no código. Este tutorial não é compilado para o aplicativo completo, portanto, verifique a versão final para ver recursos como animações personalizadas e layouts adaptáveis. Você pode encontrar a versão final na pasta raiz do repositório Windows-appsample-photo-lab .
O aplicativo de exemplo do PhotoLab tem duas páginas. A página principal exibe uma exibição de galeria de fotos, juntamente com algumas informações sobre cada arquivo de imagem.
A página de detalhes exibe uma única foto depois de selecioná-la. Um menu suspenso de edição permite alterar, renomear e salvar a foto.
Pré-requisitos
- Visual Studio 2019 ou posterior: baixar o Visual Studio (a edição Community é gratuita.)
- SDK do Windows (10.0.17763.0 ou posterior): baixe o SDK mais recente do Windows (gratuito)
- Windows 10, versão 1809 ou posterior
Parte 0: Obter o código inicial do GitHub
Para este tutorial, você começa com uma versão simplificada do exemplo do PhotoLab.
Vá para a página do GitHub para obter o exemplo: https://github.com/Microsoft/Windows-appsample-photo-lab.
Em seguida, você precisa clonar ou baixar o exemplo. Selecione o botão Clonar ou Baixar. Um submenu é exibido.
Se você não estiver familiarizado com o GitHub:
uma. Selecione Baixar ZIP e salve o arquivo localmente. Essa ação baixa um arquivo .zip que contém todos os arquivos de projeto necessários.
b. Extraia o ficheiro. Use o Explorador de Arquivos para navegar até o arquivo de .zip que você acabou de baixar, clique com o botão direito do mouse nele e selecione Extrair Tudo....
c. Navegue até a cópia local do exemplo e vá até o diretório
Windows-appsample-photo-lab-master\xaml-basics-starting-points\data-binding.Se você estiver familiarizado com o GitHub:
uma. Clone o branch principal do repositório localmente.
b. Navegue até o diretório
Windows-appsample-photo-lab\xaml-basics-starting-points\data-binding.Photolab.slnClique duas vezes para abrir a solução no Visual Studio.
Parte 1: Substituir espaços reservados
Nesta seção, você criará vinculações pontuais no XAML de modelo de dados para exibir imagens reais e metadados de imagem em vez de conteúdo de espaço reservado.
Vinculações únicas são para dados somente leitura e imutáveis. Eles são de alto desempenho e fáceis de criar, para que você possa exibir grandes conjuntos de dados em controles GridView e ListView.
Substituir os espaços reservados por ligações únicas
Abra a
xaml-basics-starting-points\data-bindingpasta e inicie oPhotoLab.slnarquivo no Visual Studio.Verifique se a Plataforma de Solução está definida como x86 ou x64, não Arm, e, em seguida, execute o aplicativo. Esta etapa mostra o estado do aplicativo com marcadores de posição da UI, antes da adição das associações.
Abra MainPage.xaml e pesquise um
DataTemplatechamado ImageGridView_DefaultItemTemplate. Você atualizará esse modelo para usar associações de dados.Antes:
<DataTemplate x:Key="ImageGridView_DefaultItemTemplate">O
x:Keyvalor é usado peloImageGridViewpara selecionar este modelo para exibir objetos de dados.Adicione um
x:DataTypevalor ao modelo.Após:
<DataTemplate x:Key="ImageGridView_DefaultItemTemplate" x:DataType="local:ImageFileInfo">x:DataTypeindica para qual tipo esse modelo serve. Nesse caso, é um modelo para a classeImageFileInfo(ondelocal:indica o namespace local, conforme definido em uma declaração xmlns no topo do arquivo).Você precisa de
x:DataTypeao usar expressõesx:Bindem um template de dados, conforme descrito a seguir.No
DataTemplate, localize o elementoImagenomeadoItemImagee substitua o valor deSourceconforme mostrado.Antes:
<Image x:Name="ItemImage" Source="/Assets/StoreLogo.png" Stretch="Uniform" />Após:
<Image x:Name="ItemImage" Source="{x:Bind ImageSource}" Stretch="Uniform" />x:Nameidentifica um elemento XAML para que você possa se referir a ele em outro lugar no XAML e no code-behind.expressões atribuem um valor a uma propriedade de interface do usuário ao obter o valor de uma propriedade de um objeto de dados . Em modelos, a propriedade indicada é uma propriedade de qualquer coisa à qual o x:DataTypeesteja definido. Portanto, nesse caso, a fonte de dados é aImageFileInfo.ImageSourcepropriedade.Observação
O
x:Bindvalor também permite que o editor saiba sobre o tipo de dados, para que você possa usar o IntelliSense em vez de digitar o nome da propriedade em umax:Bindexpressão. Experimente no código que você acabou de colar: coloque o cursor logo depoisx:Binde pressione a Barra de espaços para ver uma lista de propriedades às quais você pode associar.Substitua os valores dos outros controles de interface do usuário da mesma maneira. (Tente fazer isso com o IntelliSense em vez de copiar/colar!)
Antes:
<TextBlock Text="Placeholder" ... /> <StackPanel ... > <TextBlock Text="PNG file" ... /> <TextBlock Text="50 x 50" ... /> </StackPanel> <muxc:RatingControl Value="3" ... />Após:
<TextBlock Text="{x:Bind ImageTitle}" ... /> <StackPanel ... > <TextBlock Text="{x:Bind ImageFileType}" ... /> <TextBlock Text="{x:Bind ImageDimensions}" ... /> </StackPanel> <muxc:RatingControl Value="{x:Bind ImageRating}" ... />
Execute o aplicativo para ver a aparência dele até agora. Não mais espaços reservados! Você está começando bem.
Observação
Se você quiser experimentar mais, tente adicionar um novo TextBlock ao modelo de dados e use o truque x:Bind IntelliSense para encontrar uma propriedade a ser exibida.
Parte 2: Usar associação para conectar a interface do usuário da galeria às imagens
Nesta seção, você criará associações únicas no XAML da página para conectar a visão de galeria à coleção de imagens. Essas associações substituem o código de procedimento existente no code-behind. Você também cria um botão Excluir para ver como a exibição da galeria muda quando você remove imagens da coleção. Ao mesmo tempo, você aprenderá a associar eventos a manipuladores de eventos para obter mais flexibilidade do que os manipuladores de eventos tradicionais.
Todas as associações abordadas até agora estão dentro de modelos de dados e referem-se às propriedades da classe indicadas pelo valor x:DataType. E quanto ao restante do XAML na sua página?
x:Bind expressões fora dos modelos de dados sempre se vinculam à própria página. Isso significa que você pode referenciar qualquer coisa que você colocar em code-behind ou declarar em XAML, incluindo propriedades personalizadas e propriedades de outros controles de interface do usuário na página (desde que eles tenham um valor x:Name).
No exemplo do PhotoLab, você usa uma associação como esta para conectar o controle principal GridView diretamente à coleção de imagens, em vez de fazê-lo em code-behind. Mais tarde, você verá outros exemplos.
Associar o controle GridView principal à coleção Images
Em MainPage.xaml.cs, localize o
GetItemsAsyncmétodo e remova o código que defineItemsSource.Antes:
ImageGridView.ItemsSource = Images;Após:
// Replaced with XAML binding: // ImageGridView.ItemsSource = Images;Em MainPage.xaml, localize o
GridViewchamadoImageGridViewe adicione o atributoItemsSource. Para o valor, use uma expressãox:Bindque se refere à propriedadeImagesimplementada no código subjacente.Antes:
<GridView x:Name="ImageGridView"Após:
<GridView x:Name="ImageGridView" ItemsSource="{x:Bind Images}"A propriedade
Imagesé do tipoObservableCollection<ImageFileInfo>, portanto, os itens individuais exibidos noGridViewsão do tipoImageFileInfo. Esse tipo corresponde aox:DataTypevalor descrito na Parte 1.
Todas as associações que você viu anteriormente são associações únicas, somente leitura, que é o comportamento padrão para expressões simples x:Bind . Os dados são carregados somente na inicialização, o que torna as associações de alto desempenho perfeitas para dar suporte a várias exibições complexas de grandes conjuntos de dados.
Até mesmo a associação ItemsSource que você acabou de adicionar é uma associação única, somente leitura, a um valor de propriedade inalterado, mas há uma distinção importante a fazer aqui. O valor inalterado da Images propriedade é uma única instância específica de uma coleção, inicializada uma vez, conforme mostrado aqui.
private ObservableCollection<ImageFileInfo> Images { get; }
= new ObservableCollection<ImageFileInfo>();
O Images valor da propriedade nunca é alterado, mas como a propriedade é do tipo ObservableCollection<T>, o conteúdo da coleção pode ser alterado e a associação percebe automaticamente as alterações e atualiza a interface do usuário.
Para testar esse comportamento, adicione temporariamente um botão que exclui a imagem selecionada no momento. Esse botão não está na versão final porque selecionar uma imagem leva você a uma página de detalhes. No entanto, o comportamento de ObservableCollection<T> ainda é importante no exemplo final do PhotoLab, porque o XAML é inicializado no construtor da página (por meio da chamada do método InitializeComponent), mas a coleção Images é preenchida posteriormente no método GetItemsAsync.
Adicionar um botão de exclusão
Em MainPage.xaml, encontre o
CommandBarnomeado MainCommandBar e adicione um novo botão antes do botão de zoom. (Os controles de zoom ainda não funcionam. Você os conectará na próxima parte do tutorial.)<AppBarButton Icon="Delete" Label="Delete selected image" Click="{x:Bind DeleteSelectedImage}" />Se você já estiver familiarizado com XAML, esse
Clickvalor pode parecer incomum. Nas versões anteriores do XAML, você precisava definir isso como um método com uma assinatura específica do manipulador de eventos, normalmente incluindo parâmetros para o remetente de eventos e um objeto de argumentos específicos do evento. Você ainda pode usar essa técnica quando precisar dos argumentos do evento, mas comx:Bind, você também pode se conectar a outros métodos. Por exemplo, se você não precisar dos dados do evento, poderá se conectar a métodos que não têm parâmetros, como fazemos aqui.Em MainPage.xaml.cs, adicione o
DeleteSelectedImagemétodo.private void DeleteSelectedImage() => Images.Remove(ImageGridView.SelectedItem as ImageFileInfo);Esse método simplesmente exclui a imagem selecionada da
Imagescoleção.
Agora, execute o aplicativo e use o botão para excluir algumas imagens. Como você pode ver, a interface do usuário é atualizada automaticamente, graças à vinculação de dados e ao tipo ObservableCollection<T>.
Observação
Esse código exclui apenas a ImageFileInfo instância da Images coleção no aplicativo em execução. Ele não exclui o arquivo de imagem do computador.
Parte 3: Configurar o controle deslizante de zoom
Nesta parte, você criará associações unidirecionais de um controle no modelo de dados para o controle deslizante de zoom, que está fora do modelo. Você também aprenderá que pode usar a associação de dados com muitas propriedades de controle, não apenas as mais óbvias como TextBlock.Text e Image.Source.
Associar o modelo de dados de imagem ao controle deslizante de zoom
Encontre o
DataTemplatechamadoImageGridView_DefaultItemTemplatee substitua os valores**Height**eWidthdo elemento de controleGridna parte superior do modelo.Antes
<DataTemplate x:Key="ImageGridView_DefaultItemTemplate" x:DataType="local:ImageFileInfo"> <Grid Height="200" Width="200" Margin="{StaticResource LargeItemMargin}">Depois
<DataTemplate x:Key="ImageGridView_DefaultItemTemplate" x:DataType="local:ImageFileInfo"> <Grid Height="{Binding Value, ElementName=ZoomSlider}" Width="{Binding Value, ElementName=ZoomSlider}" Margin="{StaticResource LargeItemMargin}">
Você notou que estas são Binding expressões, e não x:Bind expressões? Essa é a maneira antiga de fazer associações de dados e é praticamente obsoleta.
x:Bind faz quase tudo o que Binding faz, e muito mais. No entanto, quando você usa x:Bind em um modelo de dados, ele se associa ao tipo declarado ao valor de x:DataType. Então, como você associa algo no modelo a algo na página XAML ou em code-behind? Você deve usar uma expressão Binding de estilo antigo.
Binding as expressões não reconhecem o x:DataType valor, mas essas Binding expressões têm ElementName valores que funcionam quase da mesma maneira. Elas informam ao mecanismo de associação que o valor de associação é uma ligação à propriedade Value do elemento especificado na página (ou seja, o elemento com esse valor x:Name). Se você quiser associar à uma propriedade em code-behind, ela será semelhante a {Binding MyCodeBehindProperty, ElementName=page}, onde page se refere ao valor x:Name definido no elemento Page em XAML.
Observação
Por padrão, Binding expressões são umamaneira, o que significa que elas atualizarão automaticamente a interface do usuário quando o valor da propriedade associada for alterado.
Por outro lado, o padrão para x:Bind é um "tempo", o que significa que qualquer alteração na propriedade vinculada é ignorada. Esse é o padrão porque é a opção de maior desempenho e a maioria das associações é para dados estáticos somente leitura.
A lição aqui é que, se você usar x:Bind com propriedades que podem alterar seus valores, não deixe de adicionar Mode=OneWay ou Mode=TwoWay. Você verá exemplos disso na próxima seção.
Execute o aplicativo e use o controle deslizante para alterar as dimensões de modelo de imagem. Como você pode ver, o efeito é bastante poderoso sem precisar de muito código.
Observação
Para um desafio, tente vincular outras propriedades de interface de usuário à propriedade do controle deslizante de zoom Value ou a outros controles deslizantes que você adicionar depois do controle deslizante de zoom. Por exemplo, você pode associar a propriedade FontSize do TitleTextBlock a um novo controle deslizante (slider) com um valor padrão de 24. Certifique-se de definir valores mínimos e máximos razoáveis.
Parte 4: Melhorar a experiência de zoom
Nesta parte, você adicionará uma propriedade personalizada ItemSize ao code-behind e criará associações unidirecionais do modelo de imagem à nova propriedade. O valor ItemSize será atualizado pelo controle deslizante de zoom e outros fatores, como o alternador Ajustar à tela e o tamanho da janela, oferecendo uma experiência mais refinada.
Ao contrário das propriedades internas de controle, suas propriedades personalizadas não atualizam automaticamente a UI, mesmo com associações unidirecionais e bidirecionais. Eles funcionam bem com associações de umtempo, mas se você quiser que suas alterações de propriedade realmente apareçam na interface do usuário, você precisa fazer algum trabalho.
Criar a propriedade ItemSize para que ela atualize a interface do usuário
Em MainPage.xaml.cs, altere a assinatura da classe
MainPagepara que ela implemente a interfaceINotifyPropertyChanged.Antes:
public sealed partial class MainPage : PageApós:
public sealed partial class MainPage : Page, INotifyPropertyChangedIsso informa ao sistema de associação que
MainPagetem um eventoPropertyChanged(adicionado em seguida) que as associações podem escutar para atualizar a interface do usuário.Adicione um
PropertyChangedevento àMainPageclasse.public event PropertyChangedEventHandler PropertyChanged;Esse evento fornece a implementação completa exigida pela
INotifyPropertyChangedinterface. No entanto, para que ele tenha qualquer efeito, você deve explicitamente gerar o evento em suas propriedades personalizadas.Adicione uma propriedade
ItemSizee acione o eventoPropertyChangedem seu setter.public double ItemSize { get => _itemSize; set { if (_itemSize != value) { _itemSize = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ItemSize))); } } } private double _itemSize;A propriedade
ItemSizeexpõe o valor de um campo privado chamado_itemSize. Usar um campo de backup como esse permite que a propriedade verifique se um novo valor é o mesmo que o valor antigo antes de gerar um evento potencialmente desnecessárioPropertyChanged.O evento em si é gerado pelo método
Invoke. O ponto de interrogação verifica se oPropertyChangedevento é nulo , ou seja, se algum manipulador de eventos foi adicionado ainda. Cada associação unidirecional ou bidirecional adiciona um manipulador de eventos nos bastidores, mas se ninguém está ouvindo, nada mais acontece aqui. SePropertyChangednão for nulo, no entanto, seráInvokechamado com uma referência à origem do evento (a própria página, representada pelathispalavra-chave) e um objeto event-args que indica o nome da propriedade. Com essas informações, todas as associações unidirecionais ou bidirecionais à propriedadeItemSizeserão notificadas de quaisquer alterações para que possam atualizar a UI vinculada.Em MainPage.xaml, encontre o
DataTemplatenomeadoImageGridView_DefaultItemTemplatee substitua osHeighteWidthvalores do controleGridno topo do modelo. (Se você fez a associação de controle a controle na parte anterior deste tutorial, as únicas alterações são substituirValueporItemSizeeZoomSliderporpage. Certifique-se de fazer isso para ambosHeighteWidth!)Antes
<DataTemplate x:Key="ImageGridView_DefaultItemTemplate" x:DataType="local:ImageFileInfo"> <Grid Height="{Binding Value, ElementName=ZoomSlider}" Width="{Binding Value, ElementName=ZoomSlider}" Margin="{StaticResource LargeItemMargin}">Depois
<DataTemplate x:Key="ImageGridView_DefaultItemTemplate" x:DataType="local:ImageFileInfo"> <Grid Height="{Binding ItemSize, ElementName=page}" Width="{Binding ItemSize, ElementName=page}" Margin="{StaticResource LargeItemMargin}">
Agora que a interface do usuário pode responder a alterações em ItemSize, você realmente precisa fazer algumas mudanças. Conforme mencionado anteriormente, o ItemSize valor é calculado do estado atual de vários controles de interface do usuário, mas o cálculo deve ser executado sempre que esses controles alterarem o estado. Para fazer isso, você usará a associação de eventos para que determinadas alterações de interface do usuário chamem um método auxiliar que atualiza ItemSize.
Atualizar o valor da propriedade ItemSize
Adicione o
DetermineItemSizemétodo ao MainPage.xaml.cs.private void DetermineItemSize() { if (FitScreenToggle != null && FitScreenToggle.IsOn == true && ImageGridView != null && ZoomSlider != null) { // The 'margins' value represents the total of the margins around the // image in the grid item. 8 from the ItemTemplate root grid + 8 from // the ItemContainerStyle * (Right + Left). If those values change, // this value needs to be updated to match. int margins = (int)this.Resources["LargeItemMarginValue"] * 4; double gridWidth = ImageGridView.ActualWidth - (int)this.Resources["DefaultWindowSidePaddingValue"]; double ItemWidth = ZoomSlider.Value + margins; // We need at least 1 column. int columns = (int)Math.Max(gridWidth / ItemWidth, 1); // Adjust the available grid width to account for margins around each item. double adjustedGridWidth = gridWidth - (columns * margins); ItemSize = (adjustedGridWidth / columns); } else { ItemSize = ZoomSlider.Value; } }Em MainPage.xaml, navegue até a parte superior do arquivo e adicione uma
SizeChangedassociação de evento aoPageelemento.Antes:
<Page x:Name="page"Após:
<Page x:Name="page" SizeChanged="{x:Bind DetermineItemSize}"Localize o
SlidernomeadoZoomSlider(na seçãoPage.Resources) e adicione uma associação de eventosValueChanged.Antes:
<Slider x:Name="ZoomSlider"Após:
<Slider x:Name="ZoomSlider" ValueChanged="{x:Bind DetermineItemSize}"Localize o
ToggleSwitchnomeadoFitScreenTogglee adicione uma associação de eventosToggled.Antes:
<ToggleSwitch x:Name="FitScreenToggle"Após:
<ToggleSwitch x:Name="FitScreenToggle" Toggled="{x:Bind DetermineItemSize}"
Execute o aplicativo e use o controle deslizante de zoom e a opção Ajustar à tela para modificar as dimensões do modelo de imagem. Como você pode ver, as alterações mais recentes permitem uma experiência de zoom/redimensionamento mais refinada, mantendo o código bem organizado.
Observação
Para um desafio, tente adicionar um TextBlock depois do ZoomSlider e vincular a propriedade Text à propriedade ItemSize. Como ele não está em um modelo de dados, você pode usar x:Bind em vez de Binding como nas associações anteriores ItemSize .
Parte 5: Habilitar edições de usuário
Aqui, você criará associações bidirecionais para permitir que os usuários atualizem valores, incluindo o título da imagem, a classificação e vários efeitos visuais.
Para fazer isso, você atualizará o DetailPageexistente, que fornece um visualizador de uma única imagem, controle de zoom e interface de edição.
Primeiro, no entanto, você precisa anexar o DetailPage para que o aplicativo navegue até ele quando o usuário clicar em uma imagem no modo de exibição da galeria.
Anexar a página de detalhes
Encontre o
GridViewdenominadoImageGridViewem MainPage.xaml. Para tornar os itens clicáveis, definaIsItemClickEnabledparaTruee adicione um manipulador de eventosItemClick.Dica
Se você digitar a alteração abaixo em vez de copiar/colar, verá um pop-up do IntelliSense que diz "<Novo Manipulador de Eventos>". Se você pressionar a tecla Tab, ela preencherá o valor com um nome de manipulador de método padrão e excluirá automaticamente o método mostrado na próxima etapa. Em seguida, você pode pressionar F12 para navegar até o método no código subjacente.
Antes:
<GridView x:Name="ImageGridView">Após:
<GridView x:Name="ImageGridView" IsItemClickEnabled="True" ItemClick="ImageGridView_ItemClick">Observação
Estamos usando um manipulador de eventos convencional aqui em vez de uma expressão x:Bind. Isso ocorre porque precisamos ver os dados do evento, conforme mostrado a seguir.
Em MainPage.xaml.cs, adicione o manipulador de eventos (ou preencha-o, se você usou a dica na última etapa).
private void ImageGridView_ItemClick(object sender, ItemClickEventArgs e) { this.Frame.Navigate(typeof(DetailPage), e.ClickedItem); }Esse método simplesmente navega até a página de detalhes, passando o item clicado, que é um
ImageFileInfoobjeto usado por DetailPage.OnNavigatedTo para inicializar a página. Você não precisará implementar esse método neste tutorial, mas pode dar uma olhada para ver o que ele faz.(Opcional) Exclua ou comente todos os controles adicionados em pontos de reprodução anteriores que funcionam com a imagem selecionada no momento. Mantê-los por perto não prejudicará nada, mas agora é muito mais difícil selecionar uma imagem sem navegar até a página de detalhes.
Agora que você conectou as duas páginas, execute o aplicativo e dê uma olhada. Tudo funciona, exceto os controles no painel de edição, que não respondem quando você tenta alterar os valores.
Como você pode ver, a caixa de texto do título exibe o título e permite que você digite alterações. Você precisa alterar o foco para outro controle para confirmar as alterações, mas o título no canto superior esquerdo da tela ainda não é atualizado.
Todos os controles já estão associados usando as expressões simples x:Bind que discutimos na Parte 1. Se você se lembrar, isso significa que todas elas são associações pontuais, o que explica por que as alterações nos valores não são registradas. Para corrigir isso, tudo o que precisamos fazer é transformá-los em associações bidirecionais.
Tornar os controles de edição interativos
Em DetailPage.xaml, encontre o
TextBlockchamado TitleTextBlock e o controle RatingControl depois dele, e atualize suas expressõesx:Bindpara incluir Mode=TwoWay.Antes:
<TextBlock x:Name="TitleTextBlock" Text="{x:Bind item.ImageTitle}" ... > <muxc:RatingControl Value="{x:Bind item.ImageRating}" ... >Após:
<TextBlock x:Name="TitleTextBlock" Text="{x:Bind item.ImageTitle, Mode=TwoWay}" ... > <muxc:RatingControl Value="{x:Bind item.ImageRating, Mode=TwoWay}" ... >Faça a mesma coisa para todos os controles deslizantes de efeito que vêm após o controle de classificação.
<Slider Header="Exposure" ... Value="{x:Bind item.Exposure, Mode=TwoWay}" ... <Slider Header="Temperature" ... Value="{x:Bind item.Temperature, Mode=TwoWay}" ... <Slider Header="Tint" ... Value="{x:Bind item.Tint, Mode=TwoWay}" ... <Slider Header="Contrast" ... Value="{x:Bind item.Contrast, Mode=TwoWay}" ... <Slider Header="Saturation" ... Value="{x:Bind item.Saturation, Mode=TwoWay}" ... <Slider Header="Blur" ... Value="{x:Bind item.Blur, Mode=TwoWay}" ...
O modo bidirecional, como você pode esperar, significa que os dados se movem em ambas as direções sempre que houver alterações em ambos os lados.
Assim como as associações unidirecionais abordadas anteriormente, essas associações bidirecionais agora atualizarão a interface do usuário sempre que as propriedades associadas forem alteradas, graças à INotifyPropertyChanged implementação na ImageFileInfo classe. No entanto, com a associação bidirecional, os valores também serão movidos da interface do usuário para as propriedades associadas sempre que o usuário interagir com o controle. Nada mais é necessário do lado XAML.
Execute o aplicativo e experimente os controles de edição. Como você pode ver, quando você faz uma alteração, ela agora afeta os valores de imagem e essas alterações persistem quando você navega de volta para a página principal.
Parte 6: Formatar valores por meio da associação de função
Um último problema permanece. Quando você move os controles deslizantes de efeito, os rótulos ao lado deles ainda não são alterados.
Sliders de efeito 
A parte final deste tutorial é adicionar vinculações que formatem os valores do controle deslizante para exibição.
Vincular os rótulos do deslizante de efeito e formatar os valores para exibição
Encontre o
TextBlockapós o controle deslizanteExposuree substitua o valorTextpela expressão de associação mostrada aqui.Antes:
<Slider Header="Exposure" ... /> <TextBlock ... Text="0.00" />Após:
<Slider Header="Exposure" ... /> <TextBlock ... Text="{x:Bind item.Exposure.ToString('N', culture), Mode=OneWay}" />Isso é chamado de vinculação de função porque você está vinculando ao valor de retorno de um método. O método deve ser acessível por meio do code-behind da página ou do tipo
x:DataTypese você estiver em um modelo de dados. Nesse caso, o método é o familiar método .NETToString, que é acessado pela propriedade do item da página e depois pela propriedadeExposuredo item. Isso ilustra como você pode vincular a métodos e propriedades que estão profundamente aninhados em uma cadeia de conexões.A vinculação de funções é uma maneira ideal de formatar valores para exibição, pois você pode passar outras fontes de dados de vinculação como argumentos de método, e a expressão de vinculação escutará as alterações nesses valores conforme esperado no modo unidirecional. Neste exemplo, o argumento cultura é uma referência a um campo imutável implementado no código subjacente, mas poderia muito bem ter sido uma propriedade que gera eventos
PropertyChanged. Nesse caso, qualquer alteração no valor da propriedade faria com que ax:Bindexpressão chamasseToStringcom o novo valor e atualizasse a interface do usuário com o resultado.Faça a mesma coisa para os
TextBlockque identificam os outros controles deslizantes de efeito.<Slider Header="Temperature" ... /> <TextBlock ... Text="{x:Bind item.Temperature.ToString('N', culture), Mode=OneWay}" /> <Slider Header="Tint" ... /> <TextBlock ... Text="{x:Bind item.Tint.ToString('N', culture), Mode=OneWay}" /> <Slider Header="Contrast" ... /> <TextBlock ... Text="{x:Bind item.Contrast.ToString('N', culture), Mode=OneWay}" /> <Slider Header="Saturation" ... /> <TextBlock ... Text="{x:Bind item.Saturation.ToString('N', culture), Mode=OneWay}" /> <Slider Header="Blur" ... /> <TextBlock ... Text="{x:Bind item.Blur.ToString('N', culture), Mode=OneWay}" />
Agora, quando você executa o aplicativo, tudo funciona, incluindo os rótulos deslizantes.
controles deslizantes de efeito 
Diferenças entre Binding e x:Bind
Ao criar associações de dados em XAML em seus aplicativos UWP, você pode escolher entre Binding e x:Bind. Aqui estão as principais diferenças:
-
x:Bind: fornece validação em tempo de compilação, melhor desempenho e é com tipagem rigorosa. Ele é mais adequado para cenários em que a estrutura de dados é conhecida em tempo de compilação. -
Binding: oferece avaliação em tempo de execução e maior flexibilidade para cenários dinâmicos, como quando a estrutura de dados é determinada em tempo de execução.
Cenários sem suporte por x:Bind
Embora seja x:Bind altamente eficiente, ele tem limitações em determinados cenários:
-
Estruturas de dados dinâmicas:
x:Bindnão podem ser usadas quando a estrutura de dados é determinada em runtime. -
Associação de elemento a elemento: não há suporte para associação direta entre dois elementos de interface do usuário
x:Bind. -
Herança de DataContext: ao contrário,
Binding,x:Bindnão herda automaticamente oDataContextde um elemento pai. -
Associações bidirecionais:
x:Binddá suporte a associações bidirecionais, permitindo que as alterações fluam da interface do usuário de volta para a propriedade de origem. Para que a interface do usuário seja atualizada quando a propriedade de origem for alterada (em associações unidirecionais ou bidirecionais), você deve implementarINotifyPropertyChangedem seus objetos de dados.
Para obter mais detalhes e exemplos, consulte os seguintes recursos:
Conclusão
Este tutorial deu uma amostra da associação de dados e mostrou algumas das funcionalidades disponíveis. Uma palavra de cuidado antes de encerrarmos: nem tudo é associável e, às vezes, os valores aos quais você tenta se conectar são incompatíveis com as propriedades que você está tentando associar. Há muita flexibilidade na associação, mas não funcionará em todas as situações.
Um exemplo de um problema não resolvido pela vinculação é quando um controle não tem propriedades adequadas para vincular, como é o caso da funcionalidade de zoom da página de detalhes. Esse controle deslizante de zoom precisa interagir com o ScrollViewer que exibe a imagem, mas ScrollViewer só pode ser atualizado por meio de seu ChangeView método. Nesse caso, usamos manipuladores convencionais de eventos para manter o ScrollViewer e o controle deslizante de zoom em sincronia; consulte os métodos ZoomSlider_ValueChanged e MainImageScroll_ViewChanged em DetailPage para obter detalhes.
No entanto, a associação é uma maneira poderosa e flexível de simplificar seu código e manter sua lógica de interface do usuário separada da lógica de dados. Isso facilitará muito o ajuste de um dos lados dessa divisão, reduzindo o risco de introduzir bugs no outro lado.
Um exemplo de separação entre a UI e os dados é com a propriedade ImageFileInfo.ImageTitle. Essa propriedade (e a ImageRating propriedade) é ligeiramente diferente da ItemSize propriedade que você criou na Parte 4 porque o valor é armazenado nos metadados do arquivo (expostos por meio do ImageProperties tipo) em vez de em um campo. Além disso, ImageTitle retornará o ImageName valor (definido como o nome do arquivo) se não houver nenhum título nos metadados do arquivo.
public string ImageTitle
{
get => String.IsNullOrEmpty(ImageProperties.Title) ? ImageName : ImageProperties.Title;
set
{
if (ImageProperties.Title != value)
{
ImageProperties.Title = value;
var ignoreResult = ImageProperties.SavePropertiesAsync();
OnPropertyChanged();
}
}
}
Como você pode ver, o setter atualiza a ImageProperties.Title propriedade e, em seguida, chama SavePropertiesAsync para gravar o novo valor no arquivo. (Este é um método assíncrono, mas não podemos usar a palavra-chave await em uma propriedade - e você não ia querer, porque os métodos get e set de propriedade devem ser concluídos imediatamente. Em vez disso, você deveria chamar o método e ignorar o objeto Task que ele retorna.)
Indo mais longe
Agora que concluiu este laboratório, você tem conhecimento suficiente para resolver um problema por conta própria.
Como você deve ter notado, se você alterar o nível de zoom na página de detalhes, ele será redefinido automaticamente quando você navegar para trás e selecionar a mesma imagem novamente. Você pode descobrir como preservar e restaurar o nível de zoom para cada imagem individualmente? Boa sorte!
Você deve ter todas as informações necessárias neste tutorial, mas se precisar de mais diretrizes, os documentos de associação de dados estarão a apenas um clique de distância. Começar aqui:
- Extensão de marcação {x:Bind}
- Vinculação de dados em profundidade