WPF版的HideCaret()
WPF版的HideCaret()
周银辉
事情是这样的:
一般说来,对于那些拥有句柄的TextBox(RichTextBox同理)控件,比如win32的,WinForm,如果我们想手动隐藏或显示其插入符(Caret),可以调用HideCaret和ShowCaret这样的Windows API,比如WinForm而言,我们可以这样:
[DllImport("user32.dll")]
public static extern bool HideCaret(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern bool ShowCaret(IntPtr hWnd);
那个hWnd嘛,传入TextBox的句柄就可以了。
但到了WPF这里,恩,不好使了,因为在WPF中,窗口级别的东东有句柄,文本框之类的控件根本就没有。
另外,把WPF的TextBox 的 IsReadOnly属性设置为True,插入符自然没有了, 如果你的应用里面的确可以将其设置为只读的话,这是可行的,当然,我比较背,我发现将其设置成只读后在某种情况之下其光标还在那里闪啊闪,难道是WPF的BUG?反正这足够让我郁闷的了。
WPF TextBox的插入符是如何实现的:
据我的粗略”研究“表明,其根本就不是调用Win32 API来显示插入符的,其用的是一个Adorner,然后对这个Adorner做的一点动画效果。
解决方案:
那么找出这个显示的插入符的Adorner,那么隐藏起来不就OK了。但是,WPF TextBox自然不会暴露出这样的”内部组件“,所以不那么容易找啊。没关系,Reflector这样的工具能够反编译出.net api的一切东东,那么就说明要把那个Adorner找出来不是没有可能的。所以我折腾出了下面的代码:
private static Adorner GetCaret(this TextBoxBase textBox)
{
var textContainer = textBox.GetPrivateProperty("TextContainer").GetValue(textBox, null);
var textSelection = textContainer.GetPrivateProperty("TextSelection").GetValue(textContainer, null);
var caretElement = textSelection.GetPrivateProperty("CaretElement").GetValue(textSelection, null);
var caret = caretElement as Adorner; return caret;
}
然后 caret.Visibility = Visibility.Collapsed (或Visible)便可以控制插入符的隐藏或显示了
但,郁闷的事情接踵而至,我发现,当你隐藏掉你查找出了的Adorner后,TextBox会在某些情况之下,完全重新创建一个Adorner来显示,Oh,My lady GaGa,
既然你不停地创建,那么我就不停地扼杀吧,呵呵呵,完整的代码如下:
internal static class CaretHelper { private static Thread GetBackgourndThread(DependencyObject obj) { return (Thread)obj.GetValue(BackgourndThreadProperty); } private static void SetBackgourndThread(DependencyObject obj, Thread value) { obj.SetValue(BackgourndThreadProperty, value); } private static readonly DependencyProperty BackgourndThreadProperty = DependencyProperty.RegisterAttached("BackgourndThread", typeof(Thread), typeof(CaretHelper), new UIPropertyMetadata(null)); public static void HideCaret(this TextBoxBase textBox) { var pts = new ParameterizedThreadStart(HideCaretCore); var thread = GetBackgourndThread(textBox); if (thread == null) { thread = new Thread(pts) {IsBackground = true}; SetBackgourndThread(textBox, thread); thread.Start(textBox); } else { try {#pragma warning disable 618,612 thread.Resume();#pragma warning restore 618,612 }// ReSharper disable EmptyGeneralCatchClause catch// ReSharper restore EmptyGeneralCatchClause { } } } private static void HideCaretCore(this object textBox) { while (true) { var caret = ((TextBoxBase)textBox).GetCaret(); if (caret != null) { Action a = () => caret.Visibility = Visibility.Collapsed; caret.Dispatcher.Invoke(a, null); } Thread.Sleep(); }// ReSharper disable FunctionNeverReturns }// ReSharper restore FunctionNeverReturns public static void ShowCaret(this TextBoxBase textBox) { var thread = GetBackgourndThread(textBox); if (thread != null) {#pragma warning disable 618,612 thread.Suspend();#pragma warning restore 618,612 } var caret = textBox.GetCaret(); if (caret != null) { caret.Visibility = Visibility.Visible; } } private static Adorner GetCaret(this TextBoxBase textBox) { var textContainer = textBox.GetPrivateProperty("TextContainer").GetValue(textBox, null); var textSelection = textContainer.GetPrivateProperty("TextSelection").GetValue(textContainer, null); var caretElement = textSelection.GetPrivateProperty("CaretElement").GetValue(textSelection, null); var caret = caretElement as Adorner; return caret; } private static PropertyInfo GetPrivateProperty(this object obj, string name) { return obj.GetType().GetProperty(name, BindingFlags.GetProperty | BindingFlags.NonPublic | BindingFlags.Instance); } }
WPF版的HideCaret()的更多相关文章
- Visual Studio 版本转换工具WPF版开源了
想法的由来 入职一家新公司,领导给了个任务,要编写一个视频监控软件,等我编写调试好,领导满意了以后,这个软件要加入到公司的一个软件系统中去(这个添加工作不用我来做,嘻嘻,看着自己的软件被别人使用,心情 ...
- CefSharp.v49.0.1浏览器控件完全WPF版,实现禁止弹出新窗口,在同一窗口打开链接,并且支持带type="POST" target="_blank"的链接
需求场景:在查询页面,填写查询条件,查询条件包括上传的图片,根据图片的特征查询,这就需要在提交的时候,使用POST提交,因为GET提交无法提交图片数据,提交查询条件之后,在新的窗口展示查询结果.(当然 ...
- 使用 GMap.NET 实现添加标注、移动标注功能。(WPF版)
前言 在WPF嵌入地图,有两种方式: 浏览器方式:控件方式. 1)浏览器方式就是使用浏览器控件WebBrowser,设置好网址就行了.这种方式与地图的交互不太直接,需要懂html.javascript ...
- 使用GMap.NET类库,实现地图轨迹回放。(WPF版)
前言 实现轨迹回放,GMap.NET有对应的类GMapRoute.这个类函数很少,功能有限,只能实现简单的轨迹回放.要实现更复杂的轨迹回放,就需要自己动手了. 本文介绍一种方法,可以实现复杂的轨迹回放 ...
- 【MEF】构建一个WPF版的ERP系统
原文:[MEF]构建一个WPF版的ERP系统 引言 MEF是微软的一个扩展性框架,遵循某种约定将各个部件组合起来.而ERP系统的一大特点是模块化,它们两者的相性很好,用MEF构建一个ERP系统是相当合 ...
- wpf版扫雷游戏
近来觉得wpf做出来的界面很拉风,自己也很喜欢搞些小游戏,感觉这做出来的会很炫,很装逼,(满足自己的一点小小的虚荣心)于是就去自学,发现感觉很不错,可是属性N多,太多了,而且质料也少,很多不会用,只会 ...
- GMap.NET实现电子围栏功能(WPF版)
前言 GMap.NET是一个强大.免费.跨平台.开源的.NET控件.分为WPF和winform版.GMap.NET的基本知识不做过多介绍,本文主要介绍如何使用该控件实现电子围栏功能. 电子围栏主要有两 ...
- WPF版的权限管理系统
好多技术人员都有一个通病,不关注用户的需求,产品的可用性,只看使用的技术的新不新,潮不潮,这就是所谓的技术发烧友. 这段时间,断断续续的开发一个WPF的软件,也拿出来Show一下.要不放在硬盘里就发霉 ...
- 一款高效视频播放控件的设计思路(c# WPF版)
因工作的需要,开发了一款视频播放程序.期间也经历许多曲折,查阅了大量资料,经过了反复测试,终于圆满完成了任务. 我把开发过程中的一些思路.想法写下来,以期对后来者有所帮助. 视频播放的本质 就是连续的 ...
随机推荐
- HTML5开发移动web应用——SAP UI5篇(9)
之前我们对于app的构建都是基于显示的.如今我们来格式化一下,引入很多其它的SAP UI5组件概念.这使得APP的一个界面更有层次性.更像是一个手机应用的界面,而且更好地使用SAP UI5中提供的功能 ...
- ios开发多线程一:了解-NSOperation的基本使用
#import "ViewController.h" @interface ViewController () @end @implementation ViewControlle ...
- css hover控制其他元素
<html> <body> <style> #a:hover {color : #FFFF00;} #a:hover > #b:first-child{col ...
- php 中英文字符串截取,字符串长度
在做PHP开发的时候,由于我国的语言环境问题,所以我们常常需要对中文进行处理.在PHP中,我们都知道有专门的mb_substr和mb_strlen函数,可以对中文进行截取和计算长度,但是,由于这些函数 ...
- ant脚本中设置环境变量
http://blog.csdn.net/quqi99/article/details/5329841
- CoreData使用方法二:NSFetchedResultsController实例操作与解说
学习了NSFetchedResultsController.才深深的体会到coredata的牛逼之处.原来Apple公司弄个新技术.不是平白无故的去弄,会给代码执行到来非常大的优点.coredata不 ...
- 全栈JavaScript之路( 二十五 )訪问元素的样式
不论什么支持style 特性的元素在 ,在其DOM 节点 对象中都有一个 style 属性与之相应. 这个style 对象是 CSSStyleDeclaration类型的实例,包括着html sty ...
- (翻译)2016美国数学建模MCM E题(环境)翻译:我们朝向一个干旱的星球?
PROBLEM E: Are we heading towards a thirsty planet? Will the world run out of clean water? According ...
- 学习鸟哥的Linux私房菜笔记(6)——过滤器、输入输出及管道
一.过滤器 Linux中的应用工具分为三种: 交互工具 过滤器 编辑器 能够接受数据,过滤再输出的工具,称之为过滤器 对过滤器和进程,存在着输入源与输出对象 二.输入.输出.重定向 输入:过滤器的数据 ...
- java常用api2
calendar calendar=calendar.getInstance(); StringBuilder和C#的用法一样 hashSet无序的,不可重复 LInkedHashSet有序的,不可重 ...