原文: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);        }    }

最新文章

  1. Java Lambda表达式初探
  2. 2015年12月12 Node.js实战(一)使用Express+MongoDB搭建多人博客
  3. 【系统移植】kernel分析
  4. sphinx下的max_matches取值对SetLimits的影响
  5. cocos2d-x 从onEnter、onExit、 引用计数 谈内存泄露问题
  6. centos下配置多个tomcat同时运行
  7. VBA 简单调试
  8. jsp生命周期和工作原理
  9. Node.js学习 - Modules
  10. apply和call的区别
  11. Python 字典(Dictionary) has_key()方法
  12. mysql 原理 ~ LRU 算法与buffer_pool
  13. selenium 无法启动IE
  14. 第二十九天- socketserver模块 ftp上传
  15. Java对称与非对称加密解密,AES与RSA
  16. org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[]
  17. php 利用http上传协议(表单提交上传图片 )
  18. tcpdump-根据IP查看程序与服务都用了哪些端口
  19. Jmeter-线程组执行顺序控制
  20. B-spline Curves 学习之B样条基函数的定义与性质(2)

热门文章

  1. php面试题四
  2. VMware Workstation 12 安装mac os x 10.11
  3. php实现 字符串加密(分类分布分工,化不可能为可能)
  4. notepad++ 正则替换
  5. 【41.43%】【codeforces 560C】Gerald's Hexagon
  6. java File类的基本使用
  7. Android 如何Android中自定义Navigationbar
  8. svn pre commit
  9. 数据库基本查询语句(SQL常用增删改查语句 简单复习 mark)
  10. Activity“ 阻止自动弹出软键盘”的方法 -尤其是对于Tab页下的!