我想为我的DataGrid实现自定义滚动行为。
我拥有的是带有两列的DataGrid。第一列中的元素具有特定的高度。但是,第二列中的元素内部有一个文本编辑器,因此它们的长度可变。我的问题是,如果文本编辑器中的文本太长,则性能会很差。所以我想设置文本编辑器的最大高度。这将导致该控件具有两个垂直滚动条,一个滚动条用于数据网格,一个滚动条用于文本编辑器。
我想要的只是垂直滚动条。一个。以下描述是为了简化。当数据网格中的某一行高于数据网格的ActualHeight并且该行的上边界到达数据网格的上边界时,外部滚动应停止,并且文本编辑器应开始滚动。当该行的下边框到达数据网格的下边框时,文本编辑器应停止滚动(因为它到达了底部),并且数据网格应继续滚动。
这样可能吗?
到目前为止,我所做的是我在文本编辑器上使用了PreviewMouseWheel-Event来检查我是否在文本编辑器中,并从那里滚动文本编辑器。然后,在数据网格scrollviewer的MouseWheel-Event中,我检查了是否已经滚动了文本编辑器,如果已经滚动,则抑制了数据网格的滚动。这有两个问题:
在文本编辑器中使用鼠标滚轮时,数据网格将立即停止滚动,但是,只有在数据网格行已到达数据网格的上边界时,才应停止滚动。
在文本编辑器中滚动时,滚动条的拇指不会移动,并且拇指的大小并不代表所有文本编辑器的总长度。
编辑:
XAML:
<ScrollViewer x:Name="ScrollViewer">
<DataGrid ItemsSource="{Binding GridItems}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Name" Width="128">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="{x:Type scrollViewerTest:GridItem}">
<Label Content="{Binding Name}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Code" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="{x:Type scrollViewerTest:GridItem}">
<TextBox Text="{Binding Code}" TextWrapping="NoWrap"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Hidden"
MaxHeight="600"
PreviewMouseWheel="TextBox_OnPreviewMouseWheel"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</ScrollViewer>
后面的代码:
private bool _scrollInside;
public MainWindow()
{
InitializeComponent();
var vm = new MainWindowViewModel();
DataContext = vm;
ScrollViewer.AddHandler(MouseWheelEvent, (MouseWheelEventHandler)ScrollViewer_OnMouseWheel, true);
}
private void TextBox_OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
var tb = (TextBox)sender;
var offset = tb.VerticalOffset;
var extentHeight = tb.ExtentHeight;
var actualHeight = tb.ActualHeight;
if ((offset < extentHeight - actualHeight && e.Delta < 0) || (offset > 0 && e.Delta > 0))
{
_scrollInside = true;
tb.ScrollToVerticalOffset(offset - e.Delta);
}
else
{
_scrollInside = false;
}
}
private void ScrollViewer_OnMouseWheel(object sender, MouseWheelEventArgs e)
{
if (!_scrollInside)
{
var scv = (ScrollViewer)sender;
scv.ScrollToVerticalOffset(scv.VerticalOffset - e.Delta);
}
}