原文: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()的更多相关文章

  1. Visual Studio 版本转换工具WPF版开源了

    想法的由来 入职一家新公司,领导给了个任务,要编写一个视频监控软件,等我编写调试好,领导满意了以后,这个软件要加入到公司的一个软件系统中去(这个添加工作不用我来做,嘻嘻,看着自己的软件被别人使用,心情 ...

  2. CefSharp.v49.0.1浏览器控件完全WPF版,实现禁止弹出新窗口,在同一窗口打开链接,并且支持带type="POST" target="_blank"的链接

    需求场景:在查询页面,填写查询条件,查询条件包括上传的图片,根据图片的特征查询,这就需要在提交的时候,使用POST提交,因为GET提交无法提交图片数据,提交查询条件之后,在新的窗口展示查询结果.(当然 ...

  3. 使用 GMap.NET 实现添加标注、移动标注功能。(WPF版)

    前言 在WPF嵌入地图,有两种方式: 浏览器方式:控件方式. 1)浏览器方式就是使用浏览器控件WebBrowser,设置好网址就行了.这种方式与地图的交互不太直接,需要懂html.javascript ...

  4. 使用GMap.NET类库,实现地图轨迹回放。(WPF版)

    前言 实现轨迹回放,GMap.NET有对应的类GMapRoute.这个类函数很少,功能有限,只能实现简单的轨迹回放.要实现更复杂的轨迹回放,就需要自己动手了. 本文介绍一种方法,可以实现复杂的轨迹回放 ...

  5. 【MEF】构建一个WPF版的ERP系统

    原文:[MEF]构建一个WPF版的ERP系统 引言 MEF是微软的一个扩展性框架,遵循某种约定将各个部件组合起来.而ERP系统的一大特点是模块化,它们两者的相性很好,用MEF构建一个ERP系统是相当合 ...

  6. wpf版扫雷游戏

    近来觉得wpf做出来的界面很拉风,自己也很喜欢搞些小游戏,感觉这做出来的会很炫,很装逼,(满足自己的一点小小的虚荣心)于是就去自学,发现感觉很不错,可是属性N多,太多了,而且质料也少,很多不会用,只会 ...

  7. GMap.NET实现电子围栏功能(WPF版)

    前言 GMap.NET是一个强大.免费.跨平台.开源的.NET控件.分为WPF和winform版.GMap.NET的基本知识不做过多介绍,本文主要介绍如何使用该控件实现电子围栏功能. 电子围栏主要有两 ...

  8. WPF版的权限管理系统

    好多技术人员都有一个通病,不关注用户的需求,产品的可用性,只看使用的技术的新不新,潮不潮,这就是所谓的技术发烧友. 这段时间,断断续续的开发一个WPF的软件,也拿出来Show一下.要不放在硬盘里就发霉 ...

  9. 一款高效视频播放控件的设计思路(c# WPF版)

    因工作的需要,开发了一款视频播放程序.期间也经历许多曲折,查阅了大量资料,经过了反复测试,终于圆满完成了任务. 我把开发过程中的一些思路.想法写下来,以期对后来者有所帮助. 视频播放的本质 就是连续的 ...

随机推荐

  1. Swift 语言概览 -自己在Xcode6 动手写2-tableView

    import UIKit class ViewController: UIViewController ,UITableViewDelegate, UITableViewDataSource { va ...

  2. HPE Comware Lab - Simulator

    http://h20565.www2.hpe.com/hpsc/swd/public/readIndex?sp4ts.oid=7107838&ac.admitted=1405352934644 ...

  3. 关于android 怎样安装 assets文件下的apk

    在自己的app中安装assets文件夹下的apk文件 public class MainActivity extends Activity { Context mContext; @Override ...

  4. 数据库使用truncate清理非常多表时碰到外键约束时怎么高速解决

    问题处理思路: 1. 先将数据库中涉及到外键约束的表置为无效状态 2.待清除全然部表数据后再将外键约束的表置为可用状态 详细实现脚本: declare begin for vv_sql in (SEL ...

  5. springmvc-Controller类的方法返回String不跳转

    买了本书,打算系统的学习一下spring,做了一下书中的练习,出现了一个问题,Controller类的方法返回String,但是页面不跳转,而是直接把字符串的内容显示到页面上. @RequestMap ...

  6. [React Router v4] Use the React Router v4 Link Component for Navigation Between Routes

    If you’ve created several Routes within your application, you will also want to be able to navigate ...

  7. java基础—网络编程———建立聊天的形式

    接收器和发射器的简单演示 import java.io.*; import java.net.*; public class SocketDemo { public static void main( ...

  8. JQuery通过radio,select改变隐藏显示div

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/qq_36092584/article/details/52740681 1)select下拉框控制d ...

  9. 项目启动部署时报错:java.lang.NoSuchMethodError

    报错: ================================================================================================ ...

  10. 《大话操作系统——扎实project实践派》(8.2)(除了指令集.完)