关于WPF中TextBox行的选择与显示的问题

声明:本文是本人在51CTO上的一篇博文,今天打算将其转载到博客园,以方便自己查阅。原文地址为:http://kestrelsaga.blog.51cto.com/3015222/1542584

 

         最近做了一个小工具,其中用到了WPF中的TextBox控件。对于这个控件的使用,其中主要的一个功能是需要选择指定的行,并将其显示在控件可见区域的视图中(如果不在可视区域时,需要控件自动滚动到改行)。在我使用时,发现一个问题,如果当我先将指定的行滚动至视图中,然后在将其选中,则经常会不稳定,有时能定位并选中,有时则会选中错误位置,或者报错。现在我想将我遇到的问题以代码的方式进行说明,以及我的解决方案。不过,目前其原因还未搞明白,如果有高人,还请给予指点。

        首先,在自定义控件中添加一个TextBox控件,命名为txtBoxDocument,并在控件中提供两个公共方法GoToLine(int rowIndex)和SelectedLine(int rowIndex),用来定位并滚动至指定行和选中改行。

 

/// <summary>

        /// 定位到指定行

        /// </summary>

        /// <param name="rowIndex">指定的从零开始的行的索引</param>

        public void GoToLine(int rowIndex)

        {

            txtBoxDocument.ScrollToLine(rowIndex);

        }

         

        /// <summary>

        /// 选中指定的行

        /// </summary>

        /// <param name="rowIndex">指定的从零开始的行的索引</param>

        public void SelectedLine(int rowIndex)

        {

            try

            {

                int lineLength = txtBoxDocument.GetLineLength(rowIndex);

                int start = txtBoxDocument.GetCharacterIndexFromLineIndex(rowIndex);

                 

                txtBoxDocument.Focus();

                txtBoxDocument.Select(start, lineLength);

            }

            catch { }

        }

 

  然后,我们在调用这两个方法(假设我们使用一个Button调用,并在TextBox中指定要跳转至的行),Button命名为:btnGoTo,该文本框命名为txtBoxLineNum

private void btnGoTo_Click(object sender, RoutedEventArgs e)

        {

            int rowIndex = 0;

            if(int.TryParse(txtBoxLineNum.Text,rowIndex))

            {

                //先选择,再跳转至指定位置(这种使用方式没问题)

                SelectedLine(rowIndex );

                GoToLine(rowIndex );

            }

        }

  如果将上面的调用方式改成下面情况,则会在SelectedLine(int rowIndex)方法的int lineLength = txtBoxDocument.GetLineLength(rowIndex);这句话出现问题,得出的lineLength不一定就是指定行的文本长度了,有可能是负值。错误的调用方式如下:

 

        private void btnGoTo_Click(object sender, RoutedEventArgs e)

        {

            int rowIndex = 0;

            if(int.TryParse(txtBoxLineNum.Text,rowIndex))

            {

                //先跳转定位,再选择(这种使用方式不稳定)

                GoToLine(rowIndex );

                SelectedLine(rowIndex );

            }

        }

 

  如果将SelectedLine(int rowIndex)方法中的获取指定行的文本长度的方式改为先获取其内容,再计算长度(int lineLength = txtBoxDocument.GetLineText(rowIndex).Length;),则经常会报错。下面是改后的SelectedLine(int rowIndex):

 

        /// <summary>

        /// 选中指定的行

        /// </summary>

        /// <param name="rowIndex">指定的从零开始的行的索引</param>

        public void SelectedLine(int rowIndex)

        {

            try

            {

                //采用错误的调用方式,下面这句话会报错(错误信息如下面贴出的图片所示)

                int lineLength = txtBoxDocument.GetLineText(rowIndex).Length;

                int start = txtBoxDocument.GetCharacterIndexFromLineIndex(rowIndex);

                 

                txtBoxDocument.Focus();

                txtBoxDocument.Select(start, lineLength);

            }

            catch { }

        }

wKioL1P0UNGxkvGKAAG8pq7ITA8780.jpg

错误内容:当前方法的代码已经过优化,因此无法计算表达式的值。

        但是,采用正确的调用顺序的方式不论是GetLineText(rowIndex).Length方式获取指定行的文本长度还是使用GetLineLength(rowIndex)方式获取指定行的文本长度,都是没问题的。具体缘由尚不明确,也没有查到相关的资料介绍。我自己的理解是在进行ScrollToLine(rowIndex)操作之前,先选中指定行的文本,此时,文本内容没有进行滚动,是个静止的状态,当先进行滚动在去选中指定文本,文本内容是个动态滚动的,可能此时.NET运行时需要做某些处理,因此,此时去获取指定行的文本长度或文本内容则容易出现问题。另外,认为文本内容滚动之后对于在可视范围内显示的文本相对于文本框的上边界的距离发生了变化,这也有可能是一个因素。不知道猜测是否正确,还希望各位大侠、专家给予指正,也好将其原理分享给其他程序员朋友。

 

posted @ 2015-03-20 16:17  Ke.Saga  阅读(2918)  评论(1编辑  收藏  举报