自定义滚动行为

时间:2018-06-26 11:51:43

标签: c# wpf datagrid customization

我想为我的DataGrid实现自定义滚动行为。

我拥有的是带有两列的DataGrid。第一列中的元素具有特定的高度。但是,第二列中的元素内部有一个文本编辑器,因此它们的长度可变。我的问题是,如果文本编辑器中的文本太长,则性能会很差。所以我想设置文本编辑器的最大高度。这将导致该控件具有两个垂直滚动条,一个滚动条用于数据网格,一个滚动条用于文本编辑器。

我想要的只是垂直滚动条。一个。以下描述是为了简化。当数据网格中的某一行高于数据网格的ActualHeight并且该行的上边界到达数据网格的上边界时,外部滚动应停止,并且文本编辑器应开始滚动。当该行的下边框到达数据网格的下边框时,文本编辑器应停止滚动(因为它到达了底部),并且数据网格应继续滚动。

这样可能吗?

到目前为止,我所做的是我在文本编辑器上使用了PreviewMouseWheel-Event来检查我是否在文本编辑器中,并从那里滚动文本编辑器。然后,在数据网格scrollviewer的MouseWheel-Event中,我检查了是否已经滚动了文本编辑器,如果已经滚动,则抑制了数据网格的滚动。这有两个问题:

  1. 在文本编辑器中使用鼠标滚轮时,数据网格将立即停止滚动,但是,只有在数据网格行已到达数据网格的上边界时,才应停止滚动。

  2. 在文本编辑器中滚动时,滚动条的拇指不会移动,并且拇指的大小并不代表所有文本编辑器的总长度。

编辑:

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

0 个答案:

没有答案