这周,咱们来玩目录树多选的应用,走起。
多选,我目前掌握两种种方法表示,比如改变节点颜色,在treeviewitem中添加复选框,当然,还是以通俗易懂的来讲解,本次我用的是第二种方法
开始还是老样子,如图(不做概述了)
来看下这次的目录树对象,稍微复杂点(有点长了就不截图了) ,看代码
public class TreeModel : BindableObject
{
private string name;
/// <summary>
/// 节点名字
/// </summary>
public string Name
{
get => name;
set
{
name = value;
OnPropertyChanged();
}
}
private bool? isCheck;
/// <summary>
/// 是否被选中(注:true是钩,false是空的,null是方块)
/// </summary>
public bool? IsCheck
{
get => isCheck;
set
{
isCheck = value;
OnPropertyChanged();
}
}
/// <summary>
/// 父节点
/// </summary>
public TreeModel Parent { get; set; }
/// <summary>
/// 子节点
/// </summary>
public ObservableCollection<TreeModel> Children { get; set; } = new ObservableCollection<TreeModel>();
}
接下来看view界面,也是直接上代码,没什么陌生的知识点,布局是一个treeview和一个button(注意需要这个Microsoft.Xaml.Behaviors.WPF包哈)
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<TreeView ItemsSource="{Binding Trees}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<CheckBox IsChecked="{Binding IsCheck, Mode=OneWay}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding DataContext.ClickCommand, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}" CommandParameter="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<TextBlock Grid.Column="1" Text="{Binding Name}" />
</CheckBox>
</Grid>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<Button
Grid.Row="1"
Height="60"
Command="{Binding ShowCommand}"
Content="选择后请点我" />
</Grid>
最后来看业务逻辑部分,看代码,没什么难的逻辑
public class TreeViewModel : BindableObject
{
/// <summary>
/// 目录树
/// </summary>
public ObservableCollection<TreeModel> Trees { get; set; }
/// <summary>
/// 存储勾选的节点
/// </summary>
public List<TreeModel> SelectItem { get; set; } = new List<TreeModel>();
/// <summary>
/// 点击节点命令
/// </summary>
public DelegateCommand<TreeModel> ClickCommand { get; private set; }
/// <summary>
/// 展示命令
/// </summary>
public DelegateCommand ShowCommand { get; private set; }
public TreeViewModel()
{
Trees = new ObservableCollection<TreeModel>();
ClickCommand = new DelegateCommand<TreeModel>(Click);
ShowCommand = new DelegateCommand(Show);
CreateTree();
}
/// <summary>
/// 初始化生成目录树
/// </summary>
public void CreateTree()
{
for (int i = 0; i < 3; i++)
{
TreeModel treeModel = new TreeModel()
{
Name = $"我是第{i}",
IsCheck = false,
};
for (int j = 0; j < 5; j++)
{
treeModel.Children.Add(new TreeModel()
{
Name = $"我是第{i}的第{j}个孩子",
IsCheck = false,
Parent = treeModel,
});
}
Trees.Add(treeModel);
}
}
public void Click(TreeModel param)
{
try
{
var result = Trees.FirstOrDefault(x => x.Name == param.Name);
if (result != null)
{
SelectAll(result);
}
else
{
Select(param);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
/// <summary>
/// 全选
/// </summary>
/// <param name="param"></param>
private void SelectAll(TreeModel param)
{
try
{
int count = 0;
List<TreeModel> lists = new List<TreeModel>();
foreach (var item in param.Children) //这里是获取之前点击了几个孩子
{
if (item.IsCheck == true)
{
count++;
}
else
{
lists.Add(item);
}
}
if (count == param.Children.Count) //相等表示之前是全选状态,现在为取消全选,否则反之
{
param.IsCheck = false;
foreach (var item in param.Children)
{
var result = SelectItem.FirstOrDefault(x => x.Name == item.Name);
if (result != null)
{
SelectItem.Remove(result);
item.IsCheck = false;
}
}
}
else
{
param.IsCheck = null;
foreach (var item in lists)
{
var result = SelectItem.FirstOrDefault(x => x.Name == item.Name);
if (result == null)
{
SelectItem.Add(item);
item.IsCheck = true;
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
/// <summary>
/// 单选
/// </summary>
/// <param name="param"></param>
private void Select(TreeModel param)
{
try
{
var result = SelectItem.FirstOrDefault(x => x.Name == param.Name);
var value = param.Parent;
if (result != null)//表示之前点击过,现在是取消选择,否则反之
{
var list = SelectItem.Where(x => x.Parent == value).ToList();
if (list.Count == value.Children.Count)//数量相等表示取消全选
{
value.IsCheck = false;
}
SelectItem.Remove(result);
param.IsCheck = false;
}
else
{
SelectItem.Add(param);
var list = SelectItem.Where(x => x.Parent == value).ToList();
if (list.Count == value.Children.Count)//数量相等表示全选
{
value.IsCheck = null;
}
param.IsCheck = true;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void Show()
{
MessageBox.Show($"已选择{SelectItem.Count}节点");
}
}
运行看结果图,如图
补充:
(1)这次案例需求简单,所有目录树就简单,但在实际开发中,得注意,最好给一个属性来区分不同的节点
(2)如果数据多了,超出设置界面的大小,这次我没有加滚动条控件(ScrollViewer),读者们可以自己加上,随便我给出滑轮实现滚动条滚动的代码
public void PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
try
{
ScrollViewer scrollviewer = sender as ScrollViewer;
if (e.Delta > 0)
{
scrollviewer.LineUp();
}
else
{
scrollviewer.LineDown();
}
e.Handled = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
(3)代码在这:https://github.com/TQtong/TreeViewExtensionApplication_1.git
结束:
希望能扩展你们的思想,那么咱们下周见,希望各位指出不足之处,