2014-10-03 36 views
0

我需要在可调整大小的列中显示一段文本。文本应该包含溢出,但对于给定的列大小,用户应该能够水平滚动以查看溢出的文本。带溢出的可滚动包装

我不相信这可以实现w/out框控件;如果我错了,请告诉我。我试图用一个自定义的控制来实现这一点:

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> 

这工作,成为时尚后。它正确包装和显示文本,水平滚动条让我查看溢出的文本。如果我调整列的右侧(较大),则文本会正确重新打包。但是,如果我将列调整到左侧(较小),文本将不会重新包装。因此,例如,如果我将列的大小调整为右侧,以便所有文本都位于同一行上,则无论后续调整大小,它都将保留在同一行上。这是一个不可接受的错误。

我对这个代码做了很多修改,尽管我没有找到一个可以找到解决方案的好方法。我不知道,也无法发现任何强制文本块重新包装其内容的机制。有什么建议?

+1

只有一个评论,但我已经看到了这种情况,当你缩小尺寸时,UI渲染就不会重新测量。甚至发现了一些来自MSFT的设计。 – Paparazzi 2014-10-03 15:49:25

+0

这似乎很有希望。你有没有机会阅读关于它的内容? – mcwyrm 2014-10-03 16:34:47

+0

不,但如果你搜索我的问题,我知道我问过这个问题。我得到了一个很好的答案,只是告诉我这是一个死路一条。 – Paparazzi 2014-10-03 16:46:06

回答

0

我能得到这个工作(W /一些限制),通过添加以下到自定义控制:

//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 s不起作用(尽管对我来说这不是必需的用例),它偶尔会闪烁,我担心wrapPoints集合可能会变得非常大。但它做我需要做的事情。