Pergunta

Eu tenho implementado um padrão de seleção semelhante ao descrito no este post usando um ViewModel para armazenar o valor IsSelected, e ligando o ListViewItem.IsSelected ao ViewModel IsSelected:

<ListView.ItemContainerStyle>
    <Style TargetType="{x:Type ListViewItem}">
        <Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}"/>
    </Style>
</ListView.ItemContainerStyle>

Ele funciona em geral, mas eu encontrar um problema grave. Usando a um VirtualizingStackPanel como o painel na vista de lista, apenas o ListViewItem visíveis estão sendo criados. Se eu usar "Ctrl + A" para selecionar todos os itens, ou usando a combinação de atalho como "Shift + Ctrl + End" no primeiro item, todos os itens são selecionados, mas para os itens não visíveis, o ViewModel não recebe sua IsSelected definido como verdadeiro. Isso é lógico, porque se o ListViewItem não são criados, a ligação pode não trabalho.

Qualquer pessoa experimentou o mesmo problema, e encontrou uma solução (além de não utilizar um VirtualizingStackPanel)?

Foi útil?

Solução

Eu encontrei outra maneira de lidar com a seleção no padrão MVVM, que resolveu o meu problema. Em vez de manter a seleção na viewmodel, a seleção é recuperado do ListView / ListBox, e passou como um parâmetro para o comando. Tudo feito em XAML:

<ListView 
    x:Name="_items"
    ItemsSource="{Binding Items}" ... />

<Button 
    Content="Remove Selected" 
    Command="{Binding RemoveSelectedItemsCommand}" 
    CommandParameter="{Binding ElementName=_items, Path=SelectedItems}"/>

no meu ViewModel:

private void RemoveSelection(object parameter)
{
    IList selection = (IList)parameter;
    ...
}

Outras dicas

No meu caso, eu acabei resolver este derivando uma classe ListBoxEx de caixa de listagem, e adicionando código para responder a alterações de seleção, impondo o estado de seleção sobre os modelos de exibição artigo:

private readonly List<IListItemViewModelBase> selectedItems = new List<IListItemViewModelBase>();

protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
    base.OnSelectionChanged(e);

    bool isVirtualizing = VirtualizingStackPanel.GetIsVirtualizing(this);
    bool isMultiSelect = (SelectionMode != SelectionMode.Single);

    if (isVirtualizing && isMultiSelect)
    {
        var newSelectedItems = SelectedItems.Cast<IListItemViewModelBase>();

        foreach (var deselectedItem in this.selectedItems.Except(newSelectedItems))
        {
            deselectedItem.IsSelected = false;
        }

        this.selectedItems.Clear();
        this.selectedItems.AddRange(newSelectedItems);

        foreach (var newlySelectedItem in this.selectedItems)
        {
            newlySelectedItem.IsSelected = true;
        }
    }
}

Além de não usar VirtualizingStackPanel, a única coisa que posso pensar é capturar esses atalhos de teclado e ter métodos para modificar um determinado intervalo de seus itens ViewModel para que sua propriedade IsSelected está definido para True (por exemplo, SelectAll(), SelectFromCurrentToEnd()) . Basicamente ignorando o Binding em ListViewItem para controlar a seleção para tais casos.

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