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

如何通过后台代码修改ItemsControl.ItemTemplate内Border的宽高

实现方案

首先明确核心问题:DataTemplate是模板定义,不是实际的控件实例,你的ListBox每生成一个列表项,就会基于这个模板创建一套独立的控件,也就是说模板里的两个Border是每个列表项各有一对,不存在全局唯一的两个Border实例,因此无法直接通过x:Name在后台全局访问。

下面给两种可行的实现方式,优先推荐第二种绑定方案,更符合WPF开发逻辑,也更稳定。


方案1:遍历可视化树查找控件后修改

这种方式直接操作控件实例,适合不想改动原有绑定逻辑的场景。

  1. 先给XAML中的两个Border加上唯一的x:Name标识,避免查找时匹配到其他同类型控件:
    <!-- 外层Border -->
    <Border x:Name="RootCardBorder" Margin="10" Width="150" Height="225" Background="{StaticResource DetailsColor}">
        <StackPanel>
            <!-- 内层图片Border -->
            <Border x:Name="ImageBorder" Width="150" Height="225">
                <!-- 原有DockPanel、Image等内容保持不变 -->
            </Border>
            <!-- 原有Rectangle、TextBlock等内容保持不变 -->
        </StackPanel>
    </Border>
    
  2. 在后台类中添加可视化树查找的通用辅助方法:
    using System.Windows;
    using System.Windows.Media;
    
    // 从指定父控件出发,查找指定名称、指定类型的子控件
    private T FindVisualChild<T>(DependencyObject parent, string childName) where T : FrameworkElement
    {
        if (parent == null) return null;
    
        int childCount = VisualTreeHelper.GetChildrenCount(parent);
        for (int i = 0; i < childCount; i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(parent, i);
            if (child is T targetEle && targetEle.Name == childName)
            {
                return targetEle;
            }
    
            T result = FindVisualChild<T>(child, childName);
            if (result != null) return result;
        }
        return null;
    }
    
  3. 在尺寸调整按钮的点击事件中,遍历所有已生成的列表项,找到对应Border修改尺寸:
    // 定义全局变量存当前尺寸,处理列表滚动时新加载项的尺寸同步
    private double _targetWidth = 150;
    private double _targetHeight = 225;
    
    private void ResizeBtn_Click(object sender, RoutedEventArgs e)
    {
        // 替换为你需要调整到的目标尺寸
        _targetWidth = 200;
        _targetHeight = 300;
    
        // 遍历所有列表项
        foreach (var item in games_list.Items)
        {
            // 获取当前数据项对应的ListBoxItem容器
            ListBoxItem itemContainer = games_list.ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem;
            if (itemContainer == null) continue; // 开启虚拟化时未加载到可视区域的项直接跳过,后续加载时再同步
    
            // 查找两个Border
            Border rootBorder = FindVisualChild<Border>(itemContainer, "RootCardBorder");
            Border imgBorder = FindVisualChild<Border>(itemContainer, "ImageBorder");
    
            // 修改尺寸
            if (rootBorder != null)
            {
                rootBorder.Width = _targetWidth;
                rootBorder.Height = _targetHeight;
            }
            if (imgBorder != null)
            {
                imgBorder.Width = _targetWidth;
                imgBorder.Height = _targetHeight;
            }
        }
    }
    

    注意:如果ListBox开启了UI虚拟化,滚动后新生成的列表项会默认使用XAML中写死的原始尺寸,你还需要监听games_list.ItemContainerGenerator.StatusChanged事件,在新项生成时主动给对应Border赋值尺寸,否则会出现新旧项尺寸不一致的问题。


方案2:通过属性绑定实现自动同步(推荐)

既然两个Border尺寸始终保持一致,完全不需要手动查找控件,用WPF原生的属性绑定就能实现一次修改、所有项自动同步,还天然兼容UI虚拟化,不会出现漏改的问题。

  1. 给后台窗口/页面类添加可通知的宽高属性,实现INotifyPropertyChanged接口:
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    
    public partial class GamesListWindow : Window, INotifyPropertyChanged
    {
        private double _cardWidth = 150;
        private double _cardHeight = 225;
    
        // 卡片宽度
        public double CardWidth
        {
            get => _cardWidth;
            set
            {
                _cardWidth = value;
                OnPropertyChanged();
            }
        }
    
        // 卡片高度
        public double CardHeight
        {
            get => _cardHeight;
            set
            {
                _cardHeight = value;
                OnPropertyChanged();
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string propName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
        }
    
        // 原有构造函数、其他事件方法保持不变
    }
    
  2. 给XAML的窗口根节点添加x:Name标识,方便元素绑定,比如:
    <Window x:Name="RootWindow"
            <!-- 其他原有窗口属性保持不变 -->
            >
    
  3. 修改两个Border的宽高属性,改为绑定到窗口定义的尺寸属性上:
    <!-- 外层Border -->
    <Border Margin="10" 
            Width="{Binding ElementName=RootWindow, Path=CardWidth}" 
            Height="{Binding ElementName=RootWindow, Path=CardHeight}" 
            Background="{StaticResource DetailsColor}">
        <StackPanel>
            <!-- 内层图片Border -->
            <Border Width="{Binding ElementName=RootWindow, Path=CardWidth}" 
                    Height="{Binding ElementName=RootWindow, Path=CardHeight}">
                <!-- 原有内容保持不变 -->
            </Border>
            <!-- 其他原有内容保持不变 -->
        </StackPanel>
    </Border>
    
  4. 按钮点击事件里直接修改属性即可,不需要查找任何控件:
    private void ResizeBtn_Click(object sender, RoutedEventArgs e)
    {
        // 直接修改属性值,所有列表项的Border会自动同步尺寸
        CardWidth = 200;
        CardHeight = 300;
    }
    

这种方案没有遍历可视化树的性能开销,不管列表有多少项、怎么滚动,新加载的项都会自动读取最新的尺寸值,不会出现尺寸不一致的问题,是WPF场景下的首选实现方式。


内容的提问来源于stack exchange,提问作者Code9

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 01:42:23