關於WPF中TextBox行的選擇與顯示的問題

        最近做了一個小工具,其中用到了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運行時需要做某些處理,因此,此時去獲取指定行的文本長度或文本內容則容易出現問題。另外,認爲文本內容滾動之後對於在可視範圍內顯示的文本相對於文本框的上邊界的距離發生了變化,這也有可能是一個因素。不知道猜測是否正確,還希望各位大俠、專家給予指正,也好將其原理分享給其他程序員朋友。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章