Este artigo foi traduzido por máquina.

Fronteiras da interface do usuário

O que é “in” e “out” no ItemsControl

Charles Petzold

Baixe o código de exemplo

Charles PetzoldSe alguém perguntar a que classe única mais sintetizou o poder e flexibilidade do Silverlight e do Windows Presentation Foundation (WPF), eu diria pela primeira vez que ele é uma pergunta boba e, em seguida, sem hesitation de um pouco, responde “ DataTemplate ”.

Um DataTemplate é basicamente uma árvore visual de elementos e controles.Os programadores usar DataTemplates para dar uma aparência visual para objetos de dados não-visuais.Propriedades dos elementos da árvore visual são vinculadas às propriedades dos objetos de dados por meio de ligações.Embora o DataTemplate é normalmente usado para definir a aparência dos objetos em um ListBox (uma das classes que derivam de ItemsControl) ou de um ItemsControl, você também pode usar um DataTemplate para definir a aparência de um objeto, defina a propriedade Content de um ContentControl ou um derivado de ContentControl, como, por exemplo, um botão.

Criar um DataTemplate — ou qualquer outro tipo de derivativo FrameworkTemplate, como o ControlTemplate ou HierarchicalDataTemplate — é uma das algumas tarefas de programação do Silverlight que não podem ser feitas no código.Você precisa usar o XAML.Ele era possível criar modelos WPF inteiramente no código usando ElementFactory Framework, mas acho que eu era a única pessoa realmente publicar exemplos (nos capítulos 11, 13 e 16 do meu livro, “ Applications = Code + Markup ” [Microsoft Press, 2006]) e a técnica agora foi preterida.

O que quero mostrar a você neste artigo é uma variação de arrastar e soltar: O usuário simplesmente move um item de um ItemsControl para outro.Mas meu objetivo principal é implementar esse processo inteiro com um inteiramente fluido aparência que pareça natural e onde nada repentinamente jerks ou desaparece.É claro que, “ aparência natural ” painstakingly geralmente é obtida e qualquer programa que se esforça para fluidity precisa evitar revelar todos machinations estranhas imediatamente abaixo da superfície.

Eu esteja usando uma combinação de técnicas que mostrei na coluna do mês passado (“ Pensando externamente a grade de , ”) como também um DataTemplate que é compartilhado entre dois ItemsControls e um ContentControl — um conceito essencial para todo esse programa.

Programa de layout

O código para download que acompanha este artigo contém um único projeto do Silverlight chamado ItemsControlTransitions, que pode ser executado a partir de meu site da Web em charlespetzold.com/silverlight/ItemsControlTransitions2 de .(Explicarei a “ 2 ” no final desse URL posteriormente.) Você pode usar os mesmos conceitos apresentados neste programa o Silverlight em um programa do WPF.

O programa exibe dois controles de itens, ambos continham em ScrollViewers.Você pode visualizar o ItemsControl, à esquerda como “ mercado ”, venda de produzir.À direita é “ cesta ”. Você pode usar o mouse para separar itens de produção do mercado e mova-os ao carrinho.A Figura 1 mostra o item de Milho na transição do mercado para o carrinho.

Figure 1 The ItemsControlTransitions Display
Figura 1 O vídeo ItemsControlTransitions

Embora o item de Milho foi movido para fora do mercado, observe a diferença de ItemsControl, que continua para indicar a origem do item.Se o usuário solta o botão do mouse antes do item arrastado tem sido posicionado sobre o controle de itens do carrinho, o programa anima o item de volta para o mercado.Somente quando o item é descartado ao carrinho essa lacuna fechar, novamente com uma animação.Dependendo de onde o item for cancelado, uma lacuna animada é aberto para receber o item e o item será animado em uma posição.

Depois que um item foi movido do mercado, ele não existe mais lá, mas que é um detalhe de programa que pode ser alterado facilmente.Nenhum recurso existente para remover um item do carrinho de compras e movê-lo de volta para o mercado, mas esse recurso, ou algo semelhante poderia ser adicionado facilmente de também.

A Figura 2 mostra a maior parte do arquivo XAML responsável para o layout básico.(Ausentes são dois storyboards com sete animações que descreverei mais tarde).

Do arquivo parcial de XAML responsável para o layout básico, a Figura 2

