valor obtener llenar data como celda wpf datagrid scroll wpfdatagrid

llenar - obtener valor de celda datagrid wpf



WPF DataGrid: ¿cómo detengo el desplazamiento automático cuando se hace clic en una celda? (9)

Como el Dr.WPF ha respondido una pregunta similar here el RequestBringIntoView debe manejarse en ItemsPanel.

Problema:
Si mi DataGrid no está completamente visible (se muestran las barras de desplazamiento horizontal y vertical) y hago clic en una de mis celdas que está parcialmente visible, la cuadrícula se desplaza automáticamente para ver esa celda. No quiero que esto suceda . He intentado jugar con RequestBringIntoView , así:

private void DataGrid_RequestBringIntoView(object sender, RequestBringIntoViewEventArgs e) { e.Handled = true; }

Pero eso no hace nada.

Cosas que he probado:

  • Mis celdas son UserControls personalizados; Intenté colocar un controlador de eventos para RequestBringIntoView en todos los UserControls que componen mis celdas, e intenté manejar el evento, pensando que tal vez no estaba haciendo lo suficiente con solo manejar RequestBringIntoView en el DataGrid . Esto no funcionó.
  • Alojó el DataGrid dentro de un ScrollViewer y manejó el evento RequestBringIntoView del ScrollViewer . Esto realmente funciona, y detiene el comportamiento de desplazamiento automático, pero en mi caso el alojamiento de un DataGrid dentro de un ScrollViewer no es del todo deseable, por lo que debo encontrar una solución diferente.

No estoy seguro de cómo detener este comportamiento, ¿alguna idea?


Defina un EventSetter en el DataGrid.RowStyle para llamar a un controlador que impide que la fila se EventSetter :

XAML

<DataGrid> <DataGrid.RowStyle> <Style TargetType="{x:Type DataGridRow}"> <EventSetter Event="Control.RequestBringIntoView" Handler="DataGrid_Documents_RequestBringIntoView" /> </Style> </DataGrid.RowStyle> </DataGrid>

Entrenador de animales

private void DataGrid_Documents_RequestBringIntoView(object sender, RequestBringIntoViewEventArgs e) { e.Handled = true; }


Esto es lo que funcionó para mí (después de probar todas las "respuestas" menos complejas hasta la fecha):

<DataGrid Grid.Column="0" Grid.Row="1" Name="ListItemContainerDataGrid" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.CanContentScroll="False" And.Others ItemsSource="{Binding Path=ListItemModels}" > </DataGrid>

ScrollViewer.CanContentScroll = "False" parece increíblemente contra intuitivo ...


La forma l33t:

static App() { EventManager.RegisterClassHandler(typeof(ScrollContentPresenter), FrameworkElement.RequestBringIntoViewEvent, new RoutedEventHandler(OnRequestBringIntoView)); } private static void OnRequestBringIntoView(object sender, RoutedEventArgs e) { e.Handled = true; }

Tenga en cuenta que esto podría interferir con, por ejemplo, controles de terceros.


No estoy seguro de que esto funcione, pero aquí hay una idea basada en algunas investigaciones realizadas en el código fuente de DataGrid usando Reflector:

1 / crear una clase que hereda DataGridCellsPanel. Este es el Panel utilizado internamente por el DataGrid para organizar las celdas.

2 / anular el método BringIndexIntoView por un método vacío (sin llamar al método base)

3 / establece la propiedad ItemsPanelTemplate en tu XAML:

<tk:DataGrid> <tk:DataGrid.ItemsPanel> <ItemsPanelTemplate> <local:DataGridCellsPanelNoAutoScroll /> </ItemsPanelTemplate> </tk:DataGrid.ItemsPanel> </tk:DataGrid>

Parece que cuando se produce un evento MouseDown, en algún momento se llama al método BringIndexIntoView del panel para hacer el desplazamiento automático. Reemplazarlo con un no-op podría hacer el truco.

No tuve tiempo de probar esta solución, háganos saber si está funcionando.


Puede acceder al ScrollViewer interno de DataGrid modificando la plantilla. Aunque normalmente no pondría un controlador de eventos al código detrás de una plantilla, si declara la plantilla en línea, puede tratar el controlador de eventos de la misma manera que lo hace cuando lo adjunta al DataGrid. Esta es la plantilla predeterminada generada desde Blend, que incluye un controlador agregado en el ScrollViewer para el evento 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>


Tomé más tiempo para ver este problema, ya que mi primera solución no estaba funcionando.

Sin embargo, la respuesta de Juan es casi la buena. El truco es capturar el evento RequestBringIntoView ANTES de que llegue al ScrollViewer para marcar que se ha manejado.

Si no tiene que refinar toda la plantilla, puede usar el siguiente código:

var scp = TreeHelper.FindVisualChild<ScrollContentPresenter>(this.datagrid); scp.RequestBringIntoView += (s, e) => e.Handled = true;

Usamos el ScrollContentPresenter porque está justo debajo del ScrollViewer en el árbol visual.

Espero que esto ayude !


Tuve el mismo problema que Rumit, pero encontré una solución / hack.

Pensé que si podía encontrar una manera de diferenciar entre los clics del mouse y las teclas de flecha, entonces podría configurar e.Handled en consecuencia.

Después de algunos experimentos, descubrí que e.OriginalSource cambió según el mouse o la tecla de flecha. Para hacer clic con el mouse, se llama una vez al controlador de RequestBringIntoView y e.OriginalSource era de tipo DataGridCell. Para una tecla de flecha, el controlador se llama dos veces y e.OriginalSource es de los tipos DataGridRow y luego DataGridCell.

El código para mi manejador es:

e.Handled = (e.OriginalSource is DataGridCell);

Esto parece un poco pirateado, pero funciona muy bien para mí.


Tuve el mismo problema y la respuesta de Jan me ayudó. Lo único que faltaba era que ScrollContentPresenter se encontraría solo después de que ocurriera el evento Loaded. Creé una clase de DataGrid extendida heredada de DataGrid con propiedad adicional AutoScroll para controlar si quiero que la cuadrícula se desplace automáticamente o no.

Aquí está la clase:

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

Y así es como lo usas:

<local:ExtendedDataGrid AutoScroll="False"> <!-- your grid definition --> </local:ExtendedDataGrid>