【问题标题】:Tab Navigation on Virtualized Items Panel虚拟化项目面板上的选项卡导航
【发布时间】:2012-12-28 17:33:24
【问题描述】:

如何在虚拟化项目上设置选项卡导航?例如;

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

如果我在 Scrollviewer 本身或 Listbox 父级等上设置 TabNavigation=Once 或 Cycle,它只会在视口中可用的项目中进行选项卡,因为其他项目尚未生成。在通过项目对象切换时,是否有人可以分享一个技巧,它将允许 Tab 继续到下一个尚未虚拟化的项目,同时将其带到视口中查看并通过控件提供直观的选项卡?

【问题讨论】:

    标签: c# xaml user-interface silverlight


    【解决方案1】:

    所以基本上出现的(多亏了另一位优秀开发人员的额外眼睛和帮助)是继续渲染其他项目,但同时通过自定义行为从 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);
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-31
      • 2010-12-22
      • 1970-01-01
      • 2020-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多