WPF: 自动完成文本框,...再次

46

这个 Stack Overflow 的问题 询问了 WPF 中的自动完成文本框。已经有几个人建立了这些,其中一个给出的答案建议使用 这篇 CodeProject 文章

但是我还没有找到任何与 WinForms 自动完成文本框相比较的 WPF 自动完成文本框。CodeProject 的示例可以运行,但是有点问题...

alt text

但是:

  • 它不像可重复使用控件或DLL那样结构化。 它是我需要嵌入每个应用程序的代码。
  • 它仅适用于目录。 它没有设置自动完成源是否仅限于文件系统目录、文件系统文件等属性。 当然,我可以编写代码来实现这一点,但......我宁愿使用别人已经编写好的代码。
  • 它没有设置弹出窗口大小等属性。
  • 有一个弹出列表框显示可能的自动完成。 在浏览该列表时,文本框不会改变。 在列表框中聚焦时键入字符不会导致文本框更新。
  • 将焦点从列表框导航到其他地方不会使弹出列表框消失。 这很令人困惑。

所以,我的问题是:

* 有人有免费的WPF AutoComplete文本框(有效),并提供优质的UI体验吗? *


回答

这是我实现的方法:

.0. 获取WPF Toolkit

.1. 运行 WPF Toolkit 的 MSI 安装程序。

.2. 在 Visual Studio 中,从工具箱中拖放 - 特别是数据可视化组 - 到 UI Designer。在 VS 工具箱中它看起来像这样:

alt text

如果您不想使用设计师工具,可以手动编写XAML。它看起来像这样:
<toolkit:AutoCompleteBox
   ToolTip="Enter the path of an assembly."
   x:Name="tbAssembly" Height="27" Width="102"
   Populating="tbAssembly_Populating" />

...其中工具包命名空间是这样映射的:

xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit"

3. 提供Populating事件的代码。 这是我使用的:


private void tbAssembly_Populating(object sender, System.Windows.Controls.PopulatingEventArgs e)
{
    string text = tbAssembly.Text;
    string dirname = Path.GetDirectoryName(text);

    if (Directory.Exists(Path.GetDirectoryName(dirname)))
    {
        string[] files = Directory.GetFiles(dirname, "*.*", SearchOption.TopDirectoryOnly);
        string[] dirs = Directory.GetDirectories(dirname, "*.*", SearchOption.TopDirectoryOnly);
        var candidates = new List<string>();

        Array.ForEach(new String[][] { files, dirs }, (x) =>
            Array.ForEach(x, (y) =>
                      {
                          if (y.StartsWith(dirname, StringComparison.CurrentCultureIgnoreCase))
                              candidates.Add(y);
                      }));

        tbAssembly.ItemsSource = candidates;
        tbAssembly.PopulateComplete();
    }
}

它运作正常,就像你预期的那样。感觉很专业。没有codeproject控件表现出的任何异常情况。它看起来是这样的:

alt text


感谢Matt提供的指引,介绍了WPF工具包。

5个回答

32

听起来很有趣,马特。有没有使用AutoCompleteBox的指南或示例?我找到了包含它的DLL。在XAML中我应该使用什么xmlns?我该如何实际使用它? - Cheeso
请注意,我刚添加的博客文章链接讨论了Silverlight,但AutoCompleteBox也适用于WPF。 - Matt Hamilton
1
WPF Toolkit在CodePlex上已经停止维护,但是在GitHub上有几个分支,如果有人需要的话:jogibear9988/wpftoolkitWPFToolkit.DataVisualizationtheonlylawislove/WPFToolkitjrwren/wpftoolkit - Athari
1
另一篇关于如何使用它的博客文章:http://www.broculos.net/2014/04/wpf-autocompletebox-autocomplete-text.html#.VG8UKvndVAU - CAD bloke

17

这是我的做法:

1. 运行WPF Toolkit的MSI文件。

2. 在Visual Studio中,从工具箱中拖放 - 特别是数据可视化组 - 到UI设计器中。在VS工具箱中它看起来像这样:

