Rob*_*Rob 26 wpf datagrid scroll wpfdatagrid
问题:
如果我DataGrid不完全可见(显示水平和垂直滚动条)并且我单击其中一个部分可见的单元格,则网格会自动滚动以将该单元格显示在视图中.我不希望这种情况发生.我试过玩RequestBringIntoView,像这样:
private void DataGrid_RequestBringIntoView(object sender, RequestBringIntoViewEventArgs e)
{
e.Handled = true;
}
Run Code Online (Sandbox Code Playgroud)
但这没有任何作用.
我试过的事情:
UserControls; 我试图把一个事件处理程序RequestBringIntoView上的所有UserControls使我的细胞,并试图处理事件,想,也许我是不是只是处理做得不够RequestBringIntoView的DataGrid本身.这没用.DataGrid一个内部的ScrollViewer,而办理ScrollViewer的RequestBringIntoView事件.这实际上是有效的,并且停止了自动滚动行为,但在我的情况下托管一个DataGrid内部ScrollViewer是完全不可取的,所以我需要提出一个不同的解决方案.我不知道如何阻止这种行为,任何想法?
小智 28
限定EventSetter在DataGrid.RowStyle调用处理程序,其防止从排被带入视图:
XAML
<DataGrid>
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<EventSetter Event="Control.RequestBringIntoView" Handler="DataGrid_Documents_RequestBringIntoView" />
</Style>
</DataGrid.RowStyle>
</DataGrid>
Run Code Online (Sandbox Code Playgroud)
处理器
private void DataGrid_Documents_RequestBringIntoView(object sender, RequestBringIntoViewEventArgs e)
{
e.Handled = true;
}
Run Code Online (Sandbox Code Playgroud)
由于我的第一个解决方案无效,我花了更多时间来研究这个问题.
然而约翰的答案几乎是好的.诀窍是在它到达ScrollViewer之前捕获RequestBringIntoView事件,以便标记它已被处理.
如果您不必优化整个模板,则可以使用以下代码:
var scp = TreeHelper.FindVisualChild<ScrollContentPresenter>(this.datagrid);
scp.RequestBringIntoView += (s, e) => e.Handled = true;
Run Code Online (Sandbox Code Playgroud)
我们使用ScrollContentPresenter,因为它位于可视化树中的ScrollViewer下方.
希望这可以帮助 !
您可以通过修改模板来访问DataGrid的内部ScrollViewer.虽然通常您不会将事件处理程序放在模板后面的代码中,但如果您将模板内联声明,则可以将事件处理程序与将其附加到DataGrid本身时的方式相同.这是从Blend生成的默认模板,包括ScrollViewer上为RequestBringIntoView事件添加的处理程序:
<ControlTemplate TargetType="{x:Type Controls:DataGrid}">
<Border SnapsToDevicePixels="True" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
<ScrollViewer x:Name="DG_ScrollViewer" Focusable="False" RequestBringIntoView="DG_ScrollViewer_RequestBringIntoView">
<ScrollViewer.Template>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button Width="{Binding CellsPanelHorizontalOffset, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type Controls:DataGrid}}}" Focusable="False">
<Button.Visibility>
<Binding Path="HeadersVisibility" RelativeSource="{RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type Controls:DataGrid}}">
<Binding.ConverterParameter>
<Controls:DataGridHeadersVisibility>All</Controls:DataGridHeadersVisibility>
</Binding.ConverterParameter>
</Binding>
</Button.Visibility>
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle x:Name="Border" Fill="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" SnapsToDevicePixels="True"/>
<Polygon x:Name="Arrow" Fill="Black" Stretch="Uniform" HorizontalAlignment="Right" Margin="8,8,3,3" VerticalAlignment="Bottom" Opacity="0.15" Points="0,10 10,10 10,0"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Stroke" TargetName="Border" Value="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Fill" TargetName="Border" Value="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Visibility" TargetName="Arrow" Value="Collapsed"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
<Button.Command>
<RoutedCommand/>
</Button.Command>
</Button>
<Custom:DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter" Grid.Column="1">
<Custom:DataGridColumnHeadersPresenter.Visibility>
<Binding Path="HeadersVisibility" RelativeSource="{RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type Controls:DataGrid}}">
<Binding.ConverterParameter>
<Controls:DataGridHeadersVisibility>Column</Controls:DataGridHeadersVisibility>
</Binding.ConverterParameter>
</Binding>
</Custom:DataGridColumnHeadersPresenter.Visibility>
</Custom:DataGridColumnHeadersPresenter>
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" Grid.ColumnSpan="2" Grid.Row="1" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" ContentTemplate="{TemplateBinding ContentTemplate}" CanContentScroll="{TemplateBinding CanContentScroll}" CanHorizontallyScroll="False" CanVerticallyScroll="False"/>
<ScrollBar x:Name="PART_VerticalScrollBar" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Grid.Column="2" Grid.Row="1" Maximum="{TemplateBinding ScrollableHeight}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" Orientation="Vertical" ViewportSize="{TemplateBinding ViewportHeight}"/>
<Grid Grid.Column="1" Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type Controls:DataGrid}}}"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ScrollBar x:Name="PART_HorizontalScrollBar" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Grid.Column="1" Maximum="{TemplateBinding ScrollableWidth}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" Orientation="Horizontal" ViewportSize="{TemplateBinding ViewportWidth}"/>
</Grid>
</Grid>
</ControlTemplate>
</ScrollViewer.Template>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>
</Border>
Run Code Online (Sandbox Code Playgroud)
小智 6
我遇到了与 Rumit 相同的问题,但找到了解决方案/hack。
我想如果我能找到一种方法来区分鼠标点击和箭头键,那么我可以相应地设置 e.Handled。
经过一些实验,我发现 e.OriginalSource 随鼠标或箭头键而变化。对于鼠标单击,RequestBringIntoView 的处理程序将被调用一次,并且 e.OriginalSource 的类型为 DataGridCell。对于箭头键,处理程序被调用两次,e.OriginalSource 是 DataGridRow 类型,然后是 DataGridCell。
我的处理程序的代码是:
e.Handled = (e.OriginalSource is DataGridCell);
Run Code Online (Sandbox Code Playgroud)
这看起来有点像黑客,但对我来说很好用。
我遇到了同样的问题,Jan的回答帮助了我。唯一缺少的是,只有在发生Loaded事件之后才能找到ScrollContentPresenter。我创建了一个继承自DataGrid的扩展DataGrid类,该类具有其他属性AutoScroll来控制是否希望网格自动滚动。
这是课程:
using System.Windows;
using System.Windows.Controls;
using Microsoft.Windows.Controls;
namespace Bartosz.Wojtowicz.Wpf
{
public class ExtendedDataGrid : DataGrid
{
public bool AutoScroll { get; set; }
public ExtendedDataGrid()
{
AutoScroll = true;
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs eventArgs)
{
if (!AutoScroll)
{
ScrollContentPresenter scp = DataGridHelper.GetVisualChild<ScrollContentPresenter>(this);
if (scp != null) scp.RequestBringIntoView += OnRequestBringIntoView;
}
}
private static void OnRequestBringIntoView(object sender, RequestBringIntoViewEventArgs e)
{
e.Handled = true;
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用方法如下:
<local:ExtendedDataGrid AutoScroll="False">
<!-- your grid definition -->
</local:ExtendedDataGrid>
Run Code Online (Sandbox Code Playgroud)