WPF 使用Popup和TreeView实现树状下拉框
效果如图
单选
<Grid Margin="15,5,0,15">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox Grid.Row="0" x:Name="singleHeader" Width="300" Height="30" PreviewMouseDown="singleHeader_PreviewMouseDown" HorizontalAlignment="Left" />
<Popup Grid.Row="1" x:Name="singlePopup" AllowsTransparency="True" IsOpen="False">
<TreeView x:Name="singleTree" ItemsSource="{Binding }" Initialized="singleTree_Initialized" SelectedItemChanged="singleTree_SelectedItemChanged">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" FontSize="18" Text="{Binding Name}" Margin="2,0,0,0"></TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Popup>
</Grid>
private void singleTree_Initialized(object sender, EventArgs e)
{
singleDataContext = new ObservableCollection<AdministrationViewModel>();
var beijing = new AdministrationViewModel() { Name = "北京市", Id = Guid.NewGuid().ToString() };
beijing.Children.Add(new AdministrationViewModel() { Name = "朝阳区", Id = Guid.NewGuid().ToString() });
beijing.Children.Add(new AdministrationViewModel() { Name = "海淀区", Id = Guid.NewGuid().ToString() });
beijing.Children.Add(new AdministrationViewModel() { Name = "通州区", Id = Guid.NewGuid().ToString() });
singleDataContext.Add(beijing);
var guangdong = new AdministrationViewModel() { Name = "广东省", Id = Guid.NewGuid().ToString() };
guangdong.Children.Add(new AdministrationViewModel() { Name = "汕尾市", Id = Guid.NewGuid().ToString() });
guangdong.Children.Add(new AdministrationViewModel() { Name = "中山市", Id = Guid.NewGuid().ToString() });
var guangzhou = new AdministrationViewModel() { Name = "广州市", Id = Guid.NewGuid().ToString() };
guangzhou.Children.Add(new AdministrationViewModel() { Name = "越秀区", Id = Guid.NewGuid().ToString() });
guangzhou.Children.Add(new AdministrationViewModel() { Name = "海珠区", Id = Guid.NewGuid().ToString() });
guangzhou.Children.Add(new AdministrationViewModel() { Name = "番禺区", Id = Guid.NewGuid().ToString() });
guangdong.Children.Add(guangzhou);
singleDataContext.Add(guangdong);
var trv = sender as TreeView;
trv.DataContext = singleDataContext;
}
private void singleTree_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
var trv = sender as TreeView;
var trvItem = trv.SelectedItem as AdministrationViewModel;
//这里是否被选择的条件为是否为叶子结点,也可以使用AdministrationViewModel中的属性灵活控制
if (trvItem.Children.Count != 0) return;
singleHeader.Text = trvItem.Name.ToString();
singlePopup.IsOpen = false;
}
private void singleHeader_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
singlePopup.Placement = System.Windows.Controls.Primitives.PlacementMode.RelativePoint;
singlePopup.VerticalOffset = singleHeader.Height;
singlePopup.StaysOpen = true;
singlePopup.Height = singleTree.Height;
singlePopup.Width = singleHeader.Width;
singlePopup.IsOpen = true;
}
多选
<Grid Margin="15,5,0,15">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox Grid.Row="0" x:Name="multiHeader" Width="300" Height="30" PreviewMouseDown="multiHeader_PreviewMouseDown" HorizontalAlignment="Left" />
<Popup Grid.Row="1" x:Name="multiPopup" AllowsTransparency="True" IsOpen="False">
<StackPanel Orientation="Vertical">
<TreeView x:Name="multiTree" ItemsSource="{Binding }" Initialized="multiTree_Initialized">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsChecked,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding IsCanChecked,Mode=OneWay}" Checked="CheckBox_CheckedOrUncheck" Unchecked="CheckBox_CheckedOrUncheck"></CheckBox>
<TextBlock VerticalAlignment="Center" FontSize="18" Text="{Binding Name}" Margin="2,0,0,0"></TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<Button Content="Close(关闭)" Click="CloseMultiPopup_Click"></Button>
</StackPanel>
</Popup>
</Grid>
private void multiHeader_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
multiPopup.Placement = System.Windows.Controls.Primitives.PlacementMode.RelativePoint;
multiPopup.VerticalOffset = multiHeader.Height;
multiPopup.StaysOpen = true;
multiPopup.Height = multiTree.Height;
multiPopup.Width = multiHeader.Width;
multiPopup.IsOpen = true;
}
private void multiTree_Initialized(object sender, EventArgs e)
{
multiDataContext = new ObservableCollection<AdministrationViewModel>();
var beijing = new AdministrationViewModel() { Name = "北京市", Id = Guid.NewGuid().ToString() };
beijing.Children.Add(new AdministrationViewModel() { Name = "朝阳区", Id = Guid.NewGuid().ToString(),IsCanChecked=true });
beijing.Children.Add(new AdministrationViewModel() { Name = "海淀区", Id = Guid.NewGuid().ToString(), IsCanChecked = true });
beijing.Children.Add(new AdministrationViewModel() { Name = "通州区", Id = Guid.NewGuid().ToString() });
multiDataContext.Add(beijing);
var guangdong = new AdministrationViewModel() { Name = "广东省", Id = Guid.NewGuid().ToString() };
guangdong.Children.Add(new AdministrationViewModel() { Name = "汕尾市", Id = Guid.NewGuid().ToString(), IsCanChecked = true });
guangdong.Children.Add(new AdministrationViewModel() { Name = "中山市", Id = Guid.NewGuid().ToString(), IsCanChecked = true });
var guangzhou = new AdministrationViewModel() { Name = "广州市", Id = Guid.NewGuid().ToString() };
guangzhou.Children.Add(new AdministrationViewModel() { Name = "越秀区", Id = Guid.NewGuid().ToString(), IsCanChecked = true });
guangzhou.Children.Add(new AdministrationViewModel() { Name = "海珠区", Id = Guid.NewGuid().ToString(), IsCanChecked = true });
guangzhou.Children.Add(new AdministrationViewModel() { Name = "番禺区", Id = Guid.NewGuid().ToString(), IsCanChecked = true });
guangdong.Children.Add(guangzhou);
multiDataContext.Add(guangdong);
var trv = sender as TreeView;
trv.DataContext = multiDataContext;
}
private static void GetSelectList(List<AdministrationViewModel> selectList, AdministrationViewModel item)
{
if(item.Children!=null)
{
foreach (var child in item.Children)
{
if (child.IsCanChecked && child.IsChecked)
selectList.Add(child);
GetSelectList(selectList, child);
}
}
}
private void CheckBox_CheckedOrUncheck(object sender, RoutedEventArgs e)
{
var trv = multiTree;
var data = trv.DataContext as ObservableCollection<AdministrationViewModel>;
//获得所有被勾选的选项:这里使用IsChecked和IsCanChecked进行判断->可以根据业务改为其他的逻辑
var selectList = new List<AdministrationViewModel>();
foreach (var item in data)
{
if (item.IsCanChecked && item.IsChecked)
selectList.Add(item);
GetSelectList(selectList, item);
}
var selectStr = "";
foreach (var item in selectList)
{
selectStr += item.Name + ",";
}
selectStr = selectStr.TrimEnd(',');
multiHeader.Text = selectStr;
}
private void CloseMultiPopup_Click(object sender, RoutedEventArgs e)
{
multiPopup.IsOpen = false;
}
示例代码
参考资料
学习技术最好的文档就是【官方文档】,没有之一。
还有学习资料【Microsoft Learn】、【CSharp Learn】、【My Note】。
如果,你认为阅读这篇博客让你有些收获,不妨点击一下右下角的【推荐】按钮。
如果,你希望更容易地发现我的新博客,不妨点击一下【关注】。