虚拟化项面板的选项卡导航



如何设置虚拟项的选项卡导航?

为例;
        <ListBox x:Name="Items">        
            <ListBox.Template>
                <ControlTemplate>
                    <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
                        <ItemsPresenter/>           
                    </ScrollViewer>         
                </ControlTemplate>      
            </ListBox.Template>
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel VirtualizingStackPanel.VirtualizationMode="Recycling"/>         
                </ItemsPanelTemplate>       
            </ListBox.ItemsPanel>
            <ListBox.ItemTemplate>
                <DataTemplate>
             <Button />
                </DataTemplate>         
            </ListBox.ItemTemplate>           
        </ListBox>

如果我设置TabNavigation=Once或Cycle在Scrollviewer本身,或Listbox的父等,它只能通过选项卡在视口中可用的项目,因为其他还没有生成。有没有人可以分享一个技巧,当在项目对象中使用Tab键时,它允许Tab键继续到下一个尚未虚拟化的项目,同时在视口中将其显示出来,并通过控件提供直观的选项卡?

所以基本上(感谢额外的眼睛和另一个优秀的开发人员的帮助)是继续渲染其他项目,但同时保持虚拟从onload自定义行为,同时暴露依赖于连续滚动,并将当前项目带入视图中;

namespace The.Namespace
{
    using System;
    using System.Linq;
    using System.Windows;   
    using System.Windows.Controls;
    using System.Windows.Input;
    /// <summary>
    /// Scroll selected item into view.
    /// </summary>
    public class ListBoxFocusBehavior : FocusBehavior<ListBox>
    {
        public static readonly DependencyProperty IsContinuousProperty = DependencyProperty.Register("IsContinuous",
                                                                         typeof(bool),
                                                                         typeof(ListBoxFocusBehavior),
                                                                         new PropertyMetadata(
                                                                             false,
                                                                             (d, e) => ((ListBoxFocusBehavior)d).IsContinuousScroll = (bool)e.NewValue));
        /// <summary>
        /// Gets or sets a value indicating whether this instance is continuous.
        /// </summary>
        /// <value>
        ///      <c>true</c> if this instance is continuous; otherwise, <c>false</c>.
        /// </value>
        public bool IsContinuous
        {
            get { return (bool)GetValue(IsContinuousProperty); }
            set { SetValue(IsContinuousProperty, value); }
        }
        /// <summary>
        /// Called after the behavior is attached to an AssociatedObject.
        /// </summary>
        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.SelectionChanged += SelectionChanged;
            AssociatedObject.KeyDown += KeyDown;
        }
        /// <summary>
        /// Keys down.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.KeyEventArgs"/> instance containing the event data.</param>
        private void KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = false;
            if (e.Key == Key.Tab && Keyboard.Modifiers == ModifierKeys.None)
            {
               //forward tab ...
                var idx = AssociatedObject.Items.IndexOf(AssociatedObject.SelectedItem);
                if (idx < AssociatedObject.Items.Count-1)
                {
                    AssociatedObject.SelectedItem = AssociatedObject.Items[idx + 1];
                    e.Handled = true;
                }
            }
            if (e.Key == Key.Tab && (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift)
            {
                //back tab.
                var idx = AssociatedObject.Items.IndexOf(AssociatedObject.SelectedItem);
                if (idx > 0)
                {
                    AssociatedObject.SelectedItem = AssociatedObject.Items[idx - 1];
                    e.Handled = true;
                }
            }
        }

        /// <summary>
        /// Called when the behavior is being detached from its AssociatedObject, but before it has actually occurred.
        /// </summary>
        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.SelectionChanged -= SelectionChanged;
            AssociatedObject.KeyDown -= KeyDown;
        }
        /// <summary>
        /// Gots the focus.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void GotFocus(object sender, RoutedEventArgs e)
        {
            if (AssociatedObject.SelectedItem == null && AssociatedObject.Items.Any())
            {
                AssociatedObject.SelectedItem = AssociatedObject.Items.First();
            }
        }
        /// <summary>
        /// Selections the changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Controls.SelectionChangedEventArgs"/> instance containing the event data.</param>
        private void SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (AssociatedObject.SelectedItem == null) return;
            AssociatedObject.UpdateLayout();
            //have to, otherwise the listbox will probably not focus.
            Action setFocus = () =>
                                  {
                                      AssociatedObject.UpdateLayout();                                     
                                      AssociatedObject.ScrollIntoView(AssociatedObject.SelectedItem);
                                      //ensure that if the container did not exist yet (virtualized), it gets created.
                                      AssociatedObject.UpdateLayout();   
                                      var container =
                                         AssociatedObject.ItemContainerGenerator.ContainerFromItem(
                                             AssociatedObject.SelectedItem) as Control;
                                      if (container != null)
                                      {
                                          container.Focus();
                                      }
                                  };
            AssociatedObject.Dispatcher.BeginInvoke(setFocus);
        }
    }
}

相关内容

  • 没有找到相关文章

最新更新