Issue with WPF custom control (Multi-Select Combobox)
On code project I found the following: http://www.codeproject.com/KB/WPF/MultiComboBox.aspx
I have integrated the following into a sample application and it seems to be working well. The only issue I have right now is that if I type in the control I would like to be taken to the items that start with those letters the same way a normal combobox or listbox functions.
I have tried adding KeyboardNavigation.DirectionalNavigation="Contained"
and TextSearch.TextPath="City"
as well as IsTextSearchEnabled="True"
.
None of these seem to be helping. Any thoughts on how to implement text search f开发者_运维问答unctionality using this control?
The author confirm that the control is build to mimic a ComboBox
, but it isn't: you should implement your own custom logic to the automatic selection.
EDIT (a.k.a. even better than a finger in the eye)
With reference to the original code:
1) In the Generic.xaml search the MultiSelectComboBoxReadOnlyTemplate
, then look for the ScrollViewer
tag: name it as "PART_Scroller".
2) Open the MultiComboBox.cs module then find the OnKeyDown function. Modify as follows:
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == System.Windows.Input.Key.Enter)
{
IsDropDownOpen = !IsDropDownOpen;
e.Handled = true;
}
else if (IsDropDownOpen)
{
if (e.Key>=Key.A && e.Key<= Key.Z) //make it better!
{
var ch = (char)((int)(e.Key-Key.A) + 0x41); //awful!!!
for (int i = 0, count = this.Items.Count; i < count; i++)
{
var text = string.Format("{0}", this.Items[i]);
if (text.StartsWith(new string(ch, 1)))
{
ListBoxItem listBoxItem = (ListBoxItem)this.ItemContainerGenerator.ContainerFromIndex(i);
var scroller = (ScrollViewer)this.GetTemplateChild("PART_Scroller"); //move out in OnApplyTemplate
scroller.ScrollToVerticalOffset(i);
this.ScrollIntoView(listBoxItem);
break;
}
}
}
}
else
base.OnKeyDown(e);
}
You should make the key analysis better than the mine, but the road is pretty sunny. NOTE: I didn't tried so much to test, I guess should be OK, at least to give you an help. Cheers Mario
EDIT2: here is how to keeping track of the key pressed within one second. 1) Modify as follows:
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == System.Windows.Input.Key.Enter)
{
IsDropDownOpen = !IsDropDownOpen;
e.Handled = true;
}
else if (IsDropDownOpen)
{
if (e.Key>=Key.A && e.Key<= Key.Z) //make it better!
{
var ch = (char)((int)(e.Key-Key.A) + 0x41); //awful!!!
this._textSought += ch;
this._timer.Stop();
this._timer.Start();
for (int i = 0, count = this.Items.Count; i < count; i++)
{
var text = string.Format("{0}", this.Items[i]);
if (text.StartsWith(this._textSought, StringComparison.InvariantCultureIgnoreCase))
{
ListBoxItem listBoxItem = (ListBoxItem)this.ItemContainerGenerator.ContainerFromIndex(i);
var scroller = (ScrollViewer)this.GetTemplateChild("PART_Scroller"); //move out in OnApplyTemplate
scroller.ScrollToVerticalOffset(i);
this.ScrollIntoView(listBoxItem);
break;
}
}
}
}
else
base.OnKeyDown(e);
}
2) add the following to the same class:
public MultiComboBox()
{
this.Loaded += new RoutedEventHandler(MultiComboBox_Loaded);
this.Unloaded += new RoutedEventHandler(MultiComboBox_Unloaded);
}
void MultiComboBox_Loaded(object sender, RoutedEventArgs e)
{
this._timer = new DispatcherTimer();
this._timer.Interval = TimeSpan.FromMilliseconds(1000);
this._timer.Tick += new EventHandler(_timer_Tick);
}
void MultiComboBox_Unloaded(object sender, RoutedEventArgs e)
{
if (this._timer != null)
{
this._timer.Stop();
this._timer = null;
}
}
void _timer_Tick(object sender, EventArgs e)
{
this._timer.Stop();
this._textSought = string.Empty;
}
private DispatcherTimer _timer;
private string _textSought = string.Empty;
Hope it helps. Cheers Mario
精彩评论