在我們使用WPF設計前臺界面時,經常會重寫數據模板,或者把控制項放到數據模板里。但是一旦將控制項放到數據模板中,在後臺就沒有辦法通過控制項的名字來獲取它了,更沒辦法對它進行操作(例如,隱藏,改變控制項的某個值)。 如果你是比我還白的小白,對我剛剛陳述的東西不清楚,接下來我簡單說一下什麼是把控制項放在數據模板中 ...
在我們使用WPF設計前臺界面時,經常會重寫數據模板,或者把控制項放到數據模板里。但是一旦將控制項放到數據模板中,在後臺就沒有辦法通過控制項的名字來獲取它了,更沒辦法對它進行操作(例如,隱藏,改變控制項的某個值)。
如果你是比我還白的小白,對我剛剛陳述的東西不清楚,接下來我簡單說一下什麼是把控制項放在數據模板中,怎麼樣的情況沒法後臺通過名字來獲取控制項,如果讀者對於數據模板這些事兒已經清楚了,或者只關心如何使用可視化樹可以將這部分跳過哈。
先上代碼介紹一下什麼是數據模板以WPF中ListBox控制項為例:
<ListBox Name="ListBox_1" HorizontalAlignment="Left" Height="299" Margin="10,10,0,0" VerticalAlignment="Top" Width="497" MouseDoubleClick="ListBox_1_OnMouseDoubleClick">
<ListBox.ItemTemplate>
<DataTemplate>
<Button Name="Button_1" Content="666"></Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
我在後臺設置了顯示了8行item,效果如下:
我們可以看到重寫數據模板實現的效果是在ListBox的每一項Item都是一個Button,這裡介紹的只是一些簡單應用例子,重寫模板是很強大的。因為如果用到可視化樹多半是因為使用了數據模板在後臺用名字無法找到相應控制項了,所以在此簡單介紹一下,方便理解。
接下來我們在後臺嘗試通過控制項的名字來找到我們的ListBox和Button
我們發現通過控制項的名字可以找到ListBox但是通過button的名字卻無法找到button,這就是數據模板搞的鬼。
但是沒有關係,我們可以通過可視化樹從ListBox里找到它的子控制項我們想要的這個Button。
重點來了,先上代碼,可視化樹通過父控制項找到它的子控制項:
List<T> FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
{
try
{
List<T> list = new List<T>();
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child is T)
{
list.Add((T)child);
List<T> childOfChildren = FindVisualChild<T>(child);
if (childOfChildren != null)
{
list.AddRange(childOfChildren);
}
}
else
{
List<T> childOfChildren = FindVisualChild<T>(child);
if (childOfChildren != null)
{
list.AddRange(childOfChildren);
}
}
}
return list;
}
catch (Exception)
{
//MessageBox.Show(ee.Message);
return null;
}
}
先將上面的方法複製到你的項目當中,此時對於可視化樹的應用已經完成一半了。
接下來上代碼,通過可視化樹雙擊ListBox的ltem把對應的button的Content值從666改成777:
private void ListBox_1_OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
ListBoxItem myListBoxItem = (ListBoxItem)ListBox_1.ItemContainerGenerator.ContainerFromItem(ListBox_1.SelectedItem);
List<Button> btnList = FindVisualChild<Button>(myListBoxItem);
foreach (var item in btnList)
{
item.Content = "777";
}
}
效果就是雙擊哪個item哪個item中的button從666變成了777。
我們通過父控制項找到了裡面的子控制項button,我們便可以對它進行任何操作(和用名字找到是一樣的)。
以上關於可視化樹的代碼可以應用於ListBox,DataGrid,ListView,TreeView,對於“.ItemContainerGenerator.ContainerFromItem”這段代碼的含義我暫時不是很理解,歡迎指教和交流。
通過以上的例子相信讀者已經可以使用可視化樹找到相應的控制項了,但在我的開發過程中曾遇到過一些問題,和對於使用可視化樹的一點小建議。
1.如果你在使用可視化樹執行“ListBoxItem myListBoxItem = (ListBoxItem)ListBox_1.ItemContainerGenerator.ContainerFromItem(ListBox_1.SelectedItem);”這句返回值是空(實際上不是空),可能是因為界面沒有初始化完畢,我的理解是,在前臺這個控制項還沒生成完畢,或者是你修改了值但前臺還沒有修改,可以加上這句:
控制項名.UpdateLayout();
之後在使用可視化樹,這一條的說法和形容可能有點不嚴謹,歡迎指正交流。
2.可視化樹使用的是遞歸的方法,所以它的效率不是很高,如果在程式中大量使用可視化樹,會使得程式變慢的。
3.調用可視化樹返回的列表如果沒有找到相應的控制項或是異常便會返回空值,所以建議在你遍歷可視化樹返回的列表時,請先判斷否非為空。
以上內容歡迎指正交流,還是小白。
2018.8.15下午五點半多兩分