2

我有一个单词插件,它有一个WPF自定义任务窗格。在那我有一个Listview. listview当word文档向下滚动时,我需要动态更新每个项目的位置。但其中一些可能具有相同canvas.top(vertical Y)的价值。然后这些项目会重叠。

我不需要重叠这些,我需要因为列表视图需要一个接一个地对齐。

屏幕样本

代码示例 XAML..

<listViewTool:ListView x:Name="Results" Margin="0" BorderThickness="0" DockPanel.Dock="Top" Background="WhiteSmoke"
                  ScrollViewer.HorizontalScrollBarVisibility="Disabled"                      
                  ItemsSource="{Binding Results}"
                  SelectionMode="Single">
    <listViewTool:ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="Control.HorizontalContentAlignment" Value="Stretch"/>
            <Setter Property="Control.Margin" Value="0"/>
            <Setter Property="Control.Padding" Value="0"/>
            <Setter Property="Control.BorderThickness" Value="0"/>
            <Setter Property="IsSelected" Value="{Binding Path=Selected, Mode=TwoWay}"/>
            <Setter Property="Canvas.Top" Value="{Binding Y}"/>
            <Setter Property="Canvas.Left" Value="0"/>
            <Setter Property="Canvas.Width" Value="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ListView}},Path=ActualWidth}" />
        </Style>
    </listViewTool:ListView.ItemContainerStyle>
    <listViewTool:ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas x:Name="CanvasMain" HorizontalAlignment="Stretch" Height="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ListView}},Path=ActuaHeight}"
                            ClipToBounds="True" />
        </ItemsPanelTemplate>
    </listViewTool:ListView.ItemsPanel>
</listViewTool:ListView>

谢谢。

4

1 回答 1

1

我做了一个简单的解决方案,如下所示:


想法是存储项目的高度并在更改任何一个高度时重新计算所有项目的位置。

项目高度是项目模板边框ActualHeight。对于每个项目:Y是初始位置,Offset计算/用于绑定(基于Height当前项目之前的项目)。

解决方案包含一些调试代码(Text属性和绑定)并且不是纯 MVVM(但您没有要求):

xml:

<ListView ItemsSource="{Binding Items}">
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="Canvas.Left"
                    Value="0" />
            <Setter Property="Canvas.Top"
                    Value="{Binding Offset}" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListViewItem">
                        <Border CornerRadius="10"
                                BorderThickness="1"
                                BorderBrush="Gray"
                                SizeChanged="Border_SizeChanged">
                            <Expander Header="{Binding Text}">
                                <Grid Height="50" />
                            </Expander>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ListView.ItemContainerStyle>
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas Height="{Binding ActualHeight, RelativeSource={RelativeSource FindAncestor, AncestorType=ListView}}"
                    ClipToBounds="True" />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
</ListView>

CS:

public class Item : INotifyPropertyChanged
{
    // INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName] string property = "") =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));

    public double Y { get; set; }
    public double Height { get; set; }

    double _offset;
    public double Offset
    {
        get { return _offset; }
        set
        {
            _offset = value;
            OnPropertyChanged();
            OnPropertyChanged(nameof(Text));
        }
    }

    public string Text => $"Y={Y} Height={Height} Offset={Offset}";
}

public partial class MainWindow : Window
{
    public ObservableCollection<Item> Items { get; } = new ObservableCollection<Item>();

    public MainWindow()
    {
        InitializeComponent();
        for (int i = 0; i < 10; i++)
            Items.Add(new Item { Y = i * 40 });
        DataContext = this;
    }

    void Border_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        var border = (Border)sender;
        var current = (Item)border.DataContext;
        current.Height = border.ActualHeight;
        // recalculate offset
        var y = Items[0].Y;
        foreach (var item in Items)
        {
            item.Offset = y > item.Y ? y : item.Y;
            y = item.Offset + item.Height;
        }
    }
}
于 2016-03-14T15:49:10.737 回答