web-dev-qa-db-fra.com

Panneau d'habillage WPF et défilement

J'ai un simple WrapPanel qui contient un certain nombre de contrôles larges. Quand je redimensionne le Width du Window tout fonctionne comme prévu. Les contrôles passeront sur une seule ligne s'il y a suffisamment d'espace ou passeront à la ligne suivante lorsqu'il n'y en a pas.

Cependant, ce que je dois arriver, c'est que si tous les contrôles sont essentiellement empilés verticalement (car il n'y a plus d'espace horizontal) et que le Width du Window est encore plus diminué, un horizontal la barre de défilement apparaît pour que je puisse faire défiler et voir l'intégralité du contrôle si je le souhaite. Ci-dessous est mon xaml. J'ai essayé d'encapsuler le WrapPanel dans un ScrollViewer mais je n'ai pas pu atteindre mon objectif.

<Window x:Class="WpfQuotes.Window1"
        xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="Auto" Width="600" Foreground="White">
    <WrapPanel>
      <Button Width="250">1</Button>
      <Button Width="250">2</Button>
      <Button Width="250">3</Button>
    </WrapPanel>
</Window>

Donc, si vous réduisez le Width de ce qui précède Window à son minimum, vous ne pourrez pas voir le texte des boutons. Je voudrais qu'une barre de défilement horizontale apparaisse pour que je puisse faire défiler pour voir le texte sans interférer avec la fonctionnalité habituelle d'habillage.

Merci.

Mise à jour: J'ai suivi la suggestion de Paul ci-dessous et la barre de défilement horizontale apparaît maintenant comme prévu. Cependant, je souhaitais également que le défilement vertical soit disponible, alors j'ai défini VerticalScrollBarVisibility="Auto". Le fait est que si je redimensionne la fenêtre pour qu'une barre de défilement verticale apparaisse, l'horizontale apparaît également toujours, même si ce n'est pas nécessaire (il y a suffisamment d'espace horizontal pour voir l'ensemble du contrôle). Il semble que la barre de défilement verticale apparaissant perturbe la largeur du visualiseur de défilement. Existe-t-il un moyen de corriger cela afin que la barre de défilement horizontale n'apparaisse que si elle est réellement nécessaire?

Voici mon xaml et le seul code que j'ai ajouté dans le CustomWrapPanel:

<Window x:Class="Window1"
        xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
        xmlns:cwp="clr-namespace:CustomWrapPanelExample"
        Title="Window1" Height="Auto" Width="300" Foreground="White" Name="mainPanel">
  <ScrollViewer x:Name="MyScrollViewer" HorizontalScrollBarVisibility="Auto"
                VerticalScrollBarVisibility="Auto">
    <cwp:CustomWrapPanel Width="{Binding ElementName=MyScrollViewer, Path=ActualWidth}">
      <Button Width="250">1</Button>
      <Button Width="250">2</Button>
      <Button Width="250">3</Button>
      <Button Width="250">4</Button>
      <Button Width="250">5</Button>
      <Button Width="250">6</Button>
      <Button Width="250">7</Button>
      <Button Width="250">8</Button>
      <Button Width="250">9</Button>
    </cwp:CustomWrapPanel>
  </ScrollViewer>
</Window>

La seule chose remplacée dans CustomWrapPanel:

protected override Size MeasureOverride(Size availableSize)
{
  double maxChildWidth = 0;
  if (Children.Count > 0)
  {
    foreach (UIElement el in Children)
    {
      if (el.DesiredSize.Width > maxChildWidth)
      {
        maxChildWidth = el.DesiredSize.Width;
      }
    }
  }      
  MinWidth = maxChildWidth;
  return base.MeasureOverride(availableSize);
}
21
Flack

Voici le truc, si vous allez utiliser un panneau enveloppant, il fait deux choses, il prendra autant d'espace disponible dans une direction et se développera au besoin dans l'autre. Par exemple, si vous le placez à l'intérieur d'une fenêtre comme vous l'avez, il prend autant d'espace horizontal que possible, puis se développe au besoin vers le bas, c'est pourquoi une barre de défilement verticale fonctionnera, le conteneur parent dit "c'est quelle largeur je suis, mais vous pouvez vous faire aussi grand que vous le souhaitez verticalement ", si vous le changez en une barre de défilement horizontale, le visualiseur de défilement dit essentiellement" c'est la taille que vous pouvez atteindre, mais vous pouvez être aussi large que vous voulez "dans ce cas, le panneau d'habillage ne s'enroule pas car il n'y a aucune contrainte horizontale.

Une solution potentielle consiste à changer la direction dans laquelle le panneau d'enroulement passe de l'horizontale à la verticale comme ceci (ce qui n'est probablement pas le comportement idéal ou attendu):

    <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
        <WrapPanel Orientation="Vertical">
            <Button Width="250">1</Button>
            <Button Width="250">2</Button>
            <Button Width="250">3</Button>
        </WrapPanel>
    </ScrollViewer>

Afin d'obtenir le comportement que vous attendez, vous devrez faire quelque chose de plus proche de ceci:

    <ScrollViewer x:Name="MyScrollViewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
        <WrapPanel MinWidth="250" Width="{Binding ElementName=MyScrollViewer, Path=ViewportWidth}">
            <Button Width="250">1</Button>
            <Button Width="250">2</Button>
            <Button Width="250">3</Button>
        </WrapPanel>
    </ScrollViewer>

Cependant, cette deuxième solution ne fonctionne que si vous connaissez déjà la largeur de vos éléments enfants, idéalement, vous voulez que votre largeur maximale soit définie sur la largeur réelle du plus grand élément enfant, mais pour ce faire, vous devez créer un contrôle personnalisé qui dérive du panneau d'habillage et écrivez le code vous-même pour le vérifier.

52
Paul Rohde
     public bool CheckUIElementInBounary(UIElement element, Rect r)
            {
                bool inbound = false;
                Point p1 = element.PointToScreen(new Point(0, 0));
                Point p2 = element.PointToScreen(new Point(0, element.RenderSize.Height));
                Point p3 = element.PointToScreen(new Point(element.RenderSize.Width, 0));
                Point p4 = element.PointToScreen(new Point(element.RenderSize.Width, element.RenderSize.Height));
                if (CheckPoint(p1, r) || CheckPoint(p2, r) || CheckPoint(p3, r) || CheckPoint(p4, r))
                {
                    inbound = true;
                }
                return inbound;
            }
            public bool CheckPoint(Point p, Rect bounday)
            {
                bool inbound = false;
                if (p.X >= bounday.Left && p.X <= bounday.Right && p.Y <= bounday.Top && p.Y <= bounday.Bottom)
                {
                    inbound = true;
                }
                return inbound;
            }

===================
void mainViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            foreach (var item in this.mainContent.Items)
            {
                Button btn = item as Button;
                Point p1 = mainViewer.PointToScreen(new Point(0, 0));
                Point p2 = mainViewer.PointToScreen(new Point(mainViewer.ActualWidth, mainViewer.ActualHeight));
                Rect bounds = new Rect(p1, p2);
                if (!CheckUIElementInBounary(btn, bounds))
                {
                    this.Title = btn.Content.ToString();
                    mainContent.ScrollIntoView(btn);
                    break;
                }
            }

        }
0
Suhas Bothe