2

WPFカスタム作業ウィンドウを持つワード アドインがあります。その中で私は持っていListviewます。listviewWord 文書を下にスクロールするときに、各項目の位置を動的に更新する必要があります。しかし、それらのいくつかは同じ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 ではありません (ただし、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;
        }
    }
}
于 2016-03-14T15:49:10.737 に答える