WPF中下拉框可作選擇項也可以作為隻讀文本框使用的方法
1、需求
當前在開發的系統需要一個這樣的控件。
(1)可以選擇已有的選擇項,類似於ComboBox選擇;
(2)可以通過其他按鈕點擊,選擇一個文件,選擇後,把文件路徑顯示到控件上,並且處於隻讀狀態,行為和隻讀狀態下的TextBox保持一致。
更直觀些,就是實現類似ArcMap中Toolbox中的數據集選擇下拉框,如下圖所示。
該控件可以通過下拉的方式,選擇左側的圖層數據,又可以通過點擊右側的打開文件按鈕,彈出打開文件對話框,選擇要設置的數據文件。該控件還可以通過鍵盤輸入,但我們的需求是禁止輸入,隻能選擇和通過打開文件對話框設置。
2、現有的ComboBox
我計劃在WPF中的ComboBox控件的基礎上進行開發,首先看通過簡單的屬性設置是否能夠滿足要求。
(1)不設置任何參數
在不設置任何參數的情況下,效果如下圖所示。
可以顯示底圖上加載的數據,但點擊【Select】按鈕,通過設置ComboBox.Text屬性,數據顯示不出來,這種效果離我們想要的還差十萬八千裡。
(2)設置ComboBox.IsEditable=true
下面我們嘗試通過設置ComboBox的屬性看能不能達到我們想要的效果。首先把ComboBox.IsEditable屬性設置為true,然後測試下Text屬性設置後是否有效果瞭。
目前可以把選擇的文件路徑設置到ComboBox.Text瞭,並且可以正常顯示,但鼠標點上去,文本框的內容可以修改,這不是我們想要的。於是發現ComboBox有個IsReadOnly屬性,把該屬性設置為true嘗試一下試試。
目前下拉框中的內容不能修改瞭,但實際操作的時候會發現有些別扭。當鼠標點擊下拉框,該控件得到焦點的時候,裡面的文字默認處於全選狀態,此時想拖動鼠標,把文字拖動到尾部是操作不瞭的,隻能再次點擊下拉框中的內容,才可以和普通文本框的操作一樣通過鼠標拖動視圖。
經過各種嘗試,發現當ComboBox控件GotFocus的時候,裡面的文字會默認處於全選狀態,這個我們需要解決一下。
3、使用VisualTreeHelper單獨處理TextBox
在網上查詢,發現ComboBox在IsEditable=true的狀態下,是有很多個控件組合而成的。如下圖所示。
我們可以調用VisualTreeHelper,獲取這個TextBox,不過需要在Load後,再調用,不然這些控件是獲取不到的。
this.Loaded += (x, y) => { var myMainGrid = VisualTreeHelper.GetChild(this, 0); var myTextBox = VisualTreeHelper.GetChild(myMainGrid, 4) as TextBox; myTextBox.IsReadOnly = true; myTextBox.IsReadOnlyCaretVisible = true; };
獲取TextBox後,我們需要解決ComboBox激活後,文字全選的問題。代碼如下。
myTextBox.GotFocus += (m, n) => { myTextBox.SelectionOpacity = 0; this._IsNeedClearSelection = true; };
該代碼的的作用是當TextBox得到焦點後,立刻把TextBox中文字選中的背景顏色的透明度設置為0,這樣操作者就感覺不出來文字被選中瞭。
鼠標左鍵彈起前,需要清空選中文字,並把光標放到鼠標點擊處,並還原文本選中的顏色,代碼如下。
myTextBox.PreviewMouseLeftButtonUp += (m, n) => { if (this._IsNeedClearSelection == false) { return; } var myPosition = n.GetPosition(myTextBox); int mySelectionStart = myTextBox.GetCharacterIndexFromPoint(myPosition, true); myTextBox.Select(mySelectionStart, 0); this._IsNeedClearSelection = false; myTextBox.SelectionOpacity = 0.4; };
此時,基本上ComboBox能夠滿足我們的需求瞭,效果如下圖所示。
但還有一個問題,就是在ComboBox在IsEditable=true的狀態下,鼠標移動到可選項上的時候,選擇項不高亮瞭。為瞭解決這個問題,嘗試瞭很多方法,都不行,準備放棄,就這樣瞭。
因為系統使用瞭DEV for WPF UI庫,忽然想到瞭WPF DEV中的ComboBoxEdit,之前測試過,通過設置屬性,滿足不瞭需求。但沒有使用VisualTreeHelper深入的去測試,那就再嘗試下看看。
4、使用WPF DEV中的ComboBoxEdit
測試的時候,ComboBoxEdit在任何屬性都不設置的情況下,除瞭文字可以編輯,其他的都可以滿足要求。於是我設置IsReadOnly=True,但這個時候,下拉框中的可選擇項都處於不可用狀態,也不能選擇,所以IsReadOnly屬性不能設置成True。嘗試瞭一下有可能性的其他屬性,例如EditMode等,都不能滿足需求。
但在測試ComboBox的時候,知道瞭WPF的可視化樹這個概念,可以通過VisualTreeHelper獲取組成控件的子控件。於是加載後,在Load事件中,我們查看下ComboBoxEdit組織樹,如下圖所示。
我看到瞭裡面有個TextBox控件,這個就是顯示文本的控件瞭,感覺是不是獲取到這個TextBox後,把該TextBox設置成隻讀是不是問題就完美解決瞭?
這個樹比較深,我就找瞭一段根據類型獲取元素的代碼,如下圖所示。
public static List<T> FindVisualChild<T>(DependencyObject pDependencyObject) where T : DependencyObject { List<T> myTList = new List<T> { }; for (int i = 0; i < VisualTreeHelper.GetChildrenCount(pDependencyObject); i++) { DependencyObject myChild = VisualTreeHelper.GetChild(pDependencyObject, i); if (myChild != null && myChild is T myT) { myTList.Add(myT); List<T> myChildOfChildren = FindVisualChild<T>(myChild); if (myChildOfChildren != null) { myTList.AddRange(myChildOfChildren); } } else { List<T> myChildOfChildren = FindVisualChild<T>(myChild); if (myChildOfChildren != null) { myTList.AddRange(myChildOfChildren); } } } return myTList; }
獲取TextBox和設置其屬性的代碼如下。
public class DatasetComboBoxExUI : ComboBoxEdit { public DatasetComboBoxExUI() { this.Loaded += (x, y) => { List<TextBox> myTextBoxList = VisualTreeExHelper.FindVisualChild<TextBox>(this); if (myTextBoxList.Count == 0) { return; } var myTextBox = myTextBoxList[0]; myTextBox.IsReadOnly = true; myTextBox.IsReadOnlyCaretVisible = true; }; } }
啟動測試,效果非常完美,正是我們需要的,界面如下圖所示。
5、總結
最開始測試Dev中的ComboBoxEdit,通過設置屬性各種嘗試,發現滿足不瞭需求。既然ComboBoxEdit滿足不瞭需求,那就在WPF原生態的ComboBox上測試吧。
在ComboBox嘗試的時候,也是設置ComboBox的屬性,各種測試後,發現還是不行。在網上搜索的時候,發現可以通過VisualTreeHelper獲取組成ComboBox的UI樹,從而對其內部的控件進行操作。VisualTreeHelper之前也用過,但這次確實沒往這塊想。
通過VisualTreeHelper獲取ComboBox中的TextBox,通過各種嘗試,終於達到瞭一個比較滿意的效果,此時已經花瞭一下午的時間。晚上下班回傢後,想把這個過程整理一下,使用的時候,發現ComboBox在IsEditable=true的狀態下,鼠標移動到可選項上的時候,選擇項不高亮瞭。於是想把這個問題再解決下,以達到最完美效果。
但花瞭兩個小時左右,一點思路也沒有,在網上也沒找到相關的資料。此時忽然想到,此前測試Dev中的ComboBoxEdit時候,還沒想到VisualTreeHelper這個方法,所以還沒測試,那就測試下看看。
於是修改瞭代碼,查看瞭下ComboBoxEdit的可視化樹,發現裡面有個TextBox,此時感覺希望非常大,因為當時放棄ComboBoxEdit是因為顯示的內容可編輯,又不能設置ComboBoxEdit的IsReadOnly屬性為True。現在看到ComboBoxEdit裡面有個TextBox,就感覺八九不離十瞭。如果獲取到TextBox,把這個TextBox的IsReadOnly屬性為True不就可以瞭?
於是按照這個思路嘗試瞭一下,最後效果非常完美,完全滿足系統要求。
到此這篇關於WPF中下拉框可作選擇項也可以作為隻讀文本框使用的方法的文章就介紹到這瞭,更多相關WPF下拉框使用內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!