2017-05-11 10 views
0

私は、コメントと署名のコレクションを表示するための2つのカスタムコントロールを持っています。これらのコントロールには、表示スタイルを変更するボタンがあります。コレクション全体または最初の4つの要素を表示します。MeasureOverrideを開始しないのはなぜですか?

これらのコントロールをデフォルトのWrapPanelに配置すると、それらはうまく動作します:ユーザーの操作に応じて展開または折りたたむ。 新しいArrangeOverride関数を使用した独自のWrapPanelでは、正常に動作します。

ここでは、オプション "LastChildFill"(ここでは例が見つかりました)とカスタム "WrapDirection"(FlowDirectionに似ています)のWrapPanelが必要です。 WrapPanelの最初または最後の要素は、残りの領域をすべて満たす必要がありますが、要素のMinWidth以上です。 カスタムMeasureOverrideとArrangeOverrideを使用してWrapPanelを3つ作成しました。私が望むように機能しますが、コントロールの表示スタイルを変更すると、コントロール内のコレクションが変更されますが、WrapPanelのMeasureOverrideはウィンドウのサイズを変更するまで開始しません。

更新:MeasureOverrideは、残りの領域を満たす最初または最後の要素を展開するために開始しません。この要素の折りたたみはうまく動作します。

私はカスタムMeasureOverrideで何が壊れているのか分かりませんか?

更新2: 私の問題は、MeasureOverride not always called on children's property changesと似ていると思います。

MeasureOverrideコードを添付します。

public class WrapPanelFlowDirection : WrapPanel 
{ 
    public bool LastChildFill 
    { 
     get { return (bool)GetValue(LastChildFillProperty); } 
     set { SetValue(LastChildFillProperty, value); } 
    } 

    public static readonly DependencyProperty LastChildFillProperty = 
     DependencyProperty.Register("LastChildFill", typeof(bool), typeof(WrapPanelFlowDirection), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsMeasure)); 

    public WrapDirection WrapDirection 
    { 
     get { return (WrapDirection)GetValue(WrapDirectionProperty); } 
     set { SetValue(WrapDirectionProperty, value); } 
    } 

    public static readonly DependencyProperty WrapDirectionProperty = 
     DependencyProperty.Register("WrapDirection", typeof(WrapDirection), typeof(WrapPanelFlowDirection), new FrameworkPropertyMetadata(WrapDirection.LeftToRight, FrameworkPropertyMetadataOptions.AffectsMeasure)); 

    #region Measure Override 

    protected override Size MeasureOverride(Size availableSize) 
    { 
     var panelSize = new Size(availableSize.Width, 0); 
     double minWidth = 0; 

     foreach (FrameworkElement child in this.InternalChildren) 
     { 
      child.Measure(availableSize); 
      minWidth += child.DesiredSize.Width; 
     } 

     int firstChildInLine = 0; 
     double currLineHeight = 0; 
     double currLineWidth = 0; 
     UIElementCollection children = this.InternalChildren; 

     for (int i = 0; i < children.Count; i++) 
     { 
      FrameworkElement child = children[i] as FrameworkElement; 
      if (child == null) 
       continue; 

      double w = 0; 
      if (child.MinWidth == 0) 
       w = child.DesiredSize.Width; 
      else 
       w = child.MinWidth; 

      if (currLineWidth + w <= availableSize.Width) 
      { 
       currLineWidth += w; 
       currLineHeight = Math.Max(currLineHeight, child.DesiredSize.Height); 
      } 
      else 
      { 
       MeasureOneLine(firstChildInLine, i - 1, ref currLineHeight, availableSize.Width); 
       panelSize.Height += currLineHeight; 
       currLineWidth = w; 
       currLineHeight = child.DesiredSize.Height; 
       if (w > availableSize.Width) 
       { 
        MeasureOneLine(i, i, ref currLineHeight, availableSize.Width); 
        panelSize.Height += currLineHeight; 
        currLineHeight = currLineWidth = 0; 
        firstChildInLine = i + 1; 
       } 
       else 
       { 
        firstChildInLine = i; 
       } 
      } 

     } 

     if (firstChildInLine < children.Count) 
     { 
      MeasureOneLine(firstChildInLine, children.Count - 1, ref currLineHeight, availableSize.Width); 
      panelSize.Height += currLineHeight; 
     } 

     if (double.IsInfinity(panelSize.Width)) 
      panelSize.Width = minWidth; 
     return panelSize; 
    } 

    private void MeasureOneLine(int start, int end, ref double height, double totalWidth) 
    { 
     UIElementCollection children = this.InternalChildren; 

     if (WrapDirection == WrapDirection.LeftToRight) 
     { 
      for (int i = start; i < end; i++) 
      { 
       FrameworkElement child = children[i] as FrameworkElement; 
       if (child == null) 
        continue; 

       double w = 0; 
       if (child.MinWidth == 0) 
        w = child.DesiredSize.Width; 
       else 
        w = child.MinWidth; 
       if (i < end) 
       { 
        child.Measure(new Size(w, height)); 
        totalWidth -= w; 
       } 
       else 
       { 
        child.Measure(new Size(totalWidth, double.PositiveInfinity)); 
        height = Math.Max(height, child.DesiredSize.Height); 
       } 
      } 
     } 
     else 
     { 
      for (int i = end; i >= start; i--) 
      { 
       FrameworkElement child = children[i] as FrameworkElement; 
       if (child == null) 
        continue; 

       double w = 0; 
       if (child.MinWidth == 0) 
        w = child.DesiredSize.Width; 
       else 
        w = child.MinWidth; 
       if (i > start) 
       { 
        child.Measure(new Size(w, height)); 
        totalWidth -= w; 
       } 
       else 
       { 
        child.Measure(new Size(totalWidth, double.PositiveInfinity)); 
        height = Math.Max(height, child.DesiredSize.Height); 
       } 
      } 
     } 
    } 

    #endregion 
+0

@クレメンス、私は同様の問題と添付コードを発見しました。何か案は? – Skarhl

答えて

0

私はここに解決策が見つかりました:How does a container know when a child has called InvalidateArrange?

をそして、それは私のために働きました。

public static void OnPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e) 
    { 
     UIElement panel= VisualTreeHelper.GetParent(source) as UIElement; 
     if(panel != null)  
      { 
       panel.InvalidateMeasure(); 
       panel.InvalidateArrange(); 
      } 
    } 
関連する問題