Неправильный выбор в ListBox с VirtualizationMode = "Recycling" и SeclectionMode = "Extended"? - PullRequest
3 голосов
/ 28 мая 2010

У меня очень странное поведение. У меня есть ListBox в представлении с DataTemplate для его элементов, включая ViewModels. Я привязываю IsSelected к моей ViewModel и использую SelectionMode = "Extended". Все отлично работает НО, если я добавлю VirtualiuationMode = "Recycling", я получу неправильные предметы. Для воспроизведения: выделите элементы с помощью Ctrl, затем прокрутите вниз и выберите только один элемент. Нормальное поведение отменяет выбор всех элементов и просто выбирает последний без удержания Ctrl. Но если я проверю свою ViewModel, все старые элементы будут выбраны!?!

<Grid>
    <StackPanel>
        <ListBox ItemsSource="{Binding People}" MaxHeight="100"
                 SelectionMode="Extended"
                 VirtualizationMode="Recycling">
            <!--VirtualizingStackPanel.IsVirtualizing="True">-->

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

                </Style>

            </ListBox.ItemContainerStyle>
            <ListBox.ItemTemplate>
                <DataTemplate>

                    <views:PeopleView />

                </DataTemplate>

            </ListBox.ItemTemplate>
        </ListBox>
        <Button Click="Button_Click">
            OK
        </Button>
    </StackPanel>
</Grid>

Шаблон товара

<UserControl x:Class="WpfApplication1.View.PeopleView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="Auto" Width="Auto">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" SharedSizeGroup="A"/>
        <ColumnDefinition Width="Auto" SharedSizeGroup="B"/>
    </Grid.ColumnDefinitions>
    <TextBox Text="{Binding Path=Name}" 
             Name="tbx_Name" 
           Grid.Column="0"/>

    <CheckBox IsChecked="{Binding Path=IstAktiv}"
        Name="cbx_IstAktiv" 
              Grid.Column="1"/>

</Grid>

Есть идеи?

Ответы [ 2 ]

1 голос
/ 19 февраля 2013

Другой вариант, связанный с более ранним ответом KCT, заключается в использовании AddedItems и RemovedItems из SelectionChangedEventArgs и нацеливании на изменения, такие как:

private void Lbx_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    foreach (var item in e.AddedItems)
    {
        ((PersonViewModel)item).IsSelected = true;
    }
    foreach (var item in e.RemovedItems)
    {
        ((PersonViewModel)item).IsSelected = false;
    }
}

Это может повысить производительность при работе с большими коллекциями (у меня есть около 15 000 записей на панели виртуализации плитки в ListBox).

1 голос
/ 31 мая 2010

Я нашел обходной путь, но почему я должен изменить его «вручную» в событии изменения, а не с помощью привязки данных?

    private void Lbx_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        ListBox lbx = (ListBox)sender;
        foreach (PersonViewModel item in lbx.Items)
        {
            item.IsSelected = lbx.SelectedItems.Contains(item);
        }
    }
...