Listview applies validation to other list items that have a checkbox when returning to the page

I have ListView

controls CheckBox

where a checkbox is mysteriously applied to other items in ListView

when the page containing ListView

is returned to it.

Specifically, I am applying checkboxes to some of the elements in ListView

which contains approximately 300 elements. Then I click Button

that launches another app to launch, and then when I go back to my original app with ListView

and scroll down ListView

, I see a sample of mysteriously checked checkboxes that follow the pattern of the original verified locations I made in ListView

.

Note: I am using virtualization in my ListView

. The mysterious checkboxes are only checked when navigating back to the page containing the ListView

.

Checkboxes should not be mysteriously checked. XAML:

<ListView   x:Name="ContactList" 
                ItemsSource="{Binding SelectedCategory.Contacts}"
                SelectedItem="{Binding SelectedContact, Mode=TwoWay}"
                ScrollViewer.VerticalScrollMode="Enabled"
                Height="600"
                Width="425"
                Margin="58,175,0,0"  Canvas.ZIndex="99"
                Background="Transparent" Foreground="#FF333747" 
                VerticalAlignment="Top" HorizontalAlignment="Left">

        <ListView.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <CheckBox x:Name="checkbox" Style="{StaticResource CheckBoxStyle1}"
                              Visibility="{Binding ElementName=grid, Path=DataContext.BroadcastActivated, Converter={StaticResource BoolToVisibilityConverter}, Mode=TwoWay}"
                              Margin="0,-8" BorderBrush="#FF4E58BC" Checked="ContactChecked" Unchecked="ContactUnchecked">
                    </CheckBox>

                    <TextBlock Text="{Binding DisplayName}" Width="425">
                        <Interactivity:Interaction.Behaviors>
                            <Core:EventTriggerBehavior EventName="Holding">
                                <behaviors:MoveContactAction />
                            </Core:EventTriggerBehavior>
                        </Interactivity:Interaction.Behaviors>

                        <FlyoutBase.AttachedFlyout>
                            <MenuFlyout>
                                <MenuFlyoutItem Text="Family" Command="{Binding ElementName=grid, Path=DataContext.MoveCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Text}" />
                                <MenuFlyoutItem Text="Friend" Command="{Binding ElementName=grid, Path=DataContext.MoveCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Text}" />
                                <MenuFlyoutItem Text="Business" Command="{Binding ElementName=grid, Path=DataContext.MoveCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Text}" />
                                <MenuFlyoutItem Text="Met" Command="{Binding ElementName=grid, Path=DataContext.MoveCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Text}" />
                                <MenuFlyoutItem Text="Others" Command="{Binding ElementName=grid, Path=DataContext.MoveCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Text}" />
                            </MenuFlyout>
                        </FlyoutBase.AttachedFlyout>
                    </TextBlock>
                </StackPanel>
            </DataTemplate>

        </ListView.ItemTemplate>

        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel />
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>

        <ListView.Template>
            <ControlTemplate TargetType="ListView">
                <Border>
                    <ScrollViewer>
                        <ItemsPresenter/>
                    </ScrollViewer>
                </Border>
            </ControlTemplate>
        </ListView.Template>

        <Interactivity:Interaction.Behaviors>
            <behaviors:ContactSelectionBehavior />
            <Core:DataTriggerBehavior Binding="{Binding DataContext.BusinessRequested, ElementName=grid}" Value="True">
                <Core:GoToStateAction StateName="BusinessSelectedState"/>
            </Core:DataTriggerBehavior>
            <Core:DataTriggerBehavior Binding="{Binding DataContext.FriendsRequested, ElementName=grid}" Value="True">
                <Core:GoToStateAction StateName="FriendsSelectedState"/>
            </Core:DataTriggerBehavior>
            <Core:DataTriggerBehavior Binding="{Binding DataContext.FamilyRequested, ElementName=grid}" Value="True">
                <Core:GoToStateAction StateName="FamilySelectedState"/>
            </Core:DataTriggerBehavior>
            <Core:DataTriggerBehavior Binding="{Binding DataContext.OthersRequested, ElementName=grid}" Value="True">
                <Core:GoToStateAction StateName="OthersSelectedState"/>
            </Core:DataTriggerBehavior>
            <Core:DataTriggerBehavior Binding="{Binding DataContext.AllRequested, ElementName=grid}" Value="True">
                <Core:GoToStateAction StateName="AllSelectedState"/>
            </Core:DataTriggerBehavior>
            <Core:DataTriggerBehavior Binding="{Binding DataContext.MetRequested, ElementName=grid}" Value="True">
                <Core:GoToStateAction StateName="MetSelectedState"/>
            </Core:DataTriggerBehavior>
        </Interactivity:Interaction.Behaviors>

        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Setter Property="FontSize" Value="26" />
                <Setter Property="Margin" Value="0,10" />
                <Setter Property="Foreground" Value="#FF333747" />
            </Style>
        </ListView.ItemContainerStyle>
