原文http://www.cnblogs.com/scheshan/archive/2012/06/30/2570867.html

最近WPF项目中遇到一个需求,需要给一个RichTextBox添加智能提示(IntelliSense)功能。

分析下具体的需求,在用户键入"@"符号时,应该显示一个弹出框,把所有用户列出。用户可以通过键盘、鼠标等进行选择。用户列表可能数据比较多,那么用户还应该可以输入字符进行筛选。用过各种IDE开发工具的童鞋应该对这样的效果很了解了,具体效果如下

输入@符号的效果:

筛选的效果:

再谈谈具体的开发思路.

1.如何制作可以实现列表选择功能的弹出框

  方法很多,Popup+ListBox可以完美解决.此处我为了省代码,直接用的ListBox

2.如何在键入@符号时,将ListBox显示在@符号之后

  在VisualStudio的智能提示里,当我们触发了IntelliSense时,提示框会显示,并且与下一字符的插入点对齐。TextPointer类提供了方法可以获取到某个插入点的坐标:

     RichTextBox textbox = this.RichTextBox;
TextPointer start = textbox.Selection.Start;
Rect rect = start.GetCharacterRect(LogicalDirection.Forward);
Point point = rect.BottomLeft;

  我们可以注册RichTextBox的键盘事件,判断用户是否键入@符号。@符号是由“Shift”+“2”组成,Keyboard.Modifiers可以获取到组合键:

 if (Keyboard.Modifiers == ModifierKeys.Shift && e.Key == Key.D2)
{
//TODO: 用户键入了@符号
}

  在TODO里,将ListBox移动到得到Point位置即可。

3.如何实现选择和筛选

  筛选功能很简单,保存一个局部变量,在智能提示框显示后记录用户输入,智能提示框隐藏后清空,智能提示框中的数据按照该变量进行过滤即可。

  当智能提示框显示的时候,用户是可以键入“上”,“下”键进行移动选择的。也许在敲了几次方向键,用户还想继续输入字符进行筛选。最开始,我是 用的ListBox自动的选择功能,当用户敲入方向键,我就将键盘焦点(WPF中分键盘焦点和逻辑焦点,这个也是困扰我很久的问题)设置到ListBox 上,那么用户就可以敲入“上”,“下”键进行移动选择了。看起来很简单,但是这样是有问题的,因为用户如果想继续敲入字符筛选,我还必须将键盘焦点重新设 置到RichTextBox上,否则用户的敲击是无效的。

  后来突然想通了,在用户敲击“上”,“下”键时,只需要调用ListBox的MoveCurrentToPrevious()和 MoveCurrentToNext()即可,这样给用户的错觉还是有了上下移动的效果。焦点不在ListBox上时,这样的移动可能造成当前选中项超出 了显示范围之外,那么可以通过ListBox的ScrollIntoView()方法,将选中对象滚动到视图中。

  下面是截取的一段代码:

           //如果按了向下键,则把选中项下移
if (e.Key == Key.Down)
{
if (UserList.CurrentPosition != UserList.Count - )
{
lbUser.Items.MoveCurrentToNext();
lbUser.ScrollIntoView(lbUser.Items.CurrentItem);
}
e.Handled = true;
}
//如果按了向上键,则把选中项上移
if (e.Key == Key.Up)
{
if (UserList.CurrentPosition != )
{
lbUser.Items.MoveCurrentToPrevious();
lbUser.ScrollIntoView(lbUser.Items.CurrentItem);
}
e.Handled = true;
}

4.实现选中和取消
  选中功能就更简单了,分别加入对鼠标双击,空格,回车,TAB等的判断,将ListBox的当前选中项的文本插入到
RichTextBox中即可。需要注意的是,此处要对单击做判定,由于单击ListBox会使键盘焦点设置到其之上,因此要强制将键盘焦点从
ListBox移开。判断ESC键,使ListBox隐藏即可实现取消功能。

5.如何实现扩展

  做一个功能最重要的就是考虑以后的重用,此处可以公开
KeyBoard.Modifyers,KeyCode,IEnumable<T>为依赖属性,前2个代表在敲入什么组合键时会弹出智能提示
框,最后一个是弹出内容的数据源。由于此处的筛选功能是在控件内部,那么我们可以定义一个接口,包含一个Name属性。 

 public interface IData
{
//用于筛选和插入的名称
string Name { get; set; }
}

  将上面的IEnumable<T>改为IEnumable<IData>。

  以后的调用方,只需要将这3个中的一个或多个传入,即可实现智能提示功能。

