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:
Aucune barre de défilement, fenêtre encore plus étroite, l'emballage fonctionne toujours très bien:
Une barre de défilement est visible, l'emballage est toujours 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:
Après avoir utilisé la barre de défilement, les éléments sautent à la colonne correcte:
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));
}
}
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
@ shadow32 J'ai essayé UpdateLayout(), InvalidateArrange(), InvalidateMeasure(), InvalidateParentsOfModifiedChildren(), InvalidateProperty (ActualHeightProperty), InvalidateProperty (ActualWidthProperty) sur à peu près tout dans l'arborescence visuelle, en vain. – eriksmith200