2009-06-22 3 views
31

Я думаю, что я глуп. Я искал сейчас 15 минут и нашел несколько различных решений для прокрутки на datagrids, но никто не работает для меня.Как autoscroll на WPF datagrid

Я использую WPF с .NET 3.5 и WPF Toolkit DataGrid. Моя сетка обновляется, когда меняется моя наблюдаемая коллекция, отлично работает. Теперь мой DataGrid находится внутри обычной сетки, и полосы прокрутки появляются, если DataGrid становится слишком большим. Также хорошо ...

А теперь приходит 1.000.000 $ Вопрос:

Как получить DataGrid для перехода к последней строке? Там есть:

  • нет AutoScroll недвижимости
  • нет CurrentRowSelected Индекс
  • CurrentCell, но не Collection я не мог использовать для CurrentCell = AllCells.Last

Любые идеи? Я чувствую себя очень глупо, и мне кажется странным, что этот вопрос так тяжел. Что мне не хватает?

ответ

37

;)

 if (mainDataGrid.Items.Count > 0) 
     { 
      var border = VisualTreeHelper.GetChild(mainDataGrid, 0) as Decorator; 
      if (border != null) 
      { 
       var scroll = border.Child as ScrollViewer; 
       if (scroll != null) scroll.ScrollToEnd(); 
      } 
     } 
+1

Большое спасибо, если бы жизнь всегда была такой простой :-) –

+1

Блестящий фрагмент кода, оберните его в исключение ArgumentOutOfRange, и это было бы прекрасно, когда список может быть пустым. – wonea

+0

Куда идет этот код? Какое событие вы используете? Благодаря! – davidbitton

0

Что вам нужно, так это получить ссылку на объект ScrollViewer для вашего DataGrid. Затем вы можете управлять свойством VerticalOffset, чтобы прокручивать его вниз.

Чтобы добавить еще больше вспышек в ваше приложение ... вы можете добавить анимацию сплайна в прокрутку, чтобы все выглядело в соответствии с остальной частью приложения.

+0

Мм, хорошо, если найдено несколько прикрепленных свойств, как ScrollViewer.CanContentScroll = "True", но без любой эффект. Я знаю, RTFM, но эй, у меня все еще есть надежда на строку кода здесь. Я знаю, испорченный brat :-) –

46

Вы должны использовать метод DataGrid

datagrid.ScrollIntoView(itemInRow); 

или

datagrid.ScrollIntoView(itemInRow, column); 

этот способ не дает бездельничать найти свиток зрителя и т.д.

+0

не работает !!! – user1034912

+2

@ user1034912 Если у вас возникли проблемы с этим ответом, вы должны указать, почему он не работает или, может быть, ваши обстоятельства разные, и вам нужно задать другой вопрос. Возможно, что-то изменилось в отношении базовой структуры, так как этот вопрос был дан 6 лет назад.Иногда у меня были проблемы с просмотром прокрутки, поскольку сетка была виртуализирована. Из числа оборотов очевидно, что это работало для довольно многих людей, поэтому, возможно, проблема заключается в том, что ваш код не является ответом. –

6
listbox.Add(foo); 
listbox.SelectedIndex = count - 1; 
listbox.ScrollIntoView(listbox.SelectedItem); 
listbox.SelectedIndex = -1; 
+0

Это отлично подходит для прокрутки выделения до «среднего» экрана (с несколькими логическими проверками и изменениями). –

3

если большие данные datagrid.ScrollIntoView (itemInRow, column); не работает нормально, то мы должны использовать только один ниже:

if (mainDataGrid.Items.Count > 0) 
     { 
      var border = VisualTreeHelper.GetChild(mainDataGrid, 0) as Decorator; 
      if (border != null) 
      { 
       var scroll = border.Child as ScrollViewer; 
       if (scroll != null) scroll.ScrollToEnd(); 
      } 
     } 
0

Если вы используете MVVM шаблона, вы можете иметь сочетание этой статьи с этим другим: http://www.codeproject.com/KB/WPF/AccessControlsInViewModel.aspx.

