原文連結:https://www.cnblogs.com/larissa-0464/p/10227483.html
資料繫結:
更新內容:補充在MVVM模式上的TreeView控制元件資料繫結的程式碼。
xaml程式碼:
<TreeView Name="syntaxTree" ItemsSource="{Binding TreeNodes}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:TreeNode}" ItemsSource="{Binding Path=ChildNodes}">
<TextBlock Text="{Binding NodeName}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
TreeView中的ItemsSource繫結的是一個名為TreeNodes的TreeNode的列表,即List<TreeNode>TreeNodes。HierarchicalDataTemplate中的ItemsSource繫結的TreeNodes中的每個節點的ChildNodes屬性。
ViewModel.cs中的程式碼(有刪減):
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private List<TreeNode> treenodes = new List<TreeNode>();
public List<TreeNode> TreeNodes
{
get { return treenodes; }
set
{
treenodes = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("TreeNodes"));
}
}
public ViewModel()
{
// Nodes是我已經獲得的一組節點
TreeNodes = getChildNodes(0,Nodes);
}
private List<TreeNode> getChildNodes(int parentID, List<TreeNode> nodes)
{
List<TreeNode> mainNodes = nodes.Where(x => x.ParentID == parentID).ToList();
List<TreeNode> otherNodes = nodes.Where(x => x.ParentID != parentID).ToList();
foreach (TreeNode node in mainNodes)
node.ChildNodes = getChildNodes(node.NodeID, otherNodes);
return mainNodes;
}
}
使用MVVM模式,那麼xaml.cs檔案就會變得非常簡單了,基本只有一句程式碼了:
this.DataContext = new ViewModel();
該模式的好處就是使得UI設計和後端程式碼分開,只透過資料繫結進行連線。嘗試用了幾次,真的還蠻方便。
TreeView資料繫結需要使用層次結構資料模板(HierarchicalDataTemplate)來顯示分層資料。XAML程式碼如下:
<TreeView Name="chapterTree" Grid.Column="0">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=ChildNodes}">
<StackPanel>
<Label Content="{Binding Path=NodeName}"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
其中,ItemsSource繫結的物件ChildNodes應該是一個集合型別:List<TreeNode>,Label中繫結的是TreeNode的NodeName屬性,TreeNode類定義如下所示:
public class TreeNode
{
public int NodeID { get; set; }
public int ParentID { get; set; }
public string NodeName { get; set; }
public List<TreeNode> ChildNodes { get; set; }
public TreeNode()
{
ChildNodes = new List<TreeNode>();
}
}
因為是樹形結構,因此TreeNode需要有NodeID屬性和ParentID屬性,即某個樹節點node本身的ID和它所屬的父節點的ID。以目錄為例,則xaml.cs中的程式碼如下。首先是寫入了資料,在我實際專案中,這些資料是從DB中查詢的,這裡為了簡化,直接Input資料了。
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
InputData();
chapterTree.ItemsSource = getNodes(0, nodes);
}
private List<TreeNode> nodes;
private void InputData()
{
nodes = new List<TreeNode>()
{
new TreeNode(){ParentID=0, NodeID=1, NodeName = "Chapter1" },
new TreeNode(){ParentID=0, NodeID=2, NodeName="Chapter2"},
new TreeNode(){ParentID=0,NodeID=3, NodeName="Chapter3"},
new TreeNode(){ParentID=1, NodeID=4, NodeName="Section1.1"},
new TreeNode(){ParentID=1, NodeID=5, NodeName="Section1.2"},
new TreeNode(){ParentID=2, NodeID=6, NodeName="Section2.1"},
new TreeNode(){ParentID=3, NodeID=7, NodeName="Section3.1"},
new TreeNode(){ParentID=6, NodeID=8, NodeName="SubSection2.1.1"},
new TreeNode(){ParentID=6, NodeID=9, NodeName="SubSection2.1.2"},
new TreeNode(){ParentID=2, NodeID=10,NodeName="Section2.2"},
new TreeNode(){ParentID=3, NodeID=11, NodeName="Section3.2"}
};
}
private List<TreeNode> getNodes(int parentID, List<TreeNode> nodes)
{
List<TreeNode> mainNodes = nodes.Where(x => x.ParentID == parentID).ToList();
List<TreeNode> otherNodes = nodes.Where(x => x.ParentID != parentID).ToList();
foreach (TreeNode node in mainNodes)
node.ChildNodes = getNodes(node.NodeID, otherNodes);
return mainNodes;
}
}
需要注意的就是NodeID是不斷增加的,每個節點都有自己的ID,而其ParentID就看它是屬於哪個父節點的了。getNodes()是一個遞迴方法,就是不斷讀取某個節點的子節點。執行結果如圖所示:
後臺動態新增TreeView:
一開始,沒用資料繫結,就直接在xaml.cs中使用treeview,雖然後來用了資料繫結之後發現還是繫結更方便,但是這種在後臺構建treeview的方法沒準哪天也能用到,就記錄一下吧。
XAML檔案,使用一個TreeView控制元件
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60*"/>
<ColumnDefinition Width="100*"/>
</Grid.ColumnDefinitions>
<TreeView Name="chapterTree" Grid.Column="0"/>
</Grid>
XAML.CS檔案,同樣使用遞迴方法,就是不斷的新建treeviewitem控制元件。
public partial class DynamicTreeView : Window
{
public DynamicTreeView()
{
InitializeComponent();
InputData();
ShowTreeView();
}
private List<TreeNode> nodes;
private void InputData()
{
nodes = new List<TreeNode>()
{
new TreeNode(){ParentID=0, NodeID=1, NodeName = "Chapter1" },
new TreeNode(){ParentID=0, NodeID=2, NodeName="Chapter2"},
new TreeNode(){ParentID=0,NodeID=3, NodeName="Chapter3"},
new TreeNode(){ParentID=1, NodeID=4, NodeName="Section1.1"},
new TreeNode(){ParentID=1, NodeID=5, NodeName="Section1.2"},
new TreeNode(){ParentID=2, NodeID=6, NodeName="Section2.1"},
new TreeNode(){ParentID=3, NodeID=7, NodeName="Section3.1"},
new TreeNode(){ParentID=6, NodeID=8, NodeName="SubSection2.1.1"},
new TreeNode(){ParentID=6, NodeID=9, NodeName="SubSection2.1.2"},
new TreeNode(){ParentID=2, NodeID=10,NodeName="Section2.2"},
new TreeNode(){ParentID=3, NodeID=11, NodeName="Section3.2"}
};
}
private void ShowTreeView()
{
TreeViewItem tv1 = new TreeViewItem();
chapterTree.Items.Add(tv1);
GetNodes(0, tv1);
}
private void GetNodes(int parentID, TreeViewItem tv)
{
List<TreeNode> mainNodes = nodes.Where(x => x.ParentID == parentID).ToList();
foreach(var item in mainNodes)
{
TreeViewItem tv1 = new TreeViewItem();
tv1.Header = item.NodeName;
tv.Items.Add(tv1);
GetNodes(item.NodeID, tv1);
}
}
}
執行圖:總歸是沒有databinding方便。剛開始學習WPF,一開始沒想過要用資料繫結,總感覺只要能實現自己想要的東西就可以了,不用管實現過程,後來使用了之後發現,使用資料繫結構建MVVM架構的應用還是挺好的。
第二部分將總結給節點新增事件的方法。
https://www.cnblogs.com/larissa-0464/p/12441607.html
關於TreeView控制元件的demo:
WPF中常用控制元件(TreeView, ComboBox, DataGrid, ListView)使用MVVM模式繫結的demo - 南風小斯 - 部落格園 (cnblogs.com)