У меня есть класс, который расширяет Combobox
. В этом классе я могу ТОЛЬКО отключить togglebutton
. Я по-прежнему хочу, чтобы пользователи нажимали на combobox
и вводили что-то для фильтрации его содержимого.
Если вы знаете какой-либо другой способ уничтожения togglebutton
, пожалуйста, дайте мне знать (если это не связано с воссозданием шаблона - я попытался и потерпел неудачу, и сгенерированный код шаблона combobox
к большому, чтобы получить дамп в стеке, поэтому я не могу решить его таким образом.)
Вначале я хотел иметь возможность переключать togglebutton
(если в фильтре осталось менее 10 элементов, разрешитьпользователь нажимает togglebutton
, чтобы показать список элементов, если их больше, кнопка исчезнет). На этом этапе я возьму любое решение, которое сжимает, скрывает, перемещает, преднамеренно ломает, удаляет, хоронит заживо, заменяет либо кнопку переключения, либо событие щелчка мыши, которое сообщает комбинированному списку, что оно должно показать свое всплывающее окно, или что-то среднее между ними. остановить это действие
Это мой третий вопрос, пытающийся найти что-то, что будет работать. Честно говоря, любые предложения будут полезны (просто не копируйте и не редактируйте шаблон, перейдите на другой мой вопрос, где я прошу помощи о том, как реализовать это решение)
using Analytics_Module.Models;
using System;
using System.Collections;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
namespace Analytics_Module.UI_Components
{
class MultiselectFilteredComboBox : ComboBox
{
////
// Public Fields
////
/// <summary>
/// The search string treshold length.
/// </summary>
/// <remarks>
/// It's implemented as a Dependency Property, so you can set it in a XAML template
/// </remarks>
public static readonly DependencyProperty MinimumSearchLengthProperty =
DependencyProperty.Register(
"MinimumSearchLength",
typeof(int),
typeof(MultiselectFilteredComboBox),
new UIPropertyMetadata(3));
////
// Private Fields
////
/// <summary>
/// Caches the previous value of the filter.
/// </summary>
private string oldFilter = string.Empty;
/// <summary>
/// Holds the current value of the filter.
/// </summary>
private string currentFilter = string.Empty;
public static T FindChild<T>(DependencyObject parent, string childName)
where T : DependencyObject
{
// Confirm parent and childName are valid.
if (parent == null) return null;
T foundChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
// If the child is not of the request child type child
T childType = child as T;
if (childType == null)
{
// recursively drill down the tree
foundChild = FindChild<T>(child, childName);
// If the child is found, break so we do not overwrite the found child.
if (foundChild != null) break;
}
else if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as FrameworkElement;
// If the child's name is set for search
if (frameworkElement != null && frameworkElement.Name == childName)
{
// if the child's name is of the request name
foundChild = (T)child;
break;
}
}
else
{
// child element found.
foundChild = (T)child;
break;
}
}
return foundChild;
}
////
// Constructors
////
/// <summary>
/// Initializes a new instance of the FilteredComboBox class.
/// </summary>
/// <remarks>
/// You could set 'IsTextSearchEnabled' to 'false' here,
/// to avoid non-intuitive behavior of the control
/// </remarks>
public MultiselectFilteredComboBox()
{
}
////
// Properties
////
/// <summary>
/// Gets or sets the search string treshold length.
/// </summary>
/// <value>The minimum length of the search string that triggers filtering.</value>
[Description("Length of the search string that triggers filtering.")]
[Category("Filtered ComboBox")]
[DefaultValue(3)]
public int MinimumSearchLength
{
[System.Diagnostics.DebuggerStepThrough]
get
{
return (int)this.GetValue(MinimumSearchLengthProperty);
}
[System.Diagnostics.DebuggerStepThrough]
set
{
this.SetValue(MinimumSearchLengthProperty, value);
}
}
/// <summary>
/// Gets a reference to the internal editable textbox.
/// </summary>
/// <value>A reference to the internal editable textbox.</value>
/// <remarks>
/// We need this to get access to the Selection.
/// </remarks>
protected TextBox EditableTextBox
{
get
{
return this.GetTemplateChild("PART_EditableTextBox") as TextBox;
}
}
////
// Event Raiser Overrides
////
/// <summary>
/// Keep the filter if the ItemsSource is explicitly changed.
/// </summary>
/// <param name="oldValue">The previous value of the filter.</param>
/// <param name="newValue">The current value of the filter.</param>
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
{
if (newValue != null)
{
ICollectionView view = CollectionViewSource.GetDefaultView(newValue);
view.Filter += this.FilterPredicate;
}
if (oldValue != null)
{
ICollectionView view = CollectionViewSource.GetDefaultView(oldValue);
view.Filter -= this.FilterPredicate;
}
base.OnItemsSourceChanged(oldValue, newValue);
}
/// <summary>
/// Confirm or cancel the selection when Tab, Enter, or Escape are hit.
/// Open the DropDown when the Down Arrow is hit.
/// </summary>
/// <param name="e">Key Event Args.</param>
/// <remarks>
/// The 'KeyDown' event is not raised for Arrows, Tab and Enter keys.
/// It is swallowed by the DropDown if it's open.
/// So use the Preview instead.
/// </remarks>
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Tab || e.Key == Key.Enter)
{
// Explicit Selection -> Close ItemsPanel
this.IsDropDownOpen = false;
}
else if (e.Key == Key.Escape)
{
// Escape -> Close DropDown and redisplay Filter
this.IsDropDownOpen = false;
this.SelectedIndex = -1;
this.Text = this.currentFilter;
}
else
{
if (e.Key == Key.Down)
{
// Arrow Down -> Open DropDown
this.IsDropDownOpen = true;
}
base.OnPreviewKeyDown(e);
}
// Cache text
this.oldFilter = this.Text;
}
/// <summary>
/// Modify and apply the filter.
/// </summary>
/// <param name="e">Key Event Args.</param>
/// <remarks>
/// Alternatively, you could react on 'OnTextChanged', but navigating through
/// the DropDown will also change the text.
/// </remarks>
protected override void OnKeyUp(KeyEventArgs e)
{
if (e.Key == Key.Up || e.Key == Key.Down)
{
// Navigation keys are ignored
}
else if (e.Key == Key.Tab || e.Key == Key.Enter)
{
// Explicit Select -> Clear Filter
this.ClearFilter();
}
else
{
// The text was changed
if (this.Text != this.oldFilter)
{
// Clear the filter if the text is empty,
// apply the filter if the text is long enough
if (this.Text.Length == 0 || this.Text.Length >= this.MinimumSearchLength)
{
this.RefreshFilter();
this.IsDropDownOpen = true;
// Unselect
this.EditableTextBox.SelectionStart = int.MaxValue;
}
}
base.OnKeyUp(e);
// Update Filter Value
this.currentFilter = this.Text;
}
}
/// <summary>
/// Make sure the text corresponds to the selection when leaving the control.
/// </summary>
/// <param name="e">A KeyBoardFocusChangedEventArgs.</param>
protected override void OnPreviewLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
//this.ClearFilter();
//int temp = this.SelectedIndex;
//this.SelectedIndex = -1;
//this.Text = string.Empty;
//this.SelectedIndex = temp;
//base.OnPreviewLostKeyboardFocus(e);
}
////
// Helpers
////
/// <summary>
/// Re-apply the Filter.
/// </summary>
private void RefreshFilter()
{
if (this.ItemsSource != null)
{
ICollectionView view = CollectionViewSource.GetDefaultView(this.ItemsSource);
view.Refresh();
}
}
/// <summary>
/// Clear the Filter.
/// </summary>
private void ClearFilter()
{
this.currentFilter = string.Empty;
this.RefreshFilter();
}
/// <summary>
/// The Filter predicate that will be applied to each row in the ItemsSource.
/// </summary>
/// <param name="value">A row in the ItemsSource.</param>
/// <returns>Whether or not the item will appear in the DropDown.</returns>
private bool FilterPredicate(object value)
{
MultiSelectDropDownListEntry tmp = (MultiSelectDropDownListEntry)value;
// No filter, no text
if (value == null)
{
return false;
}
// No text, no filter
if (this.Text.Length == 0)
{
return true;
}
// Case insensitive search
return tmp.Name.ToString().ToLower().Contains(this.Text.ToLower());
}
}
}