Pergunta

Eu tenho uma classe chamada Livro;

class Book
{
    public string Name { get; set; }
    public string Author { get; set; }
    public int PagesCount { get; set; }
    public int Category { get; set; }
}

A caixa de listagem exibe uma lista de livros eo ItemTemplate foi modificado de modo a representar visualmente o livro. Os shows de texto do livro Nome, autor e o número de páginas. A categoria, no entanto é representado por uma determinada cor (por exemplo, a história é azul, romance é vermelho etc.) Agora, o texto tem um efeito OuterGlowBitmap e um conversor de valor a partir da Categoria (int) para a cor apropriada. Tudo está ligado no DataTemplate para ListBoxItem. Tecnicamente, tudo funciona bem.

O problema, porém, é o desempenho. Parece que o efeito outerGlow bitmap é pesada no processador, então quando eu tenho uma lista de cerca de 500 livros, leva cerca de 500ms para recuperar os dados do banco de dados, mas cerca de 10 segundos para realmente carregar os itens na caixa de listagem. E mesmo quando o carregamento é feito, a rolagem é muito vagaroso. Tentei definir o VirtualizingStackPanel.IsVirtualizing como True, mas sem sucesso. (O número máximo de livros que podem estar na base de dados a qualquer momento é de cerca de 30000).

No entanto, mesmo quando há mais de 100 itens na caixa de listagem, a mente humana não pode processar muito rapidamente, então eu não visam carga e lista para o usuário todos os livros que são procurados. É por isso que eu criei um BookNavigator classe de navegação de mensagens publicitárias que realmente se liga a caixa de listagem ao seu objeto ObservableCollection. Todos os livros são carregados para este BookNavigator, mas apenas X deles são exibidos na caixa de listagem (adicionando-os para o ObservableCollection).

O problema com isso é que eu quero que o número de livros exibidos para ser pequeno o suficiente para caixa de listagem não exibir a barra de rolagem, para que eu possa implementar meus próprios métodos de rolagem (Primeiro, Anterior, Próximo passado, ou simplesmente minha própria barra de rolagem, não importa).

Como posso calcular quantos itens para exibição para a barra de rolagem não é mostrado?

Dois problemas que surgem: - Redimensionar o aplicativo pode alterar o tamanho da caixa de listagem - Nem todos os itens de caixa de listagem são da mesma altura (dependendo do número de autores)

.

Existe alguma maneira de conseguir o que estou tentando fazer?


EDIT (como uma resposta a Martin Harris)

O problema com o código de Martin Harris sugeriu é que o loop foreach usa FrameworkElement, mas a caixa de listagem é preenchida com objetos do tipo Livro que não herda de FrameworkElement, nem tem qualquer outro meio de calcular sua altura. elemento raiz do ListBoxItem é uma grade, talvez por isso, seria possível para recuperar essa grade, mas eu não sei como fazer isso?

Existe alguma maneira em tudo para obter os elementos da interface reais que são criados para representar o item caixa de listagem?


Editar

Eu encontrei este Q / A, que parece ser o que eu preciso .. ItemContainerGenerator

Foi útil?

Solução 4

A solução pode implicitamente ser encontrada aqui: Solution

Outras dicas

Depois de tentar descobrir algo semelhante, eu pensei que eu iria compartilhar meu resultado aqui (como parece mais fácil do que as outras respostas):

teste de visibilidade simples que eu tenho de aqui .

private static bool IsUserVisible(FrameworkElement element, FrameworkElement container)
{
    if (!element.IsVisible)
        return false;

    Rect bounds =
        element.TransformToAncestor(container).TransformBounds(new Rect(0.0, 0.0, element.ActualWidth, element.ActualHeight));
    var rect = new Rect(0.0, 0.0, container.ActualWidth, container.ActualHeight);
    return rect.Contains(bounds.TopLeft) || rect.Contains(bounds.BottomRight);
}

Depois, você pode percorrer os ListBoxItems e usar esse teste para determinar quais são visíveis. A contagem desta lista iria dar-lhe o número de itens visíveis na caixa de listagem.

