2017-09-28 4 views
2

J'ai un ListView WPF contenant plusieurs ItemsControl qui ont WrapPanels. Les éléments sont renvoyés comme prévu tant qu'aucune barre de défilement n'est visible. Quand il y a une barre de défilement visible, quand la fenêtre devient moins large, je peux voir le WrapPanel revendiquant l'espace vertical pour les éléments qui doivent se déplacer vers la colonne vers la gauche, mais les éléments ne bougent pas. Après le défilement à l'aide de la barre de défilement, les éléments sautent dans la bonne colonne.WPF ListBoxItem avec WrapPanel ne s'enroule pas lorsque la barre de défilement verticale est visible

Est-ce que quelqu'un a rencontré cela et quelqu'un connaît-il une solution? Un clip vidéo serait plus clair, mais dans les images ci-dessous, j'essaie d'expliquer les étapes et ce qui se passe. Le code du projet est affiché sous les photos.

Pas scrollbar, emballage fonctionne très bien: No scrollbar, wrapping works fine

Aucune barre de défilement, fenêtre encore plus étroite, l'emballage fonctionne toujours très bien: No scrollbar, even narrower window, wrapping still works fine

Une barre de défilement est visible, l'emballage est toujours ok: A scrollbar is visible, wrapping is still ok

Une barre de défilement est visible, l'écran est plus étroit, le WrapPanel vert indique que l'espace vertical est revendiquée pour les éléments qui devraient passer à la colonne de gauche, mais les articles ne bougent pas: A scrollbar is visible, screen is narrower, the green wrappanel shows that vertical space is claimed for the items that should move to the leftmost column, but the items do not move

Après avoir utilisé la barre de défilement, les éléments sautent à la colonne correcte: After using the scrollbar, the items jump to the correct column

MainWindow.xaml

<Window x:Class="Wrapping.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Height="800" Width="600"> 
<Window.Resources> 

    <DataTemplate x:Key="DetailReadOnlyTemplate"> 
     <Grid Width="75" Height="15" Margin="2" Background="Green"/> 
    </DataTemplate> 

    <DataTemplate x:Key="MainObjectReadOnlyTemplate"> 
     <StackPanel> 
      <Grid VerticalAlignment="Top"> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition Width="Auto"/> 
        <ColumnDefinition Width="*"/> 
       </Grid.ColumnDefinitions> 
       <TextBlock Text="{Binding Number}"/> 
       <TextBlock Text="Some text" Grid.Column="1" HorizontalAlignment="Right"/> 
      </Grid> 

      <ItemsControl ItemsSource="{Binding DetailObjects}" 
          ItemTemplate="{StaticResource DetailReadOnlyTemplate}" 
          Background="LightGreen"> 
       <ItemsControl.ItemsPanel> 
        <ItemsPanelTemplate> 
         <WrapPanel/> 
        </ItemsPanelTemplate> 
       </ItemsControl.ItemsPanel> 
      </ItemsControl> 
     </StackPanel> 
    </DataTemplate> 

</Window.Resources> 

<ListView ItemsSource="{Binding MainObjects}" 
      SelectedItem="{Binding SelectedMainObject}" 
      ScrollViewer.HorizontalScrollBarVisibility="Disabled" 
      ItemTemplate="{StaticResource MainObjectReadOnlyTemplate}" 
      HorizontalContentAlignment="Stretch" 
      Background="Bisque"/> 
</Window> 

MainWindow.xaml.cs

public partial class MainWindow : INotifyPropertyChanged 
{ 
    private static readonly Random Random = new Random(); 

    public MainWindow() 
    { 
     DataContext = this; 

     InitializeComponent(); 

     MainObjects = new ObservableCollection<MainObject>(); 

     for (var i = 0; i < 10; i++) 
     { 
      MainObjects.Add(CreateMainObject(i)); 
     } 
    } 

    private ObservableCollection<MainObject> _mainObjects; 
    public ObservableCollection<MainObject> MainObjects 
    { 
     get => _mainObjects; 
     set 
     { 
      _mainObjects = value; 
      OnPropertyChanged(); 
     } 
    } 

    private MainObject _selectedMainObject; 
    public MainObject SelectedMainObject 
    { 
     get => _selectedMainObject; 
     set 
     { 
      _selectedMainObject = value; 
      OnPropertyChanged(); 
     } 
    } 

    private MainObject CreateMainObject(int n) 
    { 
     return new MainObject 
     { 
      DisplayText = "Main object " + n, 
      Number = n, 
      DetailObjects = GenerateDetailObjects() 
     }; 
    } 

    private ObservableCollection<DetailObject> GenerateDetailObjects() 
    { 
     var detailObjects = new ObservableCollection<DetailObject>(); 

     for (var i = 0; i < Random.Next(2, 4); i++) 
     { 
      detailObjects.Add(new DetailObject 
      { 
       DisplayText = "Detail " + i, 
       Value = GenerateRandomString(Random.Next(3, 8)) 
      }); 
     } 

     return detailObjects; 
    } 

    public static string GenerateRandomString(int length) 
    { 
     const string chars = "abcdefghijklmnopqrstuvwxyz"; 
     return new string(Enumerable.Repeat(chars, length).Select(s => s[Random.Next(s.Length)]).ToArray()); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    [NotifyPropertyChangedInvocator] 
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

Les objets factices:

public class MainObject : INotifyPropertyChanged 
{ 
    private int _number; 
    public int Number 
    { 
     get => _number; 
     set 
     { 
      _number = value; 
      OnPropertyChanged(); 
     } 
    } 

    private string _displayText; 
    public string DisplayText 
    { 
     get => _displayText; 
     set 
     { 
      _displayText = value; 
      OnPropertyChanged(); 
     } 
    } 

    private ObservableCollection<DetailObject> _detailObjects; 
    public ObservableCollection<DetailObject> DetailObjects 
    { 
     get => _detailObjects; 
     set 
     { 
      _detailObjects = value; 
      OnPropertyChanged(); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    [NotifyPropertyChangedInvocator] 
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

public class DetailObject : INotifyPropertyChanged 
{ 
    private string _displayText; 
    public string DisplayText 
    { 
     get => _displayText; 
     set 
     { 
      _displayText = value; 
      OnPropertyChanged(); 
     } 
    } 

    private string _value; 
    public string Value 
    { 
     get => _value; 
     set 
     { 
      _value = value; 
      OnPropertyChanged(); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    [NotifyPropertyChangedInvocator] 
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 
+0

Est-ce que l'abonnement à l'événement SizeChanged de ListBox et l'appel à UpdareLayout() sur celui-ci font une différence? Ou plus précisément nommer le WrapPanel et mettre à jour sa mise en page. – shadow32

+0

@ shadow32 J'ai essayé UpdateLayout(), InvalidateArrange(), InvalidateMeasure(), InvalidateParentsOfModifiedChildren(), InvalidateProperty (ActualHeightProperty), InvalidateProperty (ActualWidthProperty) sur à peu près tout dans l'arborescence visuelle, en vain. – eriksmith200

Répondre

1

Il se avère que ListView est pas très bon au défilement. Après avoir désactivé les barres de défilement sur le ListView externe et l'avoir enveloppé dans un ScrollViewer, les WrapPanels internes et les éléments contenus se comportent comme prévu. Il m'a fallu un jour pour comprendre cela.