none
WPF Datagrid. View.MoveCurrentToNext() and datagrid arrow keys are conflicting. RRS feed

  • Question

  • Hi,

    I have a very simple WPF datagrid. I want to navigate the datagrid using buttons (first,last,previous,next).

    The datagrid is bound to an ICollectionView. It works perfectly.

    But the problem occurs, when i do the following:

    1) Click a row in the datagrid, so it gets selected. Say row 2.

    2) Click the Next-button 3 times. The selected row in the datagrid moves, just as expected, to row 5. But the black border stays on row 2.

    3) Now press the ArrowDown once. The selected row is now row 3 - and not row 6, as i would expect.

    Here is my (simplified) code:

    <Grid>
            <DataGrid Name="dg1" 
                      HorizontalAlignment="Left" 
                      Height="242" 
                      Margin="65,17,0,0" 
                      VerticalAlignment="Top" 
                      Width="225" 
                      AutoGenerateColumns="True" 
                      CanUserAddRows="False" 
                      CanUserDeleteRows="False"
                      SelectionMode="Single"
                      SelectionUnit="FullRow"
                      HeadersVisibility="Column"
                      IsSynchronizedWithCurrentItem="True" 
                      >
            </DataGrid>
            <Button Content="Next" HorizontalAlignment="Left" Margin="327,111,0,0" VerticalAlignment="Top" Width="75" Focusable="False" Click="Button_Click_2"/>
        </Grid>

    public partial class MainWindow : Window
        {
            public class person
            {
                public string Name { get; set; }
                public string Name2 { get; set; }
            }
    
            public ICollectionView view;
    
    
            public MainWindow()
            {
                InitializeComponent();
    
                for (int i = 0; i < 200; i++)
                {
                    person p = new person();
                    p.Name = "Bla bla bla "+i.ToString();
                    p.Name2 = p.Name;
                    liste.Add(p);
                }
    
    
                view = CollectionViewSource.GetDefaultView(liste);
                dg1.ItemsSource = view;
            }
          
    
            public ObservableCollection<person> liste = new ObservableCollection<person>();
            
            private void Button_Click_2(object sender, RoutedEventArgs e)
            {
                view.MoveCurrentToNext();
                dg1.ScrollIntoView(view.CurrentItem);
            }
                    
    
        }

    My solution right now, is to handle the keys in the datagrid:

    private void Dg1_PreviewKeyDown(object sender, KeyEventArgs e)
            {
                if (e.Key == Key.Up)
                {
                    view.MoveCurrentToPrevious();
                    dg1.ScrollIntoView(view.CurrentItem);
                    e.Handled = true;
                    return;
                }
    
                if (e.Key == Key.Down)
                {
                    view.MoveCurrentToNext();
                    dg1.ScrollIntoView(view.CurrentItem);
                    e.Handled = true;
                    return;
                }
    
            }

    But there must be a better solution.

    Monday, November 18, 2019 4:16 PM

Answers

  • In order to move the “black border” too, try adding these lines to Button_Click_2:

    var row = (DataGridRow)dg1.ItemContainerGenerator.ContainerFromItem( view.CurrentItem );
    row.MoveFocus( new TraversalRequest( FocusNavigationDirection.First ));

    • Marked as answer by olehaahr Tuesday, November 19, 2019 8:48 AM
    Monday, November 18, 2019 6:36 PM

All replies

  • In order to move the “black border” too, try adding these lines to Button_Click_2:

    var row = (DataGridRow)dg1.ItemContainerGenerator.ContainerFromItem( view.CurrentItem );
    row.MoveFocus( new TraversalRequest( FocusNavigationDirection.First ));

    • Marked as answer by olehaahr Tuesday, November 19, 2019 8:48 AM
    Monday, November 18, 2019 6:36 PM
  • Hi,
    with MVVM you can use this code:

    XAML:

    <Window x:Class="WpfApp1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp1"
            xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
      <Window.DataContext>
        <local:ViewModel/>
      </Window.DataContext>
      <Grid>
        <DataGrid ItemsSource="{Binding View}" 
                  HorizontalAlignment="Left" 
                  Height="242" 
                  Margin="65,17,0,0" 
                  VerticalAlignment="Top" 
                  Width="225" 
                  AutoGenerateColumns="True" 
                  CanUserAddRows="False" 
                  CanUserDeleteRows="False"
                  SelectionMode="Single"
                  SelectionUnit="FullRow"
                  HeadersVisibility="Column"
                  IsSynchronizedWithCurrentItem="True">
          <i:Interaction.Behaviors>
            <local:DataGridBehavior/>
          </i:Interaction.Behaviors>
        </DataGrid>
        <Button Content="Next" 
                HorizontalAlignment="Left" 
                Margin="327,111,0,0" 
                VerticalAlignment="Top" 
                Width="75" 
                Focusable="False"
                Command="{Binding Cmd}"/>
      </Grid>
    </Window>

    and code (System.Windows.Interactivity.WPF from Nuget, and RelayCommand)

    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Input;
    using System.Windows.Interactivity;
    
    namespace WpfApp1
    {
      class ViewModel
      {
        public ViewModel()
        {
          for (int i = 0; i < 200; i++)
          {
            person p = new person();
            p.Name = "Bla bla bla " + i.ToString();
            p.Name2 = p.Name;
            liste.Add(p);
          }
          cvs.Source = liste;
        }
        CollectionViewSource cvs = new CollectionViewSource();
        public ICollectionView View { get => cvs.View; }
        public ObservableCollection<person> liste = new ObservableCollection<person>();
        public ICommand Cmd { get => new RelayCommand((state) => cvs.View.MoveCurrentToNext()); }
      }
      public class person
      {
        public string Name { get; set; }
        public string Name2 { get; set; }
      }
    
      class DataGridBehavior : Behavior<DataGrid>
      {
        protected override void OnAttached()
        {
          AssociatedObject.SelectionChanged += AssociatedObject_SelectionChanged;
          AssociatedObject.PreviewKeyDown += AssociatedObject_PreviewKeyDown;
        }
        protected override void OnDetaching()
        {
          AssociatedObject.SelectionChanged -= AssociatedObject_SelectionChanged;
          AssociatedObject.PreviewKeyDown -= AssociatedObject_PreviewKeyDown;
        }
        private void AssociatedObject_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
          var curItem = (AssociatedObject.ItemsSource as ICollectionView).CurrentItem;
          if (curItem != null) AssociatedObject.ScrollIntoView(curItem);
          var row = (DataGridRow)AssociatedObject.ItemContainerGenerator.ContainerFromItem(curItem);
          row.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
        }
        private void AssociatedObject_PreviewKeyDown(object sender, KeyEventArgs e)
        {
          var view = AssociatedObject.ItemsSource as ICollectionView;
          if (e.Key == Key.Up) view.MoveCurrentToPrevious();
          if (e.Key == Key.Down) view.MoveCurrentToNext();
        }
      }
    }


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks


    • Edited by Peter Fleischer Wednesday, November 20, 2019 2:42 PM correct code
    Monday, November 18, 2019 6:56 PM
  • Thank you so much.

    This was exactly what i was looking for. It works perfectly.

    Tuesday, November 19, 2019 8:48 AM