Ir para o conteúdo
ItemsSource para elementos XamDockManager

ItemsSource para elementos XamDockManager

Várias pessoas perguntaram sobre a associação do ItemsSource de um TabGroupPane à sua coleção. Isso não é suportado pelo TabGroupPane, então pensei em explicar o porquê e fornecer uma abordagem alternativa.

4min de leitura

Várias pessoas perguntaram sobre a associação do ItemsSource de um TabGroupPane à sua coleção. Isso não é suportado pelo TabGroupPane, então pensei em explicar o porquê e fornecer uma abordagem alternativa.

Se você deseja associar o DocumentContentHost ou até mesmo um SplitPane específico a uma coleção, ainda deve continuar lendo, pois essa solução também permitirá isso.

O TabGroupPane é um ItemsControl derivado e a propriedade ItemsSource que você vê no TabGroupPane é a da classe ItemsControl base. O ItemsControl foi realmente projetado para que todos os contêineres criados para itens no ItemsSource sejam hospedados nesse ItemsControl – especificamente hospedados pelo Panel indicado pela propriedade ItemsPanel. Portanto, os itens são enviados automaticamente para os filhos do ItemsPanel à medida que os itens são adicionados à coleção ou, no caso de um VirtualizingPanel, o painel tem controle sobre quando/quais contêineres são hidratados. Além disso, depois de definir o ItemsSource, não é possível alterar diretamente sua coleção Items – uma exceção será lançada pelo ItemCollection se você fizer isso.

Se você pensar no TabGroupPane, ele precisa ser capaz de manipular os itens que ele contém – ou seja, sua coleção Items. Isso pode acontecer por vários motivos. Por exemplo, se o usuário final fixar/desafixar um painel, arrastar um painel para dentro ou para fora do grupo, alterar o estado encaixado/flutuante de um dos filhos, etc. Como isso não seria possível se os itens do controle fossem fornecidos por seu ItemsSource (já que a coleção Items não seria modificável), o controle não pode dar suporte à associação de sua coleção Items por meio do ItemsSource.

Então, como podemos fornecer suporte para isso sem usar a propriedade ItemsSource. Se você pensar sobre isso, o que precisamos é de algo análogo ao ItemContainerGenerator. Essa é uma classe usada pelo ItemsControl e seu ItemsPanel associado para gerar contêineres/elementos para itens que não são do tipo desejado. Portanto, para um ListBox, as instâncias de ListBoxItem são geradas para itens que não são desse tipo. Infelizmente, o ItemContainerGenerator não pode ser criado publicamente.

Portanto, a abordagem que decidi adotar foi criar minha própria classe do tipo ItemContainerGenerator chamada ContainerFactoryBase que poderia receber uma coleção de origem e manteria uma coleção associada de contêineres. Com base no conteúdo da coleção e à medida que a coleção gerava notificações de alteração, ela invocaria métodos semelhantes aos do ItemsControl em si mesmo que as classes derivadas poderiam usar para criar o contêiner apropriado (por exemplo, IsItemItsOwnContainer e GetContainerForItem) e associar esse contêiner ao item (por exemplo, ApplyItemContainerStyle e PrepareContainerForItem). Ele invocaria métodos à medida que os itens na coleção de origem fossem adicionados/removidos/movidos para que a classe derivada pudesse executar a ação apropriada com o contêiner associado.

Em seguida, criei uma classe derivada chamada ContentPaneFactory que cria instâncias de ContentPane como o contêiner para cada item e a adiciona ao destino associado. A classe expõe várias propriedades de caminho que podem ser usadas para associar propriedades do ContentPane às propriedades do item de dados, incluindo as propriedades Header, Content e TabHeader. Para quaisquer outras propriedades, você pode fornecer um Style para ContentPane usando a propriedade ContainerStyle ou pode usar a coleção ItemBindings. Por fim, também gero um evento anexado (InitializeContentPane) quando um ContentPane é criado para que você possa fazer qualquer inicialização programática que possa ser necessária.

Para facilitar o uso, criei uma propriedade anexada que seria usada para associar a fábrica a um determinado destino. Portanto, você definiria a propriedade ContentPaneFactory.PaneFactory como uma instância de ContentPaneFactory em um TabGroupPane, SplitPane ou DocumentContentHost e esse é o elemento de destino ao qual novas instâncias de ContentPane são adicionadas.

    <igDock:DocumentContentHost >
        <igExtensions:ContentPaneFactory.PaneFactory>
            <!-- Binds to the Documents property of the DataContext. -->
            <igExtensions:ContentPaneFactory 
               ItemsSource="{Binding Documents}"
               HeaderPath="Name"
               ContentPath="." />
        </igExtensions:ContentPaneFactory.PaneFactory>
    </igDock:DocumentContentHost>

Você pode obter a amostra aqui.

Solicite uma demonstração