WPF Listview项目垂直定位与画布重叠问题

时间:2016-03-09 08:56:21

标签: c# wpf listview canvas word-addins

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

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

screen sample

代码示例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>

感谢。

1 个答案:

答案 0 :(得分:1)

我做了一个简单的解决方案,看起来像这样:

想法是存储物品的高度,并在高度改变时重新计算所有物品的位置。

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

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

XAML:

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