silverlight 4.0 drodown keypress
-
Tuesday, June 07, 2011 12:52 PM
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
All Replies
-
Tuesday, June 07, 2011 1:27 PM
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 08, 2011 10:16 AM