WPF制作的一个小功能,智能提示(IntelliSense)的更多相关文章

  1. 在VS中让一个JS文件智能提示另一个JS文件中的成员

    “在VS中如何让一个JS文件智能提示另一个JS文件中的成员” 有时候会有这种情况:当我的一个Web页面引用了两个JS文件(假如分别叫common.js和JScript1.js),如果JScript1. ...

  2. 模仿京东顶部搜索条效果制作的一个小demo

    最近模仿京东顶部搜索条效果制作的一个小demo,特贴到这里,今后如果有用到可以参考一下,代码如下 #define kScreenWidth [UIScreen mainScreen].bounds.s ...

  3. 用MVC5+EF6+WebApi 做一个小功能(三) 项目搭建

    一般一个项目开始之前都会有启动会,需求交底等等,其中会有一个环节,大讲特讲项目的意义,然后取一个高大上的项目名字,咱这是一个小功能谈不上项目,但是名字不能太小气了.好吧,就叫Trump吧.没有任何含义 ...

  4. Visual Studio中让一个JS文件智能提示另一个JS文件中的成员

    当一个Web页面引用了两个JS文件(假如分别叫common.js和JScript1.js),如果JScript1.js中需要调用大量的common.js中的方法,这时候在JScript1.js中智能提 ...

  5. 用MVC5+EF6+WebApi 做一个小功能(四) 项目分层功能以及文件夹命名

    在上一节,我们完成了一个项目搭建,我们看到的是一个项目的分层架子,那接下来每一层做什么以及需要引用哪些内容呢?在本节内容我们还逐步拆分每一层的功能,顺带添加package包 Trump.Domain ...

  6. 用MVC5+EF6+WebApi 做一个小功能(二) 项目需求整理

    在一个项目开始前,需求整理大概要占到整个项目周期15%甚至30%的比重,可以说需求理得越清楚,后续开发中返工几率越小.在一个项目中,开发新功能的花费的精力要远远小于修改功能的精力,这基本是一个共识.老 ...

  7. 在VS中让一个JS文件智能提示另一个JS文件中的成员2--具体引用

    我们知道,在html中,利用<script language="javascript" type="text/javascript" src=" ...

  8. 空闲时间研究一个小功能:winform桌面程序如何实现动态更换桌面图标

    今天休息在家,由于天气热再加上疫情原因,就在家里呆着,空闲时想着,在很早以前(约3年前),产品人员跟我提了一个需求,那就是winform桌面程序的图标能否根据节日动态更换,这种需求在移动APP上还是比 ...

  9. 【一个小功能】点击图标/链接发起QQ临时会话

    有时候,我们需要实现在网页上点击一个QQ图标来实现QQ临时会话,这样不用添加好友,也能满足及时沟通的需求. 实现方案比较简单,只是为a标签修改href属性,代码如下 <a href=" ...

随机推荐

  1. php将会话保存在数据库里

    php默认把会话保存在临时文件中,保存在数据库中可以提高安全性,在共享主机服务器上,所有web站点都使用同一个临时目录,这意味着数十个程序都在同一位置进行文件读取的操作,我们很容易就编写一个脚本从这个 ...

  2. 深入浅出Node.js (6) - 理解Buffer

    6.1 Buffer结构 6.1.1 模块结构 6.1.2 Buffer对象 6.1.3 Buffer内存分配 6.2 Buffer的转换 6.2.1 字符串转Buffer 6.2.2 Buffer转 ...

  3. C++关于strcpy等函数的安全版本

    如下程序: #include <iostream> using namespace std; int main() { ]; strcpy(ch1,"); } 在VS2012上面 ...

  4. Spring HTTP invoker 入门

    一.简介 Spring开发团队意识到RMI服务和基于HTTP的服务(如,Hessian)之间的空白.一方面,RMI使用JAVA标准的对象序列化机制,很难穿透防火墙.另一方面,Hessian/Burla ...

  5. 【LeetCode练习题】Recover Binary Search Tree

    Recover Binary Search Tree Two elements of a binary search tree (BST) are swapped by mistake. Recove ...

  6. python学习之路-1 python简介及安装方法

    python简介 一种面向对象.解释型计算机程序设计语言,由Guido van Rossum于1989年发明,第一个公开发行版发行于1991年. 目前最新版本为3.5.1,发布于2015年12月07日 ...

  7. Android学习总结——去除标题栏

    1.继承app.Activity的Activity去除标题栏 @Override protected void onCreate(Bundle savedInstanceState) { super. ...

  8. Swift之贪婪的UIButton

    一.内容概要 按钮是所有UI体系中非常重要的组件,在iOS中按钮UIButton的使用也非常灵活,本文将从以下几点介绍UIButton的使用(基于Swift2.0): 1.UIButton基础 2.U ...

  9. CLR via C# - Char_String - Format

    //前面那个本来想重新编辑的,但是那个编辑器之前被我调到Markdown之后,改回Tiny MCE编辑器不出来 1.ToString()方法 & IFormattable & IFor ...

  10. js中退出语句break,continue和return 比较(转)

    原链接:http://blog.163.com/ued_er/blog/static/199703159201210283107315/ js中退出语句break,continue和return 比较 ...