locked
silverlight 4.0 drodown keypress RRS feed

  • Question

  • Hi All,

    I am using silverlight 4.0 with MVVM pattern and binding the dropdown with the populated list. When i press a key the items in the dropdown is not getting selected. Guess the feature is not supported directly in SL4.0 dropdown. Is there any workaround to this?

    Thanks in Advance.

    Anbu

    Tuesday, June 7, 2011 12:52 PM

Answers

  • Hi All

    I got a workaround to implement this feature using the Behaviour.

    Xaml

    xmlns:KBS ="clr-namespace:X.ViewModel.Service.Common"

    <ComboBox  Name="cbEngineer" ItemsSource="{Binding Path=EmployeeCollection,Mode=TwoWay}" SelectedValue="{Binding Path=Engineer,Mode=TwoWay}"  SelectedItem="{Binding Engineer,Mode=TwoWay,NotifyOnValidationError=True,ValidatesOnDataErrors=True}" DisplayMemberPath="Value" TabIndex="0" Grid.Column="1" Grid.Row="0" Width="120">
                                            <i:Interaction.Behaviors>
                                                                  <KBS:KeyboardSelectionBehavior/>
                                                        </i:Interaction.Behaviors>

    </ComboBox>

    Behaviour

    namespace X.ViewModel.Service.Common
    {
        /// <summary>
        /// This behavior can be attached to a ListBox or ComboBox to
        /// add keyboard selection
        /// </summary>
        public class KeyboardSelectionBehavior : Behavior<Selector> {

            private bool _bound;

            /// <summary>
            /// Gets or sets the Path used to select the text
            /// </summary>
            public string SelectionMemberPath { get; set; }

            public KeyboardSelectionBehavior() { }

            /// <summary>
            /// Attaches to the specified object: subscribe on KeyDown event
            /// </summary>
            protected override void OnAttached() {
                base.OnAttached();
                this.AssociatedObject.KeyDown += DoKeyDown;

                if (this.AssociatedObject is ComboBox) {
                    ((ComboBox)this.AssociatedObject).DropDownOpened += new EventHandler(KeyboardSelectionBehavior_DropDownOpened);
                }
            }

            void KeyboardSelectionBehavior_DropDownOpened(object sender, EventArgs e) {
                System.Windows.Deployment.Current.Dispatcher.BeginInvoke(this.BindBehaviorToStackPanel);
            }

            void BindBehaviorToStackPanel() {
                var hoster = (((ComboBox)this.AssociatedObject).GetItemsHost() as StackPanel);
                if (_bound == false && hoster != null) {
                    _bound = true;
                    hoster.KeyDown += DoKeyDown;
                }
            }

            void DoKeyDown(object sender, KeyEventArgs e) {
                // Create a list of strings and indexes
                int index = 0;
                IEnumerable<Item> list = null;
                var path = SelectionMemberPath ??
                    this.AssociatedObject.DisplayMemberPath;
                var evaluator = new BindingEvaluator();
                if (path != null) {
                    list = this.AssociatedObject.Items.OfType<object>()
                        .Select(item => {
                            // retrieve the value using the supplied Path
                            var binding = new Binding();
                            binding.Path = new PropertyPath(path);
                            binding.Source = item;

                            BindingOperations.SetBinding(evaluator,
                                BindingEvaluator.TargetProperty, binding);
                            var value = evaluator.Target;

                            return new Item {
                                Index = index++,
                                Text = Convert.ToString(value)
                            };
                        });
                } else {
                    list = this.AssociatedObject.Items.OfType<ListBoxItem>()
                        .Select(item => new Item {
                            Index = index++,
                            Text = Convert.ToString(item.Content)
                        });
                }
                // Sort the list starting at next selectedIndex to the end and
                // then from the beginning
                list = list.OrderBy(item => item.Index <=
                    this.AssociatedObject.SelectedIndex ?
                    item.Index + this.AssociatedObject.Items.Count : item.Index);

                // Find first starting with
                var text = e.Key.ToString();
                var first = list.FirstOrDefault(item => item.Text.StartsWith(text,
                    StringComparison.InvariantCultureIgnoreCase));
                if (first != null) {
                    // found
                    this.AssociatedObject.SelectedIndex = first.Index;
                }
            }

            /// <summary>
            /// Helper class
            /// </summary>
            private class Item {
                public int Index;
                public string Text;
            }

            /// <summary>
            /// Helper class used for property path value retrieval
            /// </summary>
            private class BindingEvaluator : FrameworkElement {

                public static readonly DependencyProperty TargetProperty =
                    DependencyProperty.Register(
                        "Target",
                        typeof(object),
                        typeof(BindingEvaluator), null);

                public object Target {
                    get { return GetValue(TargetProperty); }
                    set { SetValue(TargetProperty, value); }
                }
            }

     

        }
    }

    • Marked as answer by Anbu Varadhan Wednesday, June 8, 2011 10:16 AM
    Tuesday, June 7, 2011 1:27 PM