【问题标题】:WPF ListBoxItem with WrapPanel doesn't wrap when vertical scrollbar is visible当垂直滚动条可见时,带有 WrapPanel 的 WPF ListBoxItem 不会换行
【发布时间】:2017-09-28 14:07:46
【问题描述】:

我有一个 WPF ListView,其中包含多个具有 WrapPanel 的 ItemsControl。 只要没有可见的滚动条,项目就会按预期包装。当滚动条可见时,当窗口变窄时,我可以看到 WrapPanel 为需要移动到左侧列的项目声明垂直空间,但项目不移动。使用滚动条滚动后,项目会跳转到正确的列。

有人遇到过这种情况吗?有人知道解决办法吗?

影片剪辑会更清晰,但在下面的图片中,我会尝试解释步骤和发生的情况。项目代码贴在图片下方。

没有滚动条,环绕效果很好:

没有滚动条,窗口更窄,换行仍然可以正常工作:

滚动条可见,换行还可以:

滚动条可见,屏幕变窄,绿色环绕面板显示为应该移动到最左列的项目占用了垂直空间,但这些项目没有移动:

使用滚动条后,项目跳转到正确的列:

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 = "abcdefghijklmnopqrstuvwxyz0123456789";
        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));
    }
}

虚拟对象:

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));
    }
}

【问题讨论】:

  • 订阅 ListBox 的 SizeChanged 事件并在其上调用 UpdareLayout() 有什么不同吗?或者更准确地命名 WrapPanel 并更新其布局。
  • @shadow32 我在可视化树中的几乎所有内容上尝试了 UpdateLayout()、InvalidateArrange()、InvalidateMeasure()、InvalidateParentsOfModifiedChildren()、InvalidateProperty(ActualHeightProperty)、InvalidateProperty(ActualWidthProperty),但无济于事。

标签: wpf listview itemscontrol wrappanel


【解决方案1】:

原来ListView不擅长滚动。禁用外部 ListView 上的滚动条并将其包装在 ScrollViewer 中后,内部 WrapPanels 和包含的项目将按预期运行。我花了一天时间才弄清楚这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-03
    • 2011-11-30
    • 2023-03-17
    • 2011-06-05
    • 2013-12-18
    • 1970-01-01
    • 2014-07-20
    • 1970-01-01
    相关资源
    最近更新 更多