</ListView>

      

Code for:

private void ContactChecked(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
    var control = sender as CheckBox;
    var viewModel = this.DataContext as HomeViewModel;

    var contact = control.DataContext as Contact;
    viewModel.SelectedContacts.Add(contact);

    if (CallButton.IsEnabled)
    {
        CallButton.IsEnabled = false;
    }

    SetMessageContactOptionsEnabledState(viewModel);
}

private void ContactUnchecked(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
    var control = sender as CheckBox;
    var viewModel = this.DataContext as HomeViewModel;

    var contact = control.DataContext as Contact;
    viewModel.SelectedContacts.Remove(contact);
}

      

Update: This issue is reproducible without switching to another application.

+3


source to share


1 answer


I was able to reproduce your problem on a new Windows Phone 8.1 project (same applies to WPF, etc.):

MainPage.xaml

<Page
    x:Class="App27.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App27"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    Loaded="Page_Loaded">

    <Grid>
        <ListView x:Name="listview">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <CheckBox Content="{Binding Name}" />
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</Page>

      

MainPage.xaml.cs

class Model
{
    public string Name { get; set; }
}

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        this.NavigationCacheMode = NavigationCacheMode.Required;
    }

    private void Page_Loaded(object sender, RoutedEventArgs e)
    {
        var items = new List<Model>();
        for (var i = 0; i < 100; i++)
            items.Add(new Model { Name = i.ToString() });
        listview.ItemsSource = items;
    }
}

      

This is an extremely simple example that creates a list page containing checkboxes for each item. If I check the first three items and scroll down, some of the subsequent checkboxes are checked, like in this picuture:

screenshot

My guess is that since virtualization is enabled (by default), the list view reuses the existing one ListViewItem

when scrolling down, some of which contain a checkbox item that I checked earlier. This checkbox state will not be cleared when the container is reused.

Let's say I have 100 items in my list and due to virtualization there will only ever be 20 in memory ListViewItem

. Then how is the application supposed to remember which of the 100 items should have a checkbox when there are only 20 checkboxes in memory?



You have to store the checked state of each item in and bind to your view model. When the listview needs to reuse a listview item, it will set its data context to the new item, causing the checkbox to update its state due to the binding it has.

You have to make this change in your checkbox:

<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked, Mode=TwoWay}" />

      

and add a property IsChecked

to your product model:

class Model
{
    public string Name { get; set; }
    public bool IsChecked { get; set; }
}

      

Note. This is only required if you have enabled virtualization. If your list won't contain too many items, you can simply disable virtualization using a non-virtualizing panel such as StackPanel

:

<ListView x:Name="listview">
    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel />
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>
    ...
</ListView>

      

Now, of course, these examples are based on my simplified example, but still apply to your code.

It looks like you have certain behavior associated with each checkbox, otherwise I would suggest just setting SelectionMode="Multiple"

in your list to get the checkboxes out of the box.

0


source







All Articles