I have a ListView with UserControl as ItemTemplate. The problem is that after filtering and searching for items, the item changes and the items get mixed up. For example, items that have not yet been downloaded are shown as downloaded, and items that have been downloaded are shown as not downloaded.
The question is how do I make each item work separately and not affect other items?
this is my ListView
<ListView ItemsSource="{x:Bind SubtitlesACV, Mode=OneWay}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="model:SubsceneDownloadModel">
<usercontrol:SubsceneUserControl
Title="{x:Bind Title}"
Link="{x:Bind Link}"
SubtitleLanguage="{x:Bind Language}"
Translator="{x:Bind Translator}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
and this is my Usercontrol
<Grid>
<SwipeControl x:Name="ListViewSwipeContainer">
<Grid VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<TextBlock.../>
<StackPanel
Grid.RowSpan="2"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Orientation="Horizontal">
<AppBarButton
Name="OpenFolderButton"
MinWidth="75"
Margin="10,0,10,0"
Click="OpenFolderButton_Click"
Icon="OpenLocal"
IsTabStop="False"
Label="Open Folder"
Visibility="Collapsed"/>
<ProgressRing
Name="ProgressStatus"
Margin="10,0,10,0"
Visibility="Collapsed"/>
<AppBarButton
Name="DownloadHoverButton"
Margin="10,0,10,0"
Click="DownloadHoverButton_Click"
Icon="Download"
IsTabStop="False"
Label="Download"
Visibility="Collapsed"/>
</StackPanel>
</Grid>
</SwipeControl>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="HoveringStates">
<VisualState x:Name="HoverButtonsHidden"/>
<VisualState x:Name="HoverButtonsShown">
<VisualState.Setters>
<Setter Target="DownloadHoverButton.Visibility" Value="Visible"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
this is code behind for pointer events
private void UserControl_PointerEntered(object sender, PointerRoutedEventArgs e)
{
if (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse ||
e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Pen)
{
VisualStateManager.GoToState(sender as Control, "HoverButtonsShown", true);
}
}
private void UserControl_PointerExited(object sender, PointerRoutedEventArgs e)
{
VisualStateManager.GoToState(sender as Control, "HoverButtonsHidden", true);
}
and this codes is for filtering via numberbox and AutoSuggestBox (which SubtitlesACV is AdvancedCollectionView)
SubtitlesACV.Filter = SubtitleFilter;
private bool SubtitleFilter(object subtitle)
{
var query = subtitle as SubsceneDownloadModel;
var selectedLanguage = cmbLanguage.SelectedItem as string;
var selectedQuality = cmbQuaity.SelectedItem as string;
if (string.IsNullOrEmpty(selectedQuality) || string.IsNullOrEmpty(selectedLanguage))
return false;
var name = query.Name ?? "";
var translator = query.Translator ?? "";
var comment = query.Comment ?? "";
var language = query.Language ?? "";
if (selectedLanguage.Equals(Consts.ALL_Language))
selectedLanguage = "";
if (selectedQuality.Equals(Consts.ALL_Qualities))
selectedQuality = "";
var episode = $"E{nbEpisode.Value.ToString("00")}";
if (double.IsNaN(nbEpisode.Value) || nbEpisode.Value == 0)
episode = "";
return (name.Contains(selectedQuality, StringComparison.OrdinalIgnoreCase)
|| translator.Contains(selectedQuality, StringComparison.OrdinalIgnoreCase)
|| comment.Contains(selectedQuality, StringComparison.OrdinalIgnoreCase))
&& language.Contains(selectedLanguage, StringComparison.OrdinalIgnoreCase)
&& (name.Contains(AutoSuggest.Text, StringComparison.OrdinalIgnoreCase)
|| translator.Contains(AutoSuggest.Text, StringComparison.OrdinalIgnoreCase)
|| comment.Contains(AutoSuggest.Text, StringComparison.OrdinalIgnoreCase))
&& (name.Contains(episode, StringComparison.OrdinalIgnoreCase)
|| translator.Contains(episode, StringComparison.OrdinalIgnoreCase)
|| comment.Contains(episode, StringComparison.OrdinalIgnoreCase));
}
First, episode 16 is downloaded and the open folder button appears. As can be seen, episode 17, 18 and 19 show the download button That is absolutely correct.
Now if we filter the episode number with following codes, An item that has not yet been downloaded will show the open folder button That is wrong.
Now if we search episode 16 (previously downloaded) from the AutoSuggestBox, all items will change to unDownloaded mode.
First of all, the reason for your behavior is UI virtualization. It means UI elements representing the items are created on demand. The panel will reuse some items sometimes and that's why you got this behavior. Currently, there is no good way to solve this when using UI virtualization
.
If you don't have large amounts of data, you could just use StackPanel
which doesn't enable UI virtualization
. But if you have large amounts of data, then you need to optimize the performance by yourself. For example, cut the data into different parts, loading just parts of the data at once. Load the other parts of data when they are required. In this way, you could avoid this behavor.
If you have large amounts of data and you still want to use UI virtualization
, what you could do is clear the cached data in the usercontrol. For example, when loading the usercontrol or passing the data into the usercontrol, clear the value and manually set the value. But you still can't avoid this behavior totally.