在ComboBox中嵌套TreeView控件,有时候我们在设计界面的时候,由于界面设计的需要,我们需要将TreeView控件嵌套在ComboBox中,因为TreeView控件实在是太占用地方了,要想实现这样的功能,我们需要修改ComboBox控件的模板,这里贴出相关的代码,并进行分析:既然要将TreeView嵌套到ComboBox中,那么我们必须要修改ComboBoxItem的模板,在这里我们修改 ComboBoxItem的控件模板,同时我们也需要修改TreeView的ItemTemplate模板,我们定义了两部分,左边的部分是一个宽和高都为13 的小正方体,里面通过Path属性画上了一个对勾,这个是模拟CheckBox属性来定义的,并且通过代码来改变其Visibility属性。然后再定义一个TextBlock,用于显示文字部分,在这里我们同时使用了HierarchicalDataTemplate(分层数据模板),这个模板是使用非常多的一种模板。
1 <ComboBox x:Name="comboBox" SelectionChanged="comboBox_SelectionChanged"> 2 <ComboBoxItem Content="{Binding Name}" Visibility="Collapsed"/> 3 <ComboBoxItem x:Name="comTree" FocusVisualStyle="{x:Null}"> 4 <ComboBoxItem.Template> 5 <ControlTemplate> 6 <TreeView Name="treeView" ItemsSource="{Binding TreeViewItems}" SelectedValuePath="DataName" DisplayMemberPath="DataName" Margin="0" SelectedItemChanged="treeView_SelectedItemChanged" BorderThickness="0"> 7 <TreeView.ItemTemplate> 8 <HierarchicalDataTemplate ItemsSource="{Binding Items}"> 9 <StackPanel Orientation="Horizontal" Margin="0,1"> 10 <Grid Height="13" Width="13" VerticalAlignment="Center" Margin="2,0,0,0"> 11 <Border BorderBrush="#5c8200" BorderThickness="1"/> 12 <Path Stroke="#5c8200" StrokeThickness="1" Data="M 2,7 5,11 11,2" Visibility="{Binding Visibility}"/> 13 </Grid> 14 <TextBlock Text="{Binding Name}" Margin="2,0,0,0"/> 15 </StackPanel> 16 </HierarchicalDataTemplate> 17 </TreeView.ItemTemplate> 18 </TreeView> 19 </ControlTemplate> 20 </ComboBoxItem.Template> 21 </ComboBoxItem> 22 </ComboBox>
在后台中我们需要封装一些类,这些类分别来实现不同的功能,首先是TreeData这个类,这个类主要是用来封装一些重要的属性,即每个TreeView的节点应该包含哪些数据,注意这个类必须实现INotifyPropertyChanged接口,并定义下面的事件和方法,以便在数据源更改时,能够将数据同步更新到UI,这个在使用时需要注意。
public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string prop) { if (this.PropertyChanged != null) this.PropertyChanged(this, new PropertyChangedEventArgs(prop)); }
另外,我们需要定义另外一个类 ViewModel类,用于初始化需要绑定到前台的数据,这是一个很典型的MVVM设计模式,在使用的时候需要特别注意,很多时候我们需要采用这种方式来实现前台和后台数据的绑定,当然我们也可以在该类中定义一些我们需要的数据和属性。
另外在我们的工程中,由于更改了ComboBox的样式,所以我们定义了一个用户控件,所有与combobox相关的操作都是在这个类中进行的,在MainWindow中我们只需要将这个用户控件引入到其中就可以了,关于这些设计其中的妙处,只有我们去细心领悟才能真正地体会到。另外整个工程中,非常重要的一个部分就是,当我们点击了TreeView节点之后,需要将数据反映到combobox上面,所以我们在ComboBox中添加了一个ComboBoxItem,这个就是 <ComboBoxItem Content="{Binding Name}" Visibility="Collapsed"/>,这个ComboBoxItem默认的状态是隐藏的,这个ComboBoxItem的Content属性是和Name属性绑定在一起的,当我们选择了TreeView的某一个节点之后,我们会把当前节点的Content值赋值给该Name属性,并且让ComboBox的 this.comboBox. SelectedIndex = 0;这样当我们点击了TreeView某个节点之后,就能是ComboBox显示当前节点名称,这里面涉及到两个重要的事件,下面贴出代码仅供参考。
private void treeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e) { if (this.selectedItem != null) this.selectedItem.Visibility = Visibility.Collapsed; this.SelectedItem = e.NewValue as TreeData; } private void comboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { this.comboBox.SelectedIndex = 0; }
这里我们定义了一个数SelectedItem属性。
/// <summary> /// 当前选中项的Data /// </summary> public TreeData SelectedItem { get { return selectedItem; } set { selectedItem = value; dataModel.ViewModeName = value.Name; value.Visibility = Visibility.Visible; } }
其它的细节部分请参考整个工程。