Идея состоит в том, чтобы использовать прикрепленные свойства для доступа к элементу управления в вашем классе ViewModel. Как только вы это сделаете, вам нужно будет проверить, что datagrid не является нулевым, и он имеет какие-либо элементы.

if ((mainDataGrid != null) && (mainDataGrid.Items.Count > 0)){ 
//Same snippet 
} 
6

Для имеющего AutoScroll последний элемент добавлен:

YourDataGrid.ScrollIntoView(YourDataGrid.Items.GetItemAt(YourDataGrid.Items.Count-1)); 

May Это Помощь :)

+0

'YourDataGrid.Items.Last()' может сделать код немного более чистым. – Oskar

15

Я написал вложенное свойство для сетки автопрокрутке:

using System; 
using System.Collections.Generic; 
using System.Collections.Specialized; 
using System.Windows; 
using System.Windows.Controls; 

public static class DataGridBehavior 
{ 
    public static readonly DependencyProperty AutoscrollProperty = DependencyProperty.RegisterAttached(
     "Autoscroll", typeof(bool), typeof(DataGridBehavior), new PropertyMetadata(default(bool), AutoscrollChangedCallback)); 

    private static readonly Dictionary<DataGrid, NotifyCollectionChangedEventHandler> handlersDict = new Dictionary<DataGrid, NotifyCollectionChangedEventHandler>(); 

    private static void AutoscrollChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) 
    { 
     var dataGrid = dependencyObject as DataGrid; 
     if (dataGrid == null) 
     { 
      throw new InvalidOperationException("Dependency object is not DataGrid."); 
     } 

     if ((bool)args.NewValue) 
     { 
      Subscribe(dataGrid); 
      dataGrid.Unloaded += DataGridOnUnloaded; 
      dataGrid.Loaded += DataGridOnLoaded; 
     } 
     else 
     { 
      Unsubscribe(dataGrid); 
      dataGrid.Unloaded -= DataGridOnUnloaded; 
      dataGrid.Loaded -= DataGridOnLoaded; 
     } 
    } 

    private static void Subscribe(DataGrid dataGrid) 
    { 
     var handler = new NotifyCollectionChangedEventHandler((sender, eventArgs) => ScrollToEnd(dataGrid)); 
     handlersDict.Add(dataGrid, handler); 
     ((INotifyCollectionChanged)dataGrid.Items).CollectionChanged += handler; 
     ScrollToEnd(dataGrid); 
    } 

    private static void Unsubscribe(DataGrid dataGrid) 
    { 
     NotifyCollectionChangedEventHandler handler; 
     handlersDict.TryGetValue(dataGrid, out handler); 
     if (handler == null) 
     { 
      return; 
     } 
     ((INotifyCollectionChanged)dataGrid.Items).CollectionChanged -= handler; 
     handlersDict.Remove(dataGrid); 
    } 

    private static void DataGridOnLoaded(object sender, RoutedEventArgs routedEventArgs) 
    { 
     var dataGrid = (DataGrid)sender; 
     if (GetAutoscroll(dataGrid)) 
     { 
      Subscribe(dataGrid); 
     } 
    } 

    private static void DataGridOnUnloaded(object sender, RoutedEventArgs routedEventArgs) 
    { 
     var dataGrid = (DataGrid)sender; 
     if (GetAutoscroll(dataGrid)) 
     { 
      Unsubscribe(dataGrid); 
     } 
    } 

    private static void ScrollToEnd(DataGrid datagrid) 
    { 
     if (datagrid.Items.Count == 0) 
     { 
      return; 
     } 
     datagrid.ScrollIntoView(datagrid.Items[datagrid.Items.Count - 1]); 
    } 

    public static void SetAutoscroll(DependencyObject element, bool value) 
    { 
     element.SetValue(AutoscrollProperty, value); 
    } 

    public static bool GetAutoscroll(DependencyObject element) 
    { 
     return (bool)element.GetValue(AutoscrollProperty); 
    } 
} 

Использование:

<DataGrid c:DataGridBehavior.Autoscroll="{Binding AutoScroll}"/> 
+2