<UserControl x:Class="ItemsControlTransitions.MainPage"   
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  Name="this">
    <UserControl.Resources>
      <DataTemplate x:Key="produceDataTemplate">
        <Border Width="144"
          Height="144"
          BorderBrush="Black"
          BorderThickness="1"
          Background="AliceBlue"
          Margin="6">
          <Grid>
            <Grid.RowDefinitions>
              <RowDefinition Height="*" />
              <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>

            <Image Grid.Row="0"
              Source="{Binding Photo}" />
            <TextBlock Grid.Row="1"
              Text="{Binding Name}"
              HorizontalAlignment="Center" />
          </Grid>
        </Border>
      </DataTemplate>

        ...
        
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="White">
        <ScrollViewer HorizontalAlignment="Left"
          Margin="48">
            <ItemsControl Name="market"
              ItemTemplate="{StaticResource produceDataTemplate}"
                Width="156"
                MouseLeftButtonDown="OnMarketItemsControlMouseLeftButtonDown" />
        </ScrollViewer>

        <ScrollViewer HorizontalAlignment="Right"
          Margin="48">
            <ItemsControl Name="basket"
              ItemTemplate="{StaticResource produceDataTemplate}"
            Width="156" />
        </ScrollViewer>

        <Canvas Name="dragCanvas">
          <ContentControl Name="dragControl"
            ContentTemplate="{StaticResource produceDataTemplate}"
            Visibility="Collapsed" />
        </Canvas>
    </Grid>
</UserControl>

A seção de recursos contém um DataTemplate para exibir os itens de produção e uma referência a esse recurso está definida para a propriedade ItemsTemplate de ItemsControls os dois.

Além disso, um Canvas abrange toda a área ocupada pelo programa.Você vai se lembrar da coluna do mês passado como você pode usar a tela de desenho para itens de host precisa “ float ” sobre o restante da interface do usuário.O filho somente esta tela de desenho é um ContentControl, com seu ContentTemplate também definido para esse DataTemplate.Mas a visibilidade da propriedade é definida como recolhida por este ContentControl é inicialmente invisível.

Controles que derivam de ContentControl costumam comuns em aplicativos do WPF e Silverlight, mas ele não que você vir um ContentControl propriamente dito.Ele é extremamente útil se você deseja exibir um objeto usando um DataTemplate.Visualmente, é muito parecido com um único item em um ItemsControl.

O programa começa pela carga em um pequeno banco de dados XML de alguns produzem — usando os mesmos arquivos do projeto ItemsControlPopouts na coluna do mês passado – e, em seguida, preenchendo o ItemsControl no mercado com objetos do tipo ProduceItem.Essa classe tem propriedades Name e fotos que faz referência ao DataTemplate para exibir cada item.

Puxando os itens de ItemsControl

O ItemsControl para o mercado tem um manipulador para MouseLeftButtonDown.Ao receber este evento, o programa precisa Deslocar um item da parede quatro limites de ItemsControl e permiti-lo controlar o mouse.Mas, na verdade, não é possível remover o item de ItemsControl, ou o espaço será fechado automaticamente.

Como demonstrei na coluna do mês passado, você pode acessar a propriedade ItemContainerGenerator de um ItemsControl para obter uma classe que pode associar um ItemsControl cada item da árvore visual gerada para exibir esse item.Essa árvore visual tem um elemento raiz do tipo ContentPresenter.

Meu primeiro impulso foi um TranslateTransform aplicam-se para a propriedade RenderTransform do ContentPresenter, para permitir que ele flutuar fora o ItemsControl.Eu sei de experiência, no entanto, isso não funcionar em todos os.O problema não for o ItemsControl propriamente dito; o problema é ScrollViewer, qual necessidade clipes de seus filhos para seu interior.(Mais informações sobre o raciocínio por trás de corte daqui a pouco.)

Em vez disso, o programa copia o ProduceItem clicado em ItemsControl para o ContentControl e posiciona o ContentControl exatamente sobre o ContentPresenter do item clicado.(O programa pode obter a localização do ContentPresenter em relação à tela para o uso do método de TransformToVisual sempre à mão.) Você vai se lembrar que o arquivo XAML define a propriedade Visibility de ContentControl para reduzido, mas agora o programa ativa/desativa a propriedade Visible.

Ao mesmo tempo, o ContentPresenter em ItemsControl é tornar invisível.No WPF, você pode fazer isso simplesmente definindo a propriedade Visibility como oculto, o que torna o item invisível mas caso contrário, fará com que o tamanho do elemento a ser observado para fins de layout.A propriedade Visibility em Silverlight não possui uma opção de ocultos, e se você definir a propriedade Visibility do ContentPresenter como recolhido, o espaço será fechado.Em vez disso, pode imitar uma configuração de visibilidade de ocultos, simplesmente definindo a propriedade Opacity para zero.O elemento ainda está lá, mas é invisível.Ao testar o programa, você descobrirá que a transição do item em ItemsControl para o ContentControl arrastável é imperceptível.

