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.
Se você criou 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 sincronizados e melhorar a capacidade de manutenção do código.
Neste tutorial, você aprenderá como substituir seu clichê por associações de dados e criar outros links diretos entre sua interface do usuário e seus dados. Você também aprende a formatar ou converter seus dados para exibição e manter sua interface do usuário e 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 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 se baseia no aplicativo completo, portanto, certifique-se de verificar 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 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 de edição expansível permite alterar, renomear e guardar a foto.
Pré-requisitos
- Visual Studio 2019 ou posterior: Baixe o Visual Studio (A edição Community é gratuita.)
- SDK do Windows (10.0.17763.0 ou posterior): Baixe o SDK do Windows mais recente (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 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 Clone ou baixe botão. É apresentado um submenu.
Se você não estiver familiarizado com o GitHub:
a) Selecione Baixar ZIP e salve o arquivo localmente. Esta ação baixa um arquivo de .zip que contém todos os arquivos de projeto que você precisa.
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á para o diretório
Windows-appsample-photo-lab-master\xaml-basics-starting-points\data-binding.Se você está familiarizado com o GitHub:
a) Clonar o ramo principal do repositório localmente.
b) Navegue até ao diretório
Windows-appsample-photo-lab\xaml-basics-starting-points\data-binding.Clique duas vezes
Photolab.slnpara abrir a solução no Visual Studio.
Parte 1: Substitua os espaços reservados
Nesta seção, você cria associações únicas em XAML de modelo de dados para exibir imagens reais e metadados de imagem em vez de conteúdo de espaço reservado.
Ligações de utilização única são para dados de leitura única e imutáveis. Eles são de alto desempenho e fáceis de criar, para que possa exibir grandes conjuntos de dados nos GridView e ListView controles.
Substitua os marcadores de posição por associaçõ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 execute o aplicativo. Esta etapa mostra o estado do aplicativo com espaços reservados para a interface do usuário, antes que as associações sejam adicionadas.
Abra MainPage.xaml e procure por um
DataTemplatecom o nome ImageGridView_DefaultItemTemplate. Você atualizará este 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.Depois:
<DataTemplate x:Key="ImageGridView_DefaultItemTemplate" x:DataType="local:ImageFileInfo">x:DataTypeIndica a que tipo este modelo se destina. Nesse caso, é um modelo para aImageFileInfoclasse (ondelocal:indica o namespace local, conforme definido em uma declaração xmlns perto da parte superior do arquivo).Você precisa de
x:DataTypeao utilizar expressõesx:Bindnuma definição de dados, conforme descrito a seguir.No
DataTemplate, localize o elementoImagenomeadoItemImagee substitua seu valorSourceconforme mostrado.Antes:
<Image x:Name="ItemImage" Source="/Assets/StoreLogo.png" Stretch="Uniform" />Depois:
<Image x:Name="ItemImage" Source="{x:Bind ImageSource}" Stretch="Uniform" />x:Nameidentifica um elemento XAML para que você possa consultá-lo em outro lugar no XAML e no code-behind.expressões fornecem um valor para uma propriedade da interface de utilizador, obtendo o valor de uma propriedade do objeto de dados . Em modelos, a propriedade indicada é uma propriedade do que o x:DataTypeestiver configurado para. Portanto, neste 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 acabou de colar: coloque o cursor logo a seguirx:Binde prima a Barra de espaço para ver uma lista de propriedades às quais pode ligar.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" ... />Depois:
<TextBlock Text="{x:Bind ImageTitle}" ... /> <StackPanel ... > <TextBlock Text="{x:Bind ImageFileType}" ... /> <TextBlock Text="{x:Bind ImageDimensions}" ... /> </StackPanel> <muxc:RatingControl Value="{x:Bind ImageRating}" ... />
Corra a aplicação para ver como está até agora. Não há mais espaços reservados! Você está em um bom começo.
Observação
Se 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 a vinculação para conectar a interface do usuário da galeria às imagens
Nesta seção, você cria ligações únicas em XAML de página para conectar a vista de galeria à coleção de imagens. Essas ligações substituem o código processual 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ê aprende a vincular eventos a manipuladores de eventos para obter mais flexibilidade do que os manipuladores de eventos tradicionais.
Todas as associações cobertas até agora estão dentro de modelos de dados e referem-se a propriedades da classe indicada pelo x:DataType valor. E quanto ao resto do XAML na sua página?
x:Bind expressões fora dos modelos de dados sempre se ligam à própria página. Isso significa que é possível fazer referência a qualquer componente colocado no code-behind ou declarado em XAML, incluindo propriedades personalizadas e propriedades de outros controlos de interface do utilizador na página (desde que estes tenham um valor x:Name).
No exemplo PhotoLab, você usa uma ligaçã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.
Vincular o controle GridView principal à coleção Images
No MainPage.xaml.cs, localize o
GetItemsAsyncmétodo e remova o código que defineItemsSource.Antes:
ImageGridView.ItemsSource = Images;Depois:
// Replaced with XAML binding: // ImageGridView.ItemsSource = Images;Em MainPage.xaml, encontre o
GridViewchamadoImageGridViewe adicione um atributoItemsSource. Para o valor, use umax:Bindexpressão que se refira à propriedade implementadaImagesno code-behind.Antes:
<GridView x:Name="ImageGridView"Depois:
<GridView x:Name="ImageGridView" ItemsSource="{x:Bind Images}"A
Imagespropriedade é do tipoObservableCollection<ImageFileInfo>, portanto, os itens individuais exibidos noGridViewsão do tipoImageFileInfo. Este tipo corresponde aox:DataTypevalor descrito na Parte 1.
Todas as associações que observaste anteriormente são associações únicas e somente leitura, sendo o comportamento padrão para expressões simples x:Bind. Os dados são carregados apenas na inicialização, o que torna as ligações de alto desempenho, sendo perfeitas para suportar visualizações complexas múltiplas de grandes conjuntos de dados.
Mesmo a ligação ItemsSource que acabou de adicionar é uma ligação pontual, de somente leitura, a um valor de propriedade imutável, mas há uma distinção importante a ser feita aqui. O valor imutável da Images propriedade é uma instância única e 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 muda, 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. Este botão não está na versão final porque a seleção de 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 de 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, localize o
CommandBarchamado MainCommandBar e adicione um novo botão antes do botão de zoom. (Os controles de zoom ainda não funcionam. Você vai conectá-los 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. Em versões anteriores do XAML, você tinha que definir isso como um método com uma assinatura específica do manipulador de eventos, geralmente incluindo parâmetros para o remetente do evento e um objeto de argumentos específicos do evento. Você ainda pode usar essa técnica quando precisar dos argumentos de 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);Este método simplesmente exclui a imagem selecionada da
Imagescoleção.
Agora execute o aplicativo e use o botão para excluir algumas imagens. Como se pode ver, a interface do utilizador é atualizada automaticamente, graças à associaçã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á ligaçõ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 vinculação de dados com muitas propriedades de controle, não apenas as mais óbvias, como TextBlock.Text e Image.Source.
Vincular o modelo de dados de imagem ao controle deslizante de zoom
Encontre o
DataTemplatechamadoImageGridView_DefaultItemTemplatee substitua os valores**Height**eWidthdo controlo no topo 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}">
Reparou que estas são Binding expressões, e não x:Bind expressões? Esta é a maneira antiga de fazer vinculações de dados, e é principalmente 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 liga ao tipo declarado no x:DataType valor. Então, como vincular algo no modelo a algo na página XAML ou no code-behind? Você deve usar uma expressão estilo antigo Binding.
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. Eles indicam ao mecanismo de vinculação que o Valor de Vinculação é uma ligação à propriedade Value do elemento especificado na página (ou seja, o elemento que possui o valor x:Name). Se quiser associar a uma propriedade no code-behind, isso seria parecido com {Binding MyCodeBehindProperty, ElementName=page}, onde page se refere ao valor x:Name definido no elemento Page em XAML.
Observação
Por padrão, as expressões Binding são unidirecionais, o que significa que atualizarão automaticamente a interface de utilizadorquando o valor da propriedade vinculada for alterado.
Por outro lado, o padrão para x:Bind é umvez, o que significa que todas as alterações na propriedade vinculada são ignoradas. Esse é o padrão porque é a opção de maior desempenho e a maioria das ligações são para dados estáticos e somente leitura.
A lição aqui é que, se você usar x:Bind com propriedades que podem alterar seus valores, certifique-se 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 do modelo de imagem. Como você pode ver, o efeito é muito poderoso sem precisar de muito código.
Observação
Para um desafio, experimente ligar outras propriedades da interface do utilizador à propriedade do controlo deslizante de zoom Value, ou a outros controlos deslizantes que acrescentar após o controlo deslizante de zoom. Por exemplo, você pode vincular a propriedade FontSize do TitleTextBlock a um novo controle deslizante 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 para a nova propriedade. O valor ItemSize será atualizado pelo controle deslizante de zoom e por outros fatores como o alternador Ajustar à tela e o tamanho da janela, tornando a experiência mais refinada.
Ao contrário das propriedades de controlo internas, as suas propriedades personalizadas não atualizam automaticamente a UI, mesmo com vínculos unidirecionais e bidirecionais. Eles funcionam bem com ligações de de
Crie a propriedade ItemSize para que ela atualize a interface do usuário
Em MainPage.xaml.cs, altere a
MainPageassinatura da classe para que ela implemente aINotifyPropertyChangedinterface.Antes:
public sealed partial class MainPage : PageDepois:
public sealed partial class MainPage : Page, INotifyPropertyChangedIsso informa ao sistema de vinculaçã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;Este evento fornece a implementação completa exigida pela interface
INotifyPropertyChanged. No entanto, para que ele tenha algum efeito, você deve gerar explicitamente o evento em suas propriedades personalizadas.Adicione uma propriedade
ItemSizee aumente 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_itemSizeprivado. O uso de um campo de suporte como este permite que a propriedade verifique se um novo valor é igual ao 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 já foi adicionado. Cada ligação unidirecional ou bidirecional adiciona um manipulador de eventos nos bastidores, mas se ninguém estiver ouvindo, nada mais aconteceria aqui. Se, no entanto,PropertyChangednão for 'null',Invokeserá chamado com uma referência à fonte do evento (a própria página, representada pela palavra-chavethis) e um objeto de evento-args que indica o nome da propriedade. Com essas informações, todas as ligações unidirecionais ou bidirecionais à propriedadeItemSizeserão informadas de quaisquer alterações para que possam atualizar a interface de utilizador vinculada.Em MainPage.xaml, localize o
DataTemplatenomeImageGridView_DefaultItemTemplatee substitua os valores deHeighteWidthdo controlo na parte superior doGridtemplate. (Se você fez a ligação de controle para 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 de utilizador pode responder a alterações de ItemSize, é necessário realmente fazer algumas alterações. Como mencionado anteriormente, o ItemSize valor é calculado a partir do estado atual de vários controles da interface do usuário, mas o cálculo deve ser executado sempre que esses controles mudarem de estado. Para fazer isso, irá usar a associação de eventos para que determinadas alterações na interface do utilizador chamem um método auxiliar que atualize ItemSize.
Atualizar o valor da propriedade ItemSize
Adicione o
DetermineItemSizemétodo a 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"Depois:
<Page x:Name="page" SizeChanged="{x:Bind DetermineItemSize}"Localize o
SliderdenominadoZoomSlider(na seçãoPage.Resources) e adicione uma ligação de eventoValueChanged.Antes:
<Slider x:Name="ZoomSlider"Depois:
<Slider x:Name="ZoomSlider" ValueChanged="{x:Bind DetermineItemSize}"Localize o
ToggleSwitchchamadoFitScreenTogglee adicione uma associação de eventoToggled.Antes:
<ToggleSwitch x:Name="FitScreenToggle"Depois:
<ToggleSwitch x:Name="FitScreenToggle" Toggled="{x:Bind DetermineItemSize}"
Execute o aplicativo e use o controle deslizante de zoom e Ajustar à tela alternar para alterar 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 após o ZoomSlider e vincular a Text propriedade à ItemSize propriedade. 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 do usuário
Aqui, você criará ligaçõ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 conseguir isso, você atualizará o existente DetailPage, que fornece um visualizador de imagem única, controle de zoom e interface do usuário de edição.
Primeiro, no entanto, você precisa anexar o DetailPage para que o aplicativo navegue até ele quando o usuário clica em uma imagem na exibição de galeria.
Anexe a página de detalhes
Em MainPage.xaml, localize o
GridViewchamadoImageGridView. Para tornar os itens clicáveis, definaIsItemClickEnabledcomoTruee adicione um manipulador deItemClickeventos.Sugestão
Se você digitar a alteração abaixo em vez de copiar/colar, verá um pop-up do IntelliSense que diz "<New Event Handler>". 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, podes pressionar F12 para navegar até o método no código de fundo.
Antes:
<GridView x:Name="ImageGridView">Depois:
<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, como mostrado a seguir.
No 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 terá que implementar esse método neste tutorial, mas você 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 fará mal a 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 ao redor. 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 as alterações. Você precisa mudar o foco para outro controle para confirmar as alterações, mas o título no canto superior esquerdo da tela ainda não foi atualizado.
Todos os controles já estão vinculados usando as expressões simples x:Bind que abordamos na Parte 1. Se você se lembrar, isso significa que todos eles são ligações únicas, o que explica por que as alterações nos valores não são registradas. Para corrigir isto, tudo o que temos de fazer é transformá-las em ligações bidirecionais.
Tornar os controles de edição interativos
Em DetailPage.xaml, localize o
chamado TitleTextBlock e o controle RatingControl depois dele e atualize suas expressões para incluir Mode=TwoWay .Antes:
<TextBlock x:Name="TitleTextBlock" Text="{x:Bind item.ImageTitle}" ... > <muxc:RatingControl Value="{x:Bind item.ImageRating}" ... >Depois:
<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 seria de esperar, significa que os dados se movem em ambas as direções sempre que há alterações em ambos os lados.
Como as ligações unidirecionais abordadas anteriormente, essas ligações bidirecionais agora atualizarão a interface do usuário sempre que as propriedades vinculadas forem alteradas, graças à INotifyPropertyChanged implementação na ImageFileInfo classe. Com a associação bidirecional, no entanto, 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. No lado XAML, nada mais é necessário.
Execute o aplicativo e tente os controles de edição. Como você pode ver, quando você faz uma alteração, ela agora afeta os valores da imagem, e essas alterações persistem quando você navega de volta para a página principal.
Parte 6: Formatar valores através da vinculação de funções
Subsiste um último problema. Quando você move os controles deslizantes de efeito, os rótulos ao lado deles ainda não mudam.
A parte final deste tutorial é adicionar associações que formatam os valores do controle deslizante para exibição.
Vincular os rótulos do controle deslizante de efeitos e formatar os valores para exibição
Encontre o
TextBlockapós o controlo deslizanteExposuree substitua o valor deTextpela expressão de ligação mostrada aqui.Antes:
<Slider Header="Exposure" ... /> <TextBlock ... Text="0.00" />Depois:
<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 através do code-behind da página ou do tipo
x:DataTypese você estiver em um modelo de dados. Nesse caso, o método é o conhecido método .NETToString, que é acessado através da propriedade item da página e, em seguida, através da propriedadeExposuredo item. (Isso ilustra como se pode ligar a métodos e propriedades que estão profundamente aninhados numa cadeia de conexões.)A vinculação de função é uma maneira ideal de formatar valores para exibição porque você pode passar outras fontes de vinculação como argumentos de método, e a expressão de vinculação escutará as alterações nesses valores conforme esperado com o modo unidirecional. Neste exemplo, o argumento cultura
é uma referência a um campo imutável implementado em code-behind, mas poderia facilmente ter sido uma propriedade que gera eventos . Nesse caso, quaisquer alterações no valor da propriedade fariam com que a x:Bindexpressão chamasseToStringcom o novo valor e, em seguida, atualizasse a interface do usuário com o resultado.Faça a mesma coisa para os
TextBlockque rotulam 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 do controle deslizante.
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 é fortemente tipificado. É mais adequado para cenários em que a estrutura de dados é conhecida em tempo de compilação. -
Binding: Oferece avaliação de 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 não suportados por x:Bind
Embora x:Bind seja altamente eficiente, 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 tempo de execução. -
Vinculação de elemento a elemento: a vinculação direta entre dois elementos da interface do usuário não é suportada pelo
x:Bind. - Herança DataContext: Ao contrário de
Binding,x:Bindnão herda automaticamente oDataContextde um elemento pai. -
Ligações bidirecionais:
x:Bindsuporta ligações bidirecionais, permitindo que as alterações fluam da interface do usuário de volta para a propriedade de origem. Para que a interface de utilizador seja atualizada quando a propriedade fonte for alterada (em ligações unidirecionais ou bidirecionais), é necessário implementarINotifyPropertyChangednos seus objetos de dados.
Para obter mais detalhes e exemplos, consulte os seguintes recursos:
Conclusão
Este tutorial deu-lhe uma amostra da vinculação de dados e mostrou-lhe algumas das funcionalidades disponíveis. Uma palavra de cautela antes de terminarmos: nem tudo é vinculável e, às vezes, os valores aos quais você tenta se conectar são incompatíveis com as propriedades que você está tentando vincular. Há muita flexibilidade na vinculação, mas ela não funcionará em todas as situações.
Um exemplo de um problema não resolvido pela associação é quando um controle não tem propriedades adequadas para vincular, como acontece com o recurso de zoom de página de detalhes. Este controle deslizante de zoom precisa interagir com o ScrollViewer que exibe a imagem, mas ScrollViewer só pode ser atualizado através de seu ChangeView método. Nesse caso, usamos manipuladores de eventos convencionais para manter o ScrollViewer e o controle deslizante de zoom sincronizados; consulte os métodos ZoomSlider_ValueChanged e MainImageScroll_ViewChanged em DetailPage para obter mais detalhes.
No entanto, a vinculação é uma maneira poderosa e flexível de simplificar seu código e manter a lógica da interface do usuário separada da lógica de dados. Isso tornará muito mais fácil para você ajustar ambos os lados dessa divisão, reduzindo o risco de introduzir bugs do outro lado.
Um exemplo de separação de dados e interface de utilizador é com a propriedade ImageFileInfo.ImageTitle. Essa propriedade (e a ImageRating propriedade) é ligeiramente diferente da ItemSize propriedade criada na Parte 4 porque o valor é armazenado nos metadados do arquivo (expostos através do ImageProperties tipo) em vez de em um campo. Além disso, ImageTitle retorna 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 gostaria porque os getters e setters de propriedade devem concluir imediatamente. Então, em vez disso, você chamaria o método e ignoraria o objeto Task que ele retorna.)
Ir mais longe
Agora que você 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, em seguida, selecionar a mesma imagem novamente. Você consegue 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 orientação, os documentos de vinculação de dados estão a apenas um clique de distância. Começar aqui:
- extensão de marcação {x:Bind}
- Vinculação de dados aprofundada