gpt4 book ai didi

wpf - 基于文本输入的WPF组合框动态过滤器

转载 作者:行者123 更新时间:2023-12-04 13:29:52 25 4
gpt4 key购买 nike

我似乎无法找到一种直接方法来实现将文本输入过滤到 WPF 组合框中的项目列表中。
通过将 IsTextSearchEnabled 设置为 true,组合框下拉列表将跳转到第一个匹配项。我需要的是将列表过滤为与文本字符串匹配的任何内容(例如,如果我专注于我的组合框并键入“abc”,我想查看以(或最好包含)开头的 ItemsSource 集合中的所有项目) 'abc' 作为下拉列表的成员)。

我怀疑它有什么不同,但我的显示项被模板化为复杂类型的属性:

<ComboBox x:Name="DiagnosisComboBox" Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="3" 
ItemsSource="{Binding Path = ApacheDxList,
UpdateSourceTrigger=PropertyChanged,
Mode=OneWay}"
IsTextSearchEnabled="True"
ItemTemplate="{StaticResource DxDescriptionTemplate}"
SelectedValue="{Binding Path = SelectedEncounterDetails.Diagnosis,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"/>

谢谢。

最佳答案

几天前我刚刚使用此站点代码的修改版本完成了此操作:Credit where credit is due

我的完整代码如下:

using System.Collections;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;

namespace MyControls
{
public class FilteredComboBox : ComboBox
{
private string oldFilter = string.Empty;

private string currentFilter = string.Empty;

protected TextBox EditableTextBox => GetTemplateChild("PART_EditableTextBox") as TextBox;


protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
{
if (newValue != null)
{
var view = CollectionViewSource.GetDefaultView(newValue);
view.Filter += FilterItem;
}

if (oldValue != null)
{
var view = CollectionViewSource.GetDefaultView(oldValue);
if (view != null) view.Filter -= FilterItem;
}

base.OnItemsSourceChanged(oldValue, newValue);
}

protected override void OnPreviewKeyDown(KeyEventArgs e)
{
switch (e.Key)
{
case Key.Tab:
case Key.Enter:
IsDropDownOpen = false;
break;
case Key.Escape:
IsDropDownOpen = false;
SelectedIndex = -1;
Text = currentFilter;
break;
default:
if (e.Key == Key.Down) IsDropDownOpen = true;

base.OnPreviewKeyDown(e);
break;
}

// Cache text
oldFilter = Text;
}

protected override void OnKeyUp(KeyEventArgs e)
{
switch (e.Key)
{
case Key.Up:
case Key.Down:
break;
case Key.Tab:
case Key.Enter:

ClearFilter();
break;
default:
if (Text != oldFilter)
{
RefreshFilter();
IsDropDownOpen = true;

EditableTextBox.SelectionStart = int.MaxValue;
}

base.OnKeyUp(e);
currentFilter = Text;
break;
}
}

protected override void OnPreviewLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
ClearFilter();
var temp = SelectedIndex;
SelectedIndex = -1;
Text = string.Empty;
SelectedIndex = temp;
base.OnPreviewLostKeyboardFocus(e);
}

private void RefreshFilter()
{
if (ItemsSource == null) return;

var view = CollectionViewSource.GetDefaultView(ItemsSource);
view.Refresh();
}

private void ClearFilter()
{
currentFilter = string.Empty;
RefreshFilter();
}

private bool FilterItem(object value)
{
if (value == null) return false;
if (Text.Length == 0) return true;

return value.ToString().ToLower().Contains(Text.ToLower());
}
}
}

WPF 应该是这样的:
<MyControls:FilteredComboBox ItemsSource="{Binding MyItemsSource}"
SelectedItem="{Binding MySelectedItem}"
DisplayMemberPath="Name"
IsEditable="True"
IsTextSearchEnabled="False"
StaysOpenOnEdit="True">

<MyControls:FilteredComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel VirtualizationMode="Recycling" />
</ItemsPanelTemplate>
</MyControls:FilteredComboBox.ItemsPanel>
</MyControls:FilteredComboBox>

这里有几点需要注意。您会注意到 FilterItem 实现在对象上执行了 ToString()。这意味着您要显示的对象的属性应该在您的 object.ToString() 实现中返回。 (或者已经是一个字符串)换句话说,就像这样:
public class Customer
{
public string Name { get; set; }
public string Address { get; set; }
public string PhoneNumber { get; set; }

public override string ToString()
{
return Name;
}
}

如果这不能满足您的需求,我想您可以获取 DisplayMemberPath 的值并使用反射来获取使用它的属性,但这会更慢,因此除非必要,否则我不建议这样做。

此外,此实现不会阻止用户在 ComboBox 的 TextBox 部分键入他们喜欢的任何内容。如果他们在那里输入一些愚蠢的东西,SelectedItem 将恢复为 NULL,所以准备好在你的代码中处理它。

此外,如果您有很多项目,我强烈建议您使用 VirtualizingStackPanel 就像我上面的例子一样,因为它在加载时间上有很大的不同

关于wpf - 基于文本输入的WPF组合框动态过滤器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2001842/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com