Neste ponto, o ContentPresenter em ItemsControl não exibirá nada, mas um buraco vazio e ContentControl exiba o item agora podem ser arrastadas em torno da tela com o mouse.

O armazenamento do item

Quando estava escrevendo livros sobre o Win16 e Win32 APIs, passei todo capítulos, mostrando como usar barras de rolagem para exibir mais texto em uma janela que pode caber lá.Hoje nós simplesmente usamos um ScrollViewer e todas as pessoas estão muito mais satisfeitas —-me mais de todos.

Apesar de sua função essencial no layout do WPF e Silverlight, o ScrollViewer pode ser um pouco confuso usar algumas vezes.  Ele tem algumas peculiaridades podem ser um pouco confusa, e esse programa revela uma delas.Consulte se você pode prever o problema.

Nós à esquerda o usuário mover um item de produção em torno da tela com o mouse.Se o usuário descarta o item de produção em algum lugar sobre o ItemsControl que representa o carrinho, ele se tornará parte dessa coleção.(Falaremos mais sobre esse processo daqui a pouco.) Caso contrário, o programa anima o item de volta à sua origem, usando duas animações em returnToOriginStoryboard em MainPage.xaml.Após a conclusão da animação, a propriedade Opacity do ContentPresenter é definida como um, a propriedade Visibility de ContentControl estiver definida como recolhido e os eventos de arrastar é concluído com tudo ao normal.

Para determinar se o item de produção está sendo eliminado em ItemsControl, o programa calcula um objeto Rect que representa o local e tamanho de ContentControl o arrastado e outro objeto Rect, que representa o local e tamanho de ItemsControl.Em ambos os casos, o programa usa o método TransformToVisual para obter o local do canto superior esquerdo do controle — o ponto (0, 0) — em relação à página e as propriedades ActualWidth e ActualHeight para obter o tamanho do controle.Método de interseção da estrutura de Rect, em seguida, calcula uma interseção de dois retângulos, o que será não-vazia se houver alguma sobreposição.

Isso funciona bem, exceto quando o ItemsControl possui mais itens que podem caber no espaço vertical é permitido por ele.O ScrollViewer ativa em ação, tornando sua barra de rolagem vertical visíveis para que você pode percorrer os itens.No entanto, o ItemsControl dentro do ScrollViewer realmente acredita que ela própria seja maior do que você esteja vendo; em um sentido bastante real, o ScrollViewer é fornecer apenas uma janela visível (chamada “ visor ”) em ItemsControl.As informações de localidade e tamanho que obter para que o ItemsControl sempre indicam o tamanho máximo (chamado tamanho “ extensão ”) e não o tamanho do visor.

Este é o motivo pelo qual ScrollViewer precisa de seu filho do clipe.Se você tiver trabalhado com o Silverlight por algum tempo, talvez seja especialmente acostumados a um determinado laxity sobre corte de filhos.Quase sempre você pode usar o RenderTransform para sair dos limites do pai.No entanto, ScrollViewer definitivamente precisa do clipe, ou ele simplesmente não funciona direito.

Isso significa que não é possível usar as dimensões aparentes de ItemsControl para determinar uma operação de soltar válida, pois em alguns casos, o ItemsControl estende acima e abaixo do ScrollViewer.Por esse motivo, meu programa determina um retângulo de soltar válidas com base nas dimensões horizontais de ItemsControl, porque ele deseja excluir a área ocupada pela barra de rolagem — mas as dimensões verticais do ScrollViewer.

Quando é arrastado do ContentControl ItemsControl, ele poderia ser sobrepostas dois itens existentes ou apenas uma se ele está sendo eliminado na parte superior ou inferior da pilha de itens ou nenhum em todos os.Eu quis inserir o novo item ao ponto mais próximo de onde ele é descartado, que exigia Enumerando os itens no ItemsControl (e seus objetos associados do ContentPresenter) e determinar um bom índice para inserir o novo item.(O método GetBasketDestinationIndex é responsável por determinar esse índice.) Depois que o item é inserido, o ContentPresenter associados com o novo item é fornecido uma altura inicial igual a zero e a opacidade de zero, portanto, não está visível inicialmente.

