C# wpf 列表视图为网格视图中的每一列提供单独的滚动条
本文关键字:视图 一列 滚动条 单独 列表 wpf 网格 | 更新日期: 2023-09-27 18:31:29
我希望每列都有单独的滚动条
<ListView ItemsSource="{Binding}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name"
DisplayMemberBinding="{Binding name}"/>
<GridViewColumn Header="Price"
DisplayMemberBinding="{Binding price}"/>
</GridView>
</ListView.View>
</ListView>
我想每列有 2 个水平滚动条(名称和价格),我的目的地是设置带有图片的列,但我想在图片变大时滚动该图片。
我找到了一种基于此解决方案仅在网格视图底部添加滚动的方法:如何在 WPF 列表视图 ( 网格视图 ) 中创建组页脚 。它看起来有点笨拙,但似乎还没有解决方案。我在 xaml 中所做的是将组描述绑定到一个假属性,以便只显示一次页脚。
XAML:
<PropertyGroupDescription PropertyName="fake" />
然后我修改了一个页脚模板,使其显示滚动条:
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<DockPanel>
<Grid DockPanel.Dock="Bottom" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding ElementName=first, Path=Width, UpdateSourceTrigger=PropertyChanged}" />
<ColumnDefinition Width="{Binding ElementName=second, Path=Width, UpdateSourceTrigger=PropertyChanged}" />
</Grid.ColumnDefinitions>
<ScrollBar Grid.Column="0" Orientation="Horizontal" Scroll="ScrollBar1_Scroll"
Width="{Binding ElementName=first, Path=Width, UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" >
</ScrollBar>
<ScrollBar Grid.Column="1" Orientation="Horizontal" Scroll="ScrollBar2_Scroll"
Width="{Binding ElementName=second, Path=Width, UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}"/>
</Grid>
<ItemsPresenter />
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
有很多绑定是调整带有列的滚动条大小所必需的。那里的另一个技巧:您必须首先为每个GridViewColumn
设置Width
,否则滚动条只会在您手动调整列大小后出现。我移动单元格的内容Margin
改变StackPanel
在CellTemplate
的属性。下面是整个代码,我认为这不是一个完整的工作解决方案,但是一个很好的起点。
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
<Grid>
<Grid.Resources>
<CollectionViewSource x:Key="ViewSource" Source="{Binding Path=Collection, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=Window} }">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="fake" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Grid.Resources>
<HeaderedItemsControl Header="ListView">
<StackPanel>
<ListView ItemsSource="{Binding Source={StaticResource ViewSource}, UpdateSourceTrigger=PropertyChanged}" x:Name="Lv" Margin="5,5,5,5">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<DockPanel>
<Grid DockPanel.Dock="Bottom" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding ElementName=first, Path=Width, UpdateSourceTrigger=PropertyChanged}" />
<ColumnDefinition Width="{Binding ElementName=second, Path=Width, UpdateSourceTrigger=PropertyChanged}" />
</Grid.ColumnDefinitions>
<ScrollBar Grid.Column="0" Orientation="Horizontal" Scroll="ScrollBar1_Scroll"
Width="{Binding ElementName=first, Path=Width, UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" >
</ScrollBar>
<ScrollBar Grid.Column="1" Orientation="Horizontal" Scroll="ScrollBar2_Scroll"
Width="{Binding ElementName=second, Path=Width, UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}"/>
</Grid>
<ItemsPresenter />
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
<ListView.View >
<GridView >
<GridViewColumn Header="Name" x:Name="first" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Margin="{Binding Path=Offset1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=Window} }">
<TextBlock x:Name="tb1" Text="{Binding name}"></TextBlock>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Price" x:Name="second" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Margin="{Binding Path=Offset2, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=Window} }" >
<TextBlock Text="{Binding price}"></TextBlock>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
</HeaderedItemsControl>
</Grid>
</Window>
和代码隐藏
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls.Primitives;
namespace WpfApplication1
{
public partial class MainWindow:INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
}
private List<MyItem> _collection = new List<MyItem>();
public List<MyItem> Collection
{
get { return _collection; }
set { _collection = value; InvokePropertyChanged(new PropertyChangedEventArgs("Collection")); }
}
private Thickness _offset1;
public Thickness Offset1
{
get { return _offset1; }
set { _offset1 = value; InvokePropertyChanged(new PropertyChangedEventArgs("Offset1")); }
}
private Thickness _offset2;
public Thickness Offset2
{
get { return _offset2; }
set { _offset2 = value; InvokePropertyChanged(new PropertyChangedEventArgs("Offset2")); }
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Collection.Add(new MyItem("item1", "10"));
Collection.Add(new MyItem("item2", "200"));
Collection.Add(new MyItem("item3", "600000"));
Collection.Add(new MyItem("item4", "1"));
}
private void ScrollBar1_Scroll(object sender, ScrollEventArgs e)
{
//imitate scrolling here
double leftToRight = Offset1.Left;
if (e.ScrollEventType == ScrollEventType.SmallIncrement)
leftToRight += 5;
if (e.ScrollEventType == ScrollEventType.SmallDecrement)
leftToRight -= 5;
Offset1 = new Thickness(leftToRight, 0, 0, 0);
}
private void ScrollBar2_Scroll(object sender, ScrollEventArgs e)
{
//imitate scrolling here
double leftToRight = Offset2.Left;
if (e.ScrollEventType == ScrollEventType.SmallIncrement)
leftToRight += 5;
if (e.ScrollEventType == ScrollEventType.SmallDecrement)
leftToRight -= 5;
Offset2 = new Thickness(leftToRight, 0, 0, 0);
}
public event PropertyChangedEventHandler PropertyChanged;
public void InvokePropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, e);
}
}
public class MyItem
{
public string name { get; set; }
public string price { get; set; }
public MyItem(string n, string p)
{
name = n;
price = p;
}
}
}