WPF如何实现RichTextBox的宽度跟随父控件?

3

我这里有一个简单的窗口:

enter image description here

上半部分是一个DataGrid,下面是一个TextBox。窗口设置为根据内容自适应宽度,这是期望的布局。

现在我需要显示一些富文本,所以我将TextBox替换为RichTextBox。问题是现在窗口会像这样拉伸到屏幕的宽度(当然我已经缩小了它,但你可以明白我的意思):

enter image description here

我尝试将RichTextBox的宽度绑定到父容器的实际宽度:

 <RichTextBox Width="{Binding ElementName=Wrapper, Path=ActualWidth}"/>

但是它仍然扩展到整个窗口。顺便说一下,如果我在上面的代码中使用TextBox,情况也是一样的。
如何使RichTextBox的宽度适合父容器,同时仍然保持动态窗口布局?我的意思是DataGrid是关键元素,两个窗口的宽度和RichTextBox的宽度都必须受它的影响。
以下是完整的代码。
XAML
<Window x:Class="RichTextBox_Wrap.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:RichTextBox_Wrap"
        mc:Ignorable="d"
        SizeToContent="Width"
        Title="MainWindow" Height="250" >
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="30"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <DataGrid Grid.Row="0" 
                  HeadersVisibility="Column" 
                  CanUserAddRows="False"
                  ItemsSource="{Binding Items}">
        </DataGrid>
        <StackPanel Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center">
            <TextBlock Text="Info" />
        </StackPanel>
        <DockPanel x:Name="Wrapper" Grid.Row="2">
            <Border BorderBrush="CadetBlue" BorderThickness="1">
                <RichTextBox />
            </Border>
        </DockPanel>
    </Grid>
</Window>

C#
public class Item
    {
        public string Name { get; set; }
        public string Description { get; set; }
        public double Price { get; set; }
    }

    public class ViewModel
    {
        public ObservableCollection<Item> Items { get; set; }

        public ViewModel()
        {
            Items = new ObservableCollection<Item>
            {
                new Item {Name = "Apple", Description="Fruit", Price=3},
                new Item {Name = "Banana", Description="Fruit", Price=5},
                new Item {Name = "Tomato", Description="Vegetable", Price=4},
            };
        }
    }

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new ViewModel();
        }
    }

解决方案

1. mm8的解决方案几乎有效,但似乎Loaded事件发生得太早,不能正确地计算ActualWidth - RichTextBox没有填充宽度并留下间隙。但是将这个想法进一步使用,我使用窗口的“Content_Rendered”事件来修复窗口的宽度,然后将RichTextBox的宽度设置为自动。

<RichTextBox x:Name="RichBox" Grid.Row="1" MinHeight="75" Width="0" Visibility="Hidden" />

private void Window_ContentRendered(object sender, EventArgs e)
{
    var window = sender as Window;
    window.SizeToContent = SizeToContent.Manual;
    window.Width = window.ActualWidth;
    RichBox.Width = double.NaN;
    RichBox.Visibility = Visibility.Visible;
}

2. Spongebrot 的想法很正确。事实上,当额外的边框被删除后,绑定到父元素的 ActualWidth 是有效的。但在现实生活中,我的控件更为复杂,边框存在是有原因的。不过这可以通过级联绑定来解决:

<DockPanel x:Name="Wrapper" Grid.Row="2" >
    <Border x:Name="MyBorder" BorderBrush="CadetBlue" BorderThickness="1" Width="{Binding ElementName=Wrapper, Path=ActualWidth}" >
        <RichTextBox x:Name="RichBox" Width="{Binding ElementName=MyBorder, Path=Width}" />
    </Border>
</DockPanel>

如果绑定到祖父级或更远的祖先,则绑定到ActualWidth似乎无法按预期工作。这似乎是为什么Sinatr的建议也不起作用的原因。


我不明白你的问题是什么,你应该能够使用默认布局来完成这个任务。 - Filip Cordas
检查您的RichTextBox是否具有特定的高MinWidth。 也许如果您降低该值,它就不会拉伸窗口? - Mishka
你应该将边框 DockDockPanel 上吗?尝试在你的 Border 中添加属性 DockPanel.Dock=Left,看看是否能得到你想要的效果。 - praty
1
实际宽度绑定的问题似乎在于您的边框边框厚度。如果您直接在RichtTextBox控件上设置边框,则包装器的ActualWidth绑定似乎可以正常工作。 - Spongebrot
2个回答

3
一个简单的解决方法是在 XAML 标记中将 RichTextBox 的 Width 设置为 0,然后处理它的 Loaded 事件并在加载后将 Width 设置为窗口的宽度:
<RichTextBox Width="0" Loaded="RichTextBox_Loaded" />

private void RichTextBox_Loaded(object sender, RoutedEventArgs e)
{
    RichTextBox rtb = sender as RichTextBox;
    rtb.Width = this.Width;
}

1

SizeToContent="Width"

您希望窗口自适应的宽度吗?

RichTextBox似乎很特殊,它会从其父容器请求最大可用空间,并随意占用整个组合桌面的宽度。一个简单的解决方法是限制它的宽度:

<Grid>
    <DataGrid x:Name="dataGrid" />
    <DockPanel>
        <Border>
            <RichTextBox Width="{Binding ActualWidth, ElementName=dataGrid}" />
        </Border>
    </DockPanel>
</Grid>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接