Após esta inserção, o programa inicia o storyboard denominado transferToBasketStoryboard com cinco animações: um para diminuir a altura do ContentPresenter invisível em ItemsControl para o mercado; outro para aumentar a altura do ContentPresenter invisível recém-criada no carrinho de compras ItemsControl; e dois mais para animar a Canvas. Left e Canvas.Top anexado propriedades para o slide no lugar de ContentControl.(Falarei sobre a animação quinta daqui a pouco.) A Figura 3 mostra o alargamento da diferença conforme se aproxima de ContentControl seu destino.

Figure 3 The Animation to Move a New Item into PlaceDa animação para mover um item novo em local, a Figura 3

Quando a animação é encerrada, o ContentPresenter novo é fornecido uma opacidade de um e de ContentControl é fornecida uma visibilidade de recolhido e agora, estamos novamente para lidando apenas com dois ItemsControls normais dentro ScrollViewers.

O superior e problemas de inferior

Neste artigo eu lhe de charlespetzold.com/silverlight/ItemsControlTransitions2 de URL para testar o programa.Uma versão anterior do programa pode ser executada por charlespetzold.com/silverlight/ItemsControlTransitions , sem a “ 2 ” no final.Usando essa versão anterior, mova várias produzem itens sobre o carrinho — o suficiente para exibir a barra de rolagem vertical.Agora arraste outra e posicione-espalhados pela parte inferior da ScrollViewer.Quando você soltar o botão do mouse, o ContentControl move para baixo em direção a uma área de ItemsControl, que é invisível e, em seguida, desaparece repentinamente.O item foi inserido corretamente (conforme você pode verificar rolando para baixo), mas não muito com elegância.

Agora, role a ScrollViewer para que o item superior é apenas parcialmente visível.  Mover outro item do carrinho de compras e posicione-a para que ele será inserido antes desse item.O novo item, os slides em ItemsControl, mas não está completamente visível.Não é bem tão ruim quanto o problema na parte inferior de ItemsControl, mas ele ainda precisa de alguma ajuda.

A correção?Uma maneira para rolar através de programação o ScrollViewer é necessária.A quantidade de rolagem vertical atualmente em vigor para um ScrollViewer é fornecida por meio da propriedade VerticalOffset.Esse número é um deslocamento positivo da parte superior de ItemsControl inteiro para o local em que o controle é exibido na parte superior do ScrollViewer.

Não seria ótimo simplesmente animar essa propriedade VerticalOffset?Infelizmente, apenas o acessador get é público.Felizmente, é possível rolar por meio de programação o ScrollViewer, mas você precisa chamar um método chamado ScrollToVerticalOffset.

Para realizar esse trabalho rolagem pouco com o recurso de animação do Silverlight, defini uma propriedade de dependência, chamada de rolagem em MainPage propriamente dito.No arquivo XAML, me deu a página de um nome desta “ ” e definidos uma animação do quinta transferToBasketStoryboard para essa propriedade de destino:

<DoubleAnimation x:Name="scrollItemsControlAnima"
                 Storyboard.TargetName="this"
                 Storyboard.TargetProperty="Scroll" />

A substituição de OnMouseLeftButtonUp calcula de e para valores dessa animação.  (Você pode comparar o efeito dessa animação adicional por comentar o bloco de código inicial com o comentário “ Calculate ScrollViewer animação rolagem ”.)  Como essa propriedade de rolagem é animada, o manipulador de propriedade alterada chama o método de ScrollToVerticalOffset do ScrollViewer com o valor animado.

Em direção a uma interface do usuário de fluido

Muitos, muitos anos atrás, os computadores eram muito mais lentas do que agora, e nada o que aconteceu na tela nunca foi muito surpreendente. Hoje em dia, programas podem implementar interfaces de usuário alterar inteiramente suas aparências na intermitência de atenção. Mas isso também é insatisfatório. Muitas vezes não é possível até mesmo vemos que está acontecendo, portanto, agora que achamos necessário deliberadamente, diminuir a velocidade da interface do usuário e tornar as transições mais fluida e natural. O Silverlight 4 introduzidos alguns recursos de “ fluidos da interface do usuário ” estou ansioso para discutir, mas mesmo no Silverlight 3 é possível começar a jornada nessa direção.

Charles Petzold* é editor colaborador da há muito tempo para* MSDN Magazine*.*Atualmente, ele está gravando “ Programming Windows telefone 7 Series,” que será publicado como um download e-book gratuito no outono de 2010. Uma edição de visualização está disponível no momento por meio de charlespetzold.com seu site da Web .