@ пользователь161953 Я думаю, что потребность посетителя больше объяснения для этого кода ..! – kamesh

+2

Объясните, как это работает или как его использовать? –

+1

Работает как ожидалось, спасибо много! – JoanComasFdz

6

Я знаю, что это поздний ответ, но только для людей, которые ищут вокруг, я нашел ЛУЧШИЙ способ прокрутки до нижней части DataGrid. в DataContextChanged случае поставить это в:

myDataGrid.ScrollIntoView(CollectionView.NewItemPlaceholder); 

Легко да?

Именно поэтому он работает: на каждой сетке данных есть место внизу базы данных DataGrid, где вы можете добавить новый элемент в свой список, к которому он привязан. Это CollectionView.NewItemPlaceholder, и в вашем DataGrid будет только один из них. Поэтому вы можете просто прокрутить до конца.

+2

-1: Datacontext изменяется только при добавлении новой viewmodel в представление, поэтому это будет прокручиваться донизу только в первый раз, а не каждый раз, когда элемент добавляется к источнику данных. –

+0

Хорошо, это не так, но файл данных был просто Например, он работает как шарм в моем приложении ... –

+2

Кроме того, это не в вопросе. –

1

На самом деле ...

У меня была та же проблема, а когда я узнавал о коллекции представлений о делать DataContext в WPF.

Я тоже столкнулся с задачей хлопнуть вместе программу WPF, которую мне нужно программировать, чтобы перемещаться вверх и вниз по DataGrid с помощью кнопок, так как мне нужно было поставить ее на резистивный сенсорный экран ТОЛЬКО для производственных сборщиков \ t my компании, и нет никакой мыши или клавиатуры для их использования.

Но этот пример работал для меня, используя метод ScrollIntoView как уже упоминалось ранее в этой должности:

private void OnMoveUp(object sender, RoutedEventArgs e) 
    { 
     ICollectionView myCollectView = CollectionViewSource.GetDefaultView(Orders); 
     if (myCollectView.CurrentPosition > 0) 
      myCollectView.MoveCurrentToPrevious(); 

     if (myCollectView.CurrentItem != null) 
      theDataGrid.ScrollIntoView(myCollectView.CurrentItem); 
    } 

    private void OnMoveDown(object sender, RoutedEventArgs e) 
    { 
     ICollectionView myCollectView = CollectionViewSource.GetDefaultView(Orders); 
     if (myCollectView.CurrentPosition < Orders.Count) 
      myCollectView.MoveCurrentToNext(); 

     if (myCollectView.CurrentItem !=null) 
      theDataGrid.ScrollIntoView(myCollectView.CurrentItem); 
    } 

Где Заказы является List<T> коллекция

в XAML:

<StackPanel Grid.Row="1" 
     Orientation="Horizontal"> 
      <Button Click="OnMoveUp"> 
       <Image Source="Up.jpg" /> 
      </Button> 
      <Button Click="OnMoveDown"> 
       <Image Source="Down.jpg" /> 
       </Button> 
    </StackPanel> 

    <DataGrid Grid.Row="2" 
       x:Name="theDataGrid" 
       ItemSource="{Binding Orders}" 
       ScrollViewer.CanContentScroll="True" 
       ScrollViewer.VerticalScrollBarVisibility="Auto" Margin="0,0,0,5"> 

    <<code>> 


    </DataGrid> 

Do следовать предыдущий совет и держать DataGrid сам по себе, а не в панели стека. Для определения строки для DataGrid (третья строка в этом случае) я устанавливаю высоту на 150, а полоса прокрутки работает.

0

WPF DataGrid автопрокрутку

Авто скроллинг для тех пор, пока кнопка мыши вниз на кнопки управления.

Часть XAML

<Button x:Name="XBTNPageDown" Height="50" MouseLeftButtonDown="XBTNPageDown_MouseLeftButtonDown" MouseUp="XBTNPageDown_MouseUp">Page Down</Button> 

Кодекс

