You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
        }
    }
}

运行效果

运行效果截图

问题原因

  1. DataTemplateSelector仅在ListView条目首次渲染时调用SelectTemplateCore方法选择模板,后续状态变更如果没有主动触发,已加载的条目不会重新选择模板。
  2. 编辑状态存储在静态变量中,没有实现属性变更通知,UI层无法感知到状态变化。
  3. 嵌套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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 00:06:03