private List<object> GetVisibleItemsFromListbox(ListBox listBox, FrameworkElement parentToTestVisibility)
{
    var items = new List<object>();

    foreach (var item in PhotosListBox.Items)
    {
        if (IsUserVisible((ListBoxItem)listBox.ItemContainerGenerator.ContainerFromItem(item), parentToTestVisibility))
        {
            items.Add(item);
        }
        else if (items.Any())
        {
            break;
        }
    }

    return items;
}

Este seria, então conter a lista de itens atualmente exibidos na caixa de listagem (incluindo os que estão escondidos por rolagem ou algo similar).

Será que você provavelmente poderia descobrir os tamanhos de todos os livros antes de adicioná-los à caixa de lista (possivelmente por analisar e preencher o XAML modelo no código por trás, em seguida, pedir o controle externo para o seu tamanho) este seria um monte de trabalho para não muito ganho. Você não pode simplesmente selecionar um número de livros que será suficiente para encher a caixa de lista, mas não tantos para retardar a prestação para baixo e gire a barra de rolagem off? Isso ainda pode ser ligada ao tamanho da caixa de lista para que como ele cresceu mais foram adicionados itens, mas o custo de desempenho para a adição de alguns itens extras deve ser menor que o custo de calcular todos os tamanhos novamente.

Exemplo rápido: Vamos dizer que o tamanho de um livro com um autor é de 150 pixels. Você poderia ter o tamanho da caixa de listagem e dividir por 125 para obter uma estimativa aproximada do número de itens que seriam in-the-estádio, mas não caro para calcular. O que você quer evitar é muito alguns itens desde que vai deixar espaço vazio.


Editado à luz do seu comentário.

Nesse caso, você pode adicionar os itens à caixa de listagem (usando o método acima para obter um palpite fechar), então calcular que o último item completamente visível é e, em seguida, remover os itens extras.

Este método de extensão vai ter o último elemento que é completamente mostrado em uma caixa de listagem ou nulo se nenhum item são visíveis:

public static class ListBoxExtensions
{
    public static FrameworkElement GetLastItem(this ListBox listBox)
    {
        double height = listBox.ActualHeight;

        double currentHeight = 0;
        FrameworkElement previous = null;

        foreach (FrameworkElement item in listBox.Items)
        {
            currentHeight += item.ActualHeight;
            if (currentHeight > height)
            {
                return previous;
            }

            previous = item;
        }

        return previous;
    }
}

Se a lista é feita maior, então você pode adicionar itens suficientes para a coleção que você preencher a lacuna e re-executar o processo.

"Como posso calcular quantos itens a serem exibidos assim que a barra de rolagem não é mostrado?"

Resposta curta: (ListBox1.Height / listBox1.ItemHeight)

Isto dá-lhe o número de linhas exibidas / disponíveis, assim você pode ler apenas neste número de linhas e irá preencher toda a caixa de listagem.

Agora, a demo:

        int listbox_total_visible_lines = 2;
        listBox1.Height = (listbox_total_visible_lines + 1) * listBox1.ItemHeight;
        listBox1.Items.Add("um");
        listBox1.Items.Add("dois");
        listBox1.Items.Add("tres");
        listBox1.Items.Add("quatro");
        listBox1.Items.Add("cinco");
        listBox1.SelectedIndex = listBox1.Items.Count - 1;
        this.Text = (listBox1.Height/ listBox1.ItemHeight).ToString();

Este exemplo permite que você escolha o número de itens que vão ser visíveis, por isso é as linhas OS números que são actualy disponível para mostrar. Portanto, você adicionar apenas os "listbox_total_visible_items" itens e caixa de listagem será cheio e não mostrar as barras de rolagem.

Código explicar:

  1. listbox_total_visible_items contém o número de linhas para ser mostrado

  2. listbox configuração com o tamanho adequado, apenas 2 linhas

3-7. Adicione algumas linhas

  1. ir para a última linha, apenas para se divertir

  2. show na barra de formulário de texto, o número das linhas de caixa de listagem, com base na altura listbox dividido pelo tamanho de cada item.

É isso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top