private bool pagedown = false; 
    private DispatcherTimer pageDownTimer = new DispatcherTimer(); 

    private void XBTNPageDown_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 
    { 
     pagedown = true; 
     pageDownTimer.Interval = new TimeSpan(0, 0, 0, 0, 30); 
     pageDownTimer.Start(); 
     pageDownTimer.Tick += (o, ea) => 
     { 
      if (pagedown) 
      { 
       var sv = XDG.FindVisualChild<ScrollViewer>(); 
       sv.PageDown(); 
       pageDownTimer.Start(); 
      } 
      else 
      { 
       pageDownTimer.Stop(); 
      } 
     }; 
    } 

    private void XBTNPageDown_MouseUp(object sender, MouseButtonEventArgs e) 
    { 
     pagedown = false; 
    } 

Это метод расширения

Поместите его в статическом классе по вашему выбору и добавить ссылку код выше.

public static T FindVisualChild<T>(this DependencyObject depObj) where T : DependencyObject 
    { 
     if (depObj != null) 
     { 
      for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) 
      { 
       DependencyObject child = VisualTreeHelper.GetChild(depObj, i); 
       if (child != null && child is T) 
       { 
        return (T)child; 
       } 

       T childItem = FindVisualChild<T>(child); 
       if (childItem != null) return childItem; 
      } 
     } 
     return null; 
    } 

Примечание: Свойство св может быть перемещено, чтобы избежать повторной работы.

У любого есть способ RX для этого?

2

Я обнаружил, что самый простой способ сделать это - вызвать метод ScrollIntoView из присоединенного события ScrollViewer.ScrollChanged. Это может быть установлено в XAML следующим образом:

<DataGrid 
... 
ScrollViewer.ScrollChanged="control_ScrollChanged"> 

Объекта ScrollChangedEventArgs имеет различные свойства, которые могут быть полезны для вычисления макета и положения прокрутки (экстента, офсет, Viewport). Обратите внимание, что они обычно измеряются в количествах строк/столбцов при использовании настроек виртуализации DataGrid по умолчанию.

Вот пример реализации, который сохраняет нижний элемент в виде добавления новых элементов в DataGrid, если пользователь не перемещает полосу прокрутки для просмотра элементов выше в сетке.

private void control_ScrollChanged(object sender, ScrollChangedEventArgs e) 
    { 
     // If the entire contents fit on the screen, ignore this event 
     if (e.ExtentHeight < e.ViewportHeight) 
      return; 

     // If no items are available to display, ignore this event 
     if (this.Items.Count <= 0) 
      return; 

     // If the ExtentHeight and ViewportHeight haven't changed, ignore this event 
     if (e.ExtentHeightChange == 0.0 && e.ViewportHeightChange == 0.0) 
      return; 

     // If we were close to the bottom when a new item appeared, 
     // scroll the new item into view. We pick a threshold of 5 
     // items since issues were seen when resizing the window with 
     // smaller threshold values. 
     var oldExtentHeight = e.ExtentHeight - e.ExtentHeightChange; 
     var oldVerticalOffset = e.VerticalOffset - e.VerticalChange; 
     var oldViewportHeight = e.ViewportHeight - e.ViewportHeightChange; 
     if (oldVerticalOffset + oldViewportHeight + 5 >= oldExtentHeight) 
      this.ScrollIntoView(this.Items[this.Items.Count - 1]); 
    } 
1

Вот еще одно отличное решение.

public sealed class CustomDataGrid : DataGrid 
{ 
    protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue) 
    { 
     base.OnItemsSourceChanged(oldValue, newValue); 
    } 
    protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) 
    { 
     base.OnItemsChanged(e); 
     if (this.Items.Count > 0) this.ScrollIntoView(this.Items[this.Items.Count - 1]); 
    } 
} 
0

Если вы использовали DataView для datagrid.datacontext, вы можете использовать это:

private void dgvRecords_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) 
{ 
    var dv = dgvRecords.DataContext as DataView; 
    if (dv.Count > 0) 
    { 
     var drv = dv[dv.Count - 1] as DataRowView; 
     dgvRecords.ScrollIntoView(drv); 
    } 
} 
Смежные вопросы