在ComboBox中嵌套TreeView控件,有时候我们在设计界面的时候,由于界面设计的需要,我们需要将TreeView控件嵌套在ComboBox中,因为TreeView控件实在是太占用地方了,要想实现这样的功能,我们需要修改ComboBox控件的模板,这里贴出相关的代码,并进行分析:既然要将TreeView嵌套到ComboBox中,那么我们必须要修改ComboBoxItem的模板,在这里我们修改 ComboBoxItem的控件模板,同时我们也需要修改TreeView的ItemTemplate模板,我们定义了两部分,左边的部分是一个宽和高都为13 的小正方体,里面通过Path属性画上了一个对勾,这个是模拟CheckBox属性来定义的,并且通过代码来改变其Visibility属性。然后再定义一个TextBlock,用于显示文字部分,在这里我们同时使用了HierarchicalDataTemplate(分层数据模板),这个模板是使用非常多的一种模板。
<ComboBox x:Name="comboBox" SelectionChanged="comboBox_SelectionChanged">
<ComboBoxItem Content="{Binding Name}" Visibility="Collapsed"/>
<ComboBoxItem x:Name="comTree" FocusVisualStyle="{x:Null}">
<ComboBoxItem.Template>
<ControlTemplate>
<TreeView Name="treeView" ItemsSource="{Binding TreeViewItems}" SelectedValuePath="DataName" DisplayMemberPath="DataName" Margin="0" SelectedItemChanged="treeView_SelectedItemChanged" BorderThickness="0">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Items}">
<StackPanel Orientation="Horizontal" Margin="0,1">
<Grid Height="13" Width="13" VerticalAlignment="Center" Margin="2,0,0,0">
<Border BorderBrush="#5c8200" BorderThickness="1"/>
<Path Stroke="#5c8200" StrokeThickness="1" Data="M 2,7 5,11 11,2" Visibility="{Binding Visibility}"/>
</Grid>
<TextBlock Text="{Binding Name}" Margin="2,0,0,0"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</ControlTemplate>
</ComboBoxItem.Template>
</ComboBoxItem>
</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;
}
}
其它的细节部分请参考整个工程。