我有ListView
个CheckBox
个控件,当包含ListView
的网页返回到导航时,ListView
内的其他项目会神秘地应用复选标记它
具体来说,我对包含大约300个项目的ListView
中的某些项目应用了复选标记。然后我点按Button
调用另一个应用启动,然后当我使用ListView
返回原始应用并向下滚动ListView
时,我会观察到一种神秘检查的模式复选框遵循我在ListView
内创建的原始核对位置的模式。
注意:
我在ListView
内使用虚拟化。
仅当导航返回到包含ListView
的页面时才会出现神秘复选框。
不应该神秘地检查复选框。 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>
代码背后:
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);
}
更新 此问题可重现,无需导航到其他应用程序。
答案 0 :(得分:0)
我设法在新的Windows Phone 8.1项目中重现您的问题(同样适用于WPF等):
<强> 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;
}
}
这是一个非常基本的示例,它创建一个包含列表视图的页面,其中包含每个项目的复选框。如果我检查前三项并向下滚动,则会检查一些后续复选框,如下图所示:
我的猜测是,由于启用了虚拟化(默认情况下),列表视图在向下滚动时会重用现有的ListViewItem
,其中一些包含我之前检查过的复选框元素。重新使用容器时,不会清除此复选框的状态。
假设我的listview中有100个项目,并且由于虚拟化,在内存中只会创建20个ListViewItem
。那么,如果内存中只有20个复选框,应用程序应该如何记住100个项目中的哪一个应该有一个复选框?
您应该在视图模型中存储每个项目的已检查状态,并将数据绑定到该模型。当listview需要重用列表视图项时,它会将其数据上下文设置为新项,从而导致复选框由于其具有绑定而更新其状态。
您应该对您的复选框进行此更改:
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked, Mode=TwoWay}" />
并将IsChecked
属性添加到商品的模型中:
class Model
{
public string Name { get; set; }
public bool IsChecked { get; set; }
}
注意:仅在启用虚拟化时才需要这样做。如果您的列表不包含太多项目,那么您可以通过使用非虚拟化面板(例如StackPanel
:
<ListView x:Name="listview">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
...
</ListView>
当然,这些示例基于我的简化示例,但仍适用于您的代码。
您似乎在每个复选框上都附加了一些特定的行为,否则我建议您只在列表视图中设置SelectionMode="Multiple"
以获取开箱即用的复选框。