UWP嵌套ListView切换编辑模式时TemplateSelector模板更新延迟问题
UWP 嵌套ListView TemplateSelector 切换模板不生效问题
问题描述
开发UWP应用时使用嵌套ListView展示按固定属性分组的条目,需要在「查看模式」和「编辑模式」之间切换实现条目编辑功能。但开启「编辑视图」时,第一个ListView并未更新为编辑视图对应的模板。
相关代码
UWP页面代码
<Page x:Class="UWPTest.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:UWPTest" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="auto"></RowDefinition> <RowDefinition Height="*"></RowDefinition> </Grid.RowDefinitions> <CommandBar Grid.Row="0"> <AppBarToggleButton Icon="Edit" Label="Bearbeitungs-Ansicht" IsChecked="{x:Bind EditMode, Mode=TwoWay}" /> </CommandBar> <local:ListViewControl Grid.Row="1" MyListCollection="{x:Bind MyList}"></local:ListViewControl> </Grid> </Page>
UWP用户控件代码
<UserControl x:Class="UWPTest.ListViewControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:UWPTest" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <UserControl.Resources> <DataTemplate x:Key="DTView" x:DataType="local:Model"> <Grid> <TextBlock Text="{x:Bind Text}"></TextBlock> </Grid> </DataTemplate> <DataTemplate x:Key="DTEdit" x:DataType="local:Model"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"></ColumnDefinition> <ColumnDefinition Width="auto"></ColumnDefinition> </Grid.ColumnDefinitions> <TextBox Grid.Column="0" Text="{x:Bind Text,Mode=TwoWay}"></TextBox> <Button Grid.Column="1" Content="Delete"></Button> </Grid> </DataTemplate> <local:ModelSelector x:Key="tplSelector" ViewTemplate="{StaticResource DTView}" EditTemplate="{StaticResource DTEdit}" /> </UserControl.Resources> <ListView x:Name="list" ItemsSource="{x:Bind MyListCollection, Mode=TwoWay}"> <ListView.ItemTemplate> <DataTemplate x:DataType="local:ListModel"> <ListView ItemsSource="{x:Bind ModelList,Mode=TwoWay}" ItemTemplateSelector="{StaticResource tplSelector}"></ListView> </DataTemplate> </ListView.ItemTemplate> </ListView> </UserControl>
模型及其他类代码
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media; namespace UWPTest { public class Model { public string Text; public Model(string t) { Text = t; } } public class ListModel { public List<Model> ModelList = new List<Model>(); } public class ModelSelector : DataTemplateSelector { public DataTemplate ViewTemplate { get; set; } public DataTemplate EditTemplate { get; set; } protected override DataTemplate SelectTemplateCore(object item) { return StaticHelper.EditView ? EditTemplate : ViewTemplate; } protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) { return StaticHelper.EditView ? EditTemplate : ViewTemplate; } } static class StaticHelper { public static bool EditView { get; set; } = false; } public class DataService { private List<ListModel> _cache = new List<ListModel>(); public void LoadData() { _cache.Clear(); for (var i = 0; i < 5; i++) { ListModel nl = new ListModel(); for (var k = 0; k < 10; k++) { nl.ModelList.Add(new Model(i + "-" + k)); } _cache.Add(nl); } } public List<ListModel> getCachedEntries() { return _cache; } } }
运行效果
问题原因
DataTemplateSelector仅在ListView条目首次渲染时调用SelectTemplateCore方法选择模板,后续状态变更如果没有主动触发,已加载的条目不会重新选择模板。- 编辑状态存储在静态变量中,没有实现属性变更通知,UI层无法感知到状态变化。
- 嵌套ListView的可视化树加载顺序不同,首个ListView先完成渲染缓存了模板,后续状态变更不会主动刷新缓存。
解决方法
- 编辑状态切换时手动触发模板重选,在
EditMode属性的set方法中遍历外层ListView条目,重置内层ListView的ItemTemplateSelector强制重新选择模板,示例代码:
// EditMode变更时执行 for (int i = 0; i < list.Items.Count; i++) { if (list.ContainerFromIndex(i) is ListViewItem container) { var innerList = FindChild<ListView>(container); if (innerList != null) { var selector = innerList.ItemTemplateSelector; innerList.ItemTemplateSelector = null; innerList.ItemTemplateSelector = selector; } } } // 可视化树查找子元素方法 private T FindChild<T>(DependencyObject parent) where T : DependencyObject { if (parent == null) return null; for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) { var child = VisualTreeHelper.GetChild(parent, i); if (child is T target) return target; var result = FindChild<T>(child); if (result != null) return result; } return null; }
- 替换静态存储的编辑状态,改为实现
INotifyPropertyChanged的可绑定属性,或者将编辑状态作为依赖属性传入用户控件,确保状态变更可被UI感知。 - 也可以改用DataTrigger绑定编辑状态直接切换
ItemTemplate,无需通过TemplateSelector,状态响应更直接。
内容的提问来源于stack exchange,提问作者TinoZ
相关产品推荐
相关产品推荐