alt text

或者手动编写XAML代码。它看起来像这样:


<toolkit:AutoCompleteBox
   ToolTip="Enter the path of an assembly."
   x:Name="tbAssembly" Height="27" Width="102"
   Populating="tbAssembly_Populating" />

...其中工具包命名空间是这样映射的:

xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit"

3. 提供Populating事件的代码。这是我使用的代码:


private void tbAssembly_Populating(object sender, System.Windows.Controls.PopulatingEventArgs e)
{
    string text = tbAssembly.Text;
    string dirname = Path.GetDirectoryName(text);

    if (Directory.Exists(Path.GetDirectoryName(dirname)))
    {
        string[] files = Directory.GetFiles(dirname, "*.*", SearchOption.TopDirectoryOnly);
        string[] dirs = Directory.GetDirectories(dirname, "*.*", SearchOption.TopDirectoryOnly);
        var candidates = new List<string>();

        Array.ForEach(new String[][] { files, dirs }, (x) =>
            Array.ForEach(x, (y) =>
                      {
                          if (y.StartsWith(dirname, StringComparison.CurrentCultureIgnoreCase))
                              candidates.Add(y);
                      }));

        tbAssembly.ItemsSource = candidates;
        tbAssembly.PopulateComplete();
    }
}
感谢 Matt 指向 WPF 工具包。

2
Mindscape还提供了3个免费控件,包括WPF Autocomplete Textbox。 http://intellibox.codeplex.com/ 似乎最近更新于2013年10月1日,并包含单个控件。 我本来想在Troy的答案上添加评论,但没有足够的声望。由于那条评论,我差点忽略了它。文档中的示例用法如下:
    <auto:Intellibox ResultsHeight="80"
                     ExplicitlyIncludeColumns="True"
                     Name="lightspeedBox"
                     DisplayedValueBinding="{Binding Product_Name}"
                     SelectedValueBinding="{Binding Product_Id}"
                     DataProvider="{Binding RelativeSource={RelativeSource FindAncestor, 
                     AncestorType={x:Type Window}}, Path=LinqToEntitiesProvider}"
                     Height="26"
                     Margin="12,26,12,0"
                     VerticalAlignment="Top">
        <auto:Intellibox.Columns>
            <auto:IntelliboxColumn DisplayMemberBinding="{Binding Product_Name}"
                                   Width="150"
                                   Header="Product Name" />
            <auto:IntelliboxColumn DisplayMemberBinding="{Binding Unit_Price}"
                                   Width="75"
                                   Header="Unit Price" />
            <auto:IntelliboxColumn DisplayMemberBinding="{Binding Suppliers.Company_Name}"
                                   Width="125"
                                   Header="Supplier" />
        </auto:Intellibox.Columns>
    </auto:Intellibox>

2

我在我的内部项目中使用Intellibox。http://intellibox.codeplex.com/

我发现它使用提供程序模式进行搜索非常直观。

Rake的答案提供了如何使用它的示例,正如他所指出的那样,它在去年底进行了一些开发(尽管这是我上次使用它之后的事情)。


1
http://intellibox.codeplex.com/ 似乎最近更新于2013年10月1日,其中包含单个控件。(感谢Rake) - Cheeso
是的,我已经有一段时间没有在那上工作了,很高兴知道它自那以后得到了一些关注。谢谢! - Troy

2

2
我看到这是你的项目,看起来不错,但你应该做更多的事情,而不仅仅是在这里添加一个链接。添加一些示例代码、说明,展示为什么它是 OP 的可能解决方案。StackOverflow 本质上是一个问答 wiki,因此用户期望在答案中看到足够的细节,以便他们能够确定该解决方案适用于他们,而不必离开该网站。当然可以引导人们前往 codeplex 网站获取更多信息。 - Chris Ballard
1
我花了早上的时间审查了我在网络上找到的不同地方的自动完成文本框。这个是迄今为止最好的,也是我将在我的项目中使用的。 - dlf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接