2014-10-03 65 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集合可能會變得非常大。但它做我需要做的事情。