2010-08-07 6 views
8

Je souhaite créer un StackPanel personnalisé avec une propriété ReverseOrder que je peux déclarer comme vrai pour que les éléments du StackPanel apparaissent dans l'ordre inverse de la normale (par exemple, de bas en haut ou de droite) à gauche). Il doit être réversible à la volée.Construction d'un StackPanel réversible dans WPF

Je pense à dériver une nouvelle classe de StackPanel, mais j'ai besoin de savoir quelles méthodes remplacer.

solution finale:

protected override System.Windows.Size ArrangeOverride(System.Windows.Size arrangeSize) { 
    double x = 0; 
    double y = 0; 

    IEnumerable<UIElement> children = ReverseOrder ? InternalChildren.Cast<UIElement>().Reverse<UIElement>() : InternalChildren.Cast<UIElement>(); 
    foreach (UIElement child in children) { 
     var size = child.DesiredSize; 
     child.Arrange(new Rect(new Point(x, y), size)); 

     if (Orientation == Orientation.Horizontal) 
      x += size.Width; 
     else 
      y += size.Height; 
    } 

    if (Orientation == Orientation.Horizontal) 
     return new Size(x, arrangeSize.Height); 
    else 
     return new Size(arrangeSize.Width, y); 
} 

définissent également et le registre ReverseOrder et appellent UpdateLayout si elle change.

Répondre

12

Vous pouvez réimplémenter FrameworkElement.ArrangeOverride et appeler l'ensemble child.Arrange dans l'ordre inverse de l'habitude si nécessaire.

http://msdn.microsoft.com/en-us/library/system.windows.uielement.arrange.aspx

Quelque chose comme ça (non testé):

double x = 0; 
    double y = 0; 

    var children = ReverseOrder ? InternalChildren.Reverse() : InternalChildren; 
    foreach (UIElement child in children) 
    { 
     var size = child.DesiredSize; 
     child.Arrange(new Rect(new Point(x, y), size)); 

     if (Orientation == Horizontal) 
      x += size.Width; 
     else 
      y += size.Height; 
    } 

Assurez-vous que vous invoquez UpdateLayout après avoir changé la propriété ReverseOrder.

+0

Parfait! Merci - je n'avais même pas à penser à ça! ;) – devios1

+1

quel effet a l'inversion des uielements? qu'arrive-t-il réellement dans ArrangeOverride comme précédemment? –

3

MeasureOverride et ArrangeOverride

En fait, votre logique de mesure peut être le même que StackPanel, vous pourriez être en mesure de simplement remplacer ArrangeOverride. Sachez que StackPanel a une certaine logique pour gérer le défilement que vous devrez peut-être dupliquer si vous l'écrivez vous-même. Vous voudrez peut-être hériter directement de Panel et ne pas essayer de supporter le défilement. Voir Custom Panel Elements dans la page MSDN sur Panneaux ou diverses entrées de blog sur l'écriture de panneaux personnalisés tels que WPF Tutorial - Creating A Custom Panel Control ou Creating Custom Panels In WPF.

0

Voici une autre variante. Il est basé sur le reference source de StackPanel et est également capable de gérer les alignements d'éléments.

public class ReversibleStackPanel : StackPanel 
{ 
    public bool ReverseOrder 
    { 
     get => (bool)GetValue(ReverseOrderProperty); 
     set => SetValue(ReverseOrderProperty, value); 
    } 

    public static readonly DependencyProperty ReverseOrderProperty = 
     DependencyProperty.Register(nameof(ReverseOrder), typeof(bool), typeof(ReversibleStackPanel), new PropertyMetadata(false)); 


    protected override Size ArrangeOverride(Size arrangeSize) 
    { 
     bool fHorizontal = (Orientation == Orientation.Horizontal); 
     var rcChild = new Rect(arrangeSize); 
     double previousChildSize = 0.0; 

     var children = ReverseOrder ? InternalChildren.Cast<UIElement>().Reverse() : InternalChildren.Cast<UIElement>(); 
     foreach (UIElement child in children) 
     { 
      if (child == null) 
       continue; 

      if (fHorizontal) 
      { 
       rcChild.X += previousChildSize; 
       previousChildSize = child.DesiredSize.Width; 
       rcChild.Width = previousChildSize; 
       rcChild.Height = Math.Max(arrangeSize.Height, child.DesiredSize.Height); 
      } 
      else 
      { 
       rcChild.Y += previousChildSize; 
       previousChildSize = child.DesiredSize.Height; 
       rcChild.Height = previousChildSize; 
       rcChild.Width = Math.Max(arrangeSize.Width, child.DesiredSize.Width); 
      } 

      child.Arrange(rcChild); 
     } 

     return arrangeSize; 
    } 
}