Yêu cầu: Trong một ứng dụng cập nhật phiên bản, cần hiển thị thông tin dạng văn bản với chiều rộng cố định nhưng chiều cao thay đổi linh hoạt theo nội dung. Chiều cao phải nằm trong khoảng cho phép — có giá trị tối thiểu và tối đa. Khi nội dung vượt quá giới hạn chiều cao, thanh cuộn dọc sẽ xuất hiện.
Cụ thể, control cần đảm bảo:
- Chiều cao tự động co giãn theo nội dung văn bản.
- Không nhỏ hơn
MinHeight. - Không lớn hơn
MaxHeight. - Vượt quá
MaxHeightthì kích hoạt thanh cuộn.
Phân tích giải pháp
Thành phần chính gồm:
- Một
Borderlàm khung chứa (đặtMinHeight="207",MaxHeight="503"). - Bên trong là
ScrollViewerbao quanhTextBlockđể xử lý văn bản dài. - Chiều cao của
Bordercần được cập nhật động dựa trên độ cao thực tế của nội dung văn bản.
Vấn đề đặt ra: Nếu chỉ thiết lập MinHeight và MaxHeight, WPF sẽ chiếm dụng toàn bộ không gian đến MaxHeight, bất kể nội dung ngắn hay dài — điều này không đáp ứng yêu cầu "tự động co giãn".
Giải pháp: Dùng Binding kết hợp ValueConverter
Ý tưởng chính: Ràng buộc (bind) thuộc tính Height của Border vào ExtentHeight của ScrollViewer — giá trị này phản ánh chiều cao thực tế của nội dung bên trong vùng cuộn.
Bước 1: Tạo Converter chuyển đổi chiều cao
Tạo lớp converter để lấy ExtentHeight từ ScrollViewer và cộng thêm khoảng đệm (padding, margin) nếu cần để đảm bảo hiển thị đầy đủ các thành phần khác trong layout.
using System;
using System.Globalization;
using System.Windows.Data;
public class DynamicHeightConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is double extentHeight)
{
// Cộng thêm khoảng không gian cố định dành cho tiêu đề, nút,...
const double fixedSpace = 80;
return Math.Max(207, Math.Min(extentHeight + fixedSpace, 503));
}
return 207; // Giá trị mặc định tối thiểu
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
Bước 2: Áp dụng Binding trong XAML
Đăng ký converter trong tài nguyên cửa sổ và ràng buộc Height của Border tới ExtentHeight của ScrollViewer.
<Window x:Class="DynamicHeightApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DynamicHeightApp"
Title="Cập Nhật Phiên Bản" Width="800" Height="500">
<Window.Resources>
<local:DynamicHeightConverter x:Key="HeightConverter"/>
</Window.Resources>
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<Border x:Name="ContentBorder"
Width="360"
MinHeight="207"
MaxHeight="503"
Height="{Binding ElementName=ContentScroller, Path=ExtentHeight, Converter={StaticResource HeightConverter}}"
Background="#F0F0F0"
Padding="30,10,30,20"
CornerRadius="10"
BorderThickness="1"
BorderBrush="#DDD">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Tiêu đề -->
<TextBlock Grid.Row="0"
Margin="0,20,0,0"
FontSize="20"
FontWeight="Bold"
Text="Phát hiện phiên bản mới!" />
<!-- Mô tả ngắn -->
<TextBlock Grid.Row="1"
Margin="0,16,0,8"
FontSize="16"
FontWeight="SemiBold"
Text="Thông tin phiên bản" />
<!-- Nội dung cuộn -->
<ScrollViewer Grid.Row="2"
x:Name="ContentScroller"
Margin="0,10"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled"
CanContentScroll="True"
PanningMode="VerticalOnly">
<TextBlock x:Name="ContentText"
TextWrapping="Wrap"
FontSize="14"
Margin="0,0,10,10"
Text="Nội dung mô tả cập nhật rất dài... [dữ liệu mẫu]" />
</ScrollViewer>
<!-- Nút hành động -->
<StackPanel Grid.Row="3"
Margin="0,10,0,0"
Orientation="Horizontal"
HorizontalAlignment="Right"
VerticalAlignment="Center">
<Button Content="Hoãn lại"
Background="#E7E7E7"
Foreground="#000"
Padding="12,6"/>
<Button Content="Cập nhật ngay"
Margin="10,0,0,0"
Background="#0052D9"
Foreground="#FFF"
Padding="12,6"/>
</StackPanel>
</Grid>
</Border>
</Grid>
</Window>
Giải thích hoạt động
ScrollViewer.ExtentHeight: Trả về chiều cao tổng thể của nội dung bên trong (không bị giới hạn bởi vùng hiển thị).DynamicHeightConverter: Nhận giá trị này, cộng thêm không gian cho các thành phần cố định (tiêu đề, nút), sau đó giới hạn trong khoảng [207, 503].HeightcủaBorderđược cập nhật liên tục khi nội dung thay đổi — giúp giao diện co giãn mềm dẻo.
Kết quả: Với nội dung ngắn, hộp thoại co lại vừa vặn. Với nội dung dài, nó mở rộng đến giới hạn cho phép rồi kích hoạt thanh cuộn — đúng như yêu cầu ban đầu.