WPF UserControl如何基于内部TextBlock内容实现阶梯式动态高度
问题原因
你当前的实现直接将ScrollViewer放在Grid中,而ScrollViewer默认布局逻辑会占用父容器分配的所有可用高度,因此会直接将UserControl撑到你设置的MaxHeight=64,无法根据内部文本高度动态收缩。
解决方案
需要结合XAML调整和少量后台代码实现阶梯高度适配,修改如下:
1. XAML代码调整
<UserControl x:Class="Test.UI.View.Controls.ErrorBannerControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:Test.UI.View.Controls" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="400" MinHeight="40" MaxHeight="64" Background="#FFF8F8" SizeChanged="ErrorBannerControl_SizeChanged" Loaded="ErrorBannerControl_Loaded"> <Grid Margin="16,8,16,8"> <Grid.ColumnDefinitions> <ColumnDefinition Width="16"></ColumnDefinition> <ColumnDefinition Width="*"></ColumnDefinition> </Grid.ColumnDefinitions> <TextBlock Grid.Column="0" FontFamily="Segoe MDL2 Assets" Text="" FontSize="16" Foreground="Red" VerticalAlignment="Center" /> <ScrollViewer x:Name="ErrorScrollViewer" Grid.Column="1" VerticalScrollBarVisibility="Auto"> <TextBlock x:Name="TextBlockError" Margin="8,0,0,0" Foreground="Red" FontSize="12" VerticalAlignment="Center" TextWrapping="Wrap" /> </ScrollViewer> </Grid> </UserControl>
主要改动点:
- 给UserControl添加
SizeChanged和Loaded事件监听,用于宽度变化、初始化时重新计算高度 - 给ScrollViewer添加
x:Name方便后台控制滚动条显隐
2. 后台代码调整
using System; using System.Windows; using System.Windows.Controls; namespace Test.UI.View.Controls { public partial class ErrorBannerControl : UserControl { public static readonly DependencyProperty ErrorTextProperty = DependencyProperty.Register("ErrorText", typeof(string), typeof(ErrorBannerControl), new FrameworkPropertyMetadata(ErrorTextChangedCallback)); public ErrorBannerControl() { InitializeComponent(); } // 修正依赖属性CLR包装,符合WPF规范 public string ErrorText { get => (string)GetValue(ErrorTextProperty); set => SetValue(ErrorTextProperty, value); } private static void ErrorTextChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) { var errorBannerControl = (ErrorBannerControl)d; errorBannerControl.TextBlockError.Text = Convert.ToString(e.NewValue); errorBannerControl.UpdateControlHeight(); } private void ErrorBannerControl_SizeChanged(object sender, SizeChangedEventArgs e) { // 控件宽度变化时可能导致文本换行,重新计算高度 UpdateControlHeight(); } private void ErrorBannerControl_Loaded(object sender, RoutedEventArgs e) { // 初始化时计算高度 UpdateControlHeight(); } // 核心高度计算逻辑 private void UpdateControlHeight() { if (TextBlockError == null || !IsLoaded) return; // 等待TextBlock布局更新完成后获取实际行数 Dispatcher.InvokeAsync(() => { int lineCount = TextBlockError.LineCount; if (lineCount <= 1) { Height = 40; ErrorScrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden; } else if (lineCount == 2) { Height = 52; ErrorScrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden; } else { Height = 64; ErrorScrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Auto; } }, System.Windows.Threading.DispatcherPriority.Loaded); } } }
主要改动点:
- 修正了依赖属性CLR包装的错误实现,避免绑定场景下赋值失效
- 新增
UpdateControlHeight方法,根据文本实际行数匹配对应的阶梯高度,同时控制滚动条显隐 - 新增文本变更、控件宽度变化、初始化三个场景的高度计算触发逻辑
内容的提问来源于stack exchange,提问作者Action Heinz
相关产品推荐
相关产品推荐

