我需要在可调整大小的列中显示一个文本块。文本应该包含溢出,但是对于给定的列大小,用户应该能够水平滚动以查看溢出的文本。
我不相信这可以通过开箱即用的控制来实现;如果我错了,请告诉我。我尝试使用自定义控件实现此目的:
public class Sizer : ContentPresenter
{
static Sizer()
{
ContentPresenter.ContentProperty.OverrideMetadata(typeof(Sizer), new FrameworkPropertyMetadata(ContentChanged)); ;
}
public Sizer() : base() {}
protected override Size MeasureOverride(Size constraint)
{
var childWidth = Content==null ? 0.0 : ((FrameworkElement)Content).RenderSize.Width;
var newWidth = Math.Max(RenderSize.Width, childWidth);
return base.MeasureOverride(new Size(newWidth, constraint.Height));
}
private static void ContentChanged(DependencyObject dep, DependencyPropertyChangedEventArgs args)
{
var @this = dep as Sizer;
var newV = args.NewValue as FrameworkElement;
var oldV = args.OldValue as FrameworkElement;
if (oldV != null)
oldV.SizeChanged -= @this.childSizeChanged;
if(newV!=null)
newV.SizeChanged += @this.childSizeChanged;
}
private void childSizeChanged(object sender, SizeChangedEventArgs e)
{
this.InvalidateMeasure();
}
}
...我可以在一个简单的WPF应用程序中测试它,如下所示:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ScrollViewer Grid.Column="0" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto" VerticalAlignment="Top">
<local:Sizer>
<local:Sizer.Content>
<TextBlock Background="Coral" Text="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaa"
TextWrapping="WrapWithOverflow" />
</local:Sizer.Content>
</local:Sizer>
</ScrollViewer>
<GridSplitter Grid.Column="1" Background="Black" VerticalAlignment="Stretch" HorizontalAlignment="Left" Width="5" />
</Grid>
这是一种时尚之后的作品。它正确地包装和显示文本,水平滚动条让我查看溢出的文本。如果我将列调整到右侧(更大),则文本会正确重新包装。但是,如果我将列调整到左侧(较小),则文本将不会重新换行。因此,例如,如果我向右调整列的大小以使所有文本都在一行上,则无论后续的重新调整大小,它都将保持在一行上。这是一个不可接受的错误。
我已经修改了这个代码很多,虽然我没有找到你称之为寻找解决方案的好策略。我不知道也无法发现强制文本块重新包装其内容的任何机制。有什么建议吗?
答案 0 :(得分:0)
通过将以下内容添加到自定义控件中,我能够实现此功能(具有一些限制):
//stores first ScrollViewer ancestor
private ScrollViewer parentSV = null;
//stores collection of observed valid widths
private SortedSet<double> wrapPoints = new SortedSet<double>();
protected override void OnVisualParentChanged(DependencyObject oldParent)
{
parentSV = this.FindParent<ScrollViewer>();
base.OnVisualParentChanged(oldParent);
}
...并编辑MeasureOverride列出:
protected override Size MeasureOverride(Size constraint)
{
if (parentSV != null)
{
var childWidth = Content == null ? 0.0 : ((FrameworkElement)Content).RenderSize.Width;
var viewportWidth = parentSV.ViewportWidth;
if (childWidth > viewportWidth + 5)
wrapPoints.Add(childWidth);
var pt = wrapPoints.FirstOrDefault(d => d > viewportWidth);
if (pt < childWidth)
childWidth = pt;
return base.MeasureOverride(new Size(childWidth, constraint.Height));
}
else
return base.MeasureOverride(constraint);
}
我根本不喜欢这个。它不适用于WrapPanel
(虽然这对我来说不是必需的用例),它偶尔会闪烁,我担心wrapPoints集合可能会变得非常大。但它做了我需要做的事情。