C# 如何使用mvvm从模型中填充wpf树视图;英文特;水平
我有一个自内的实体框架模型,在这个模型中,用户可以根据需要将子类别转换为子类别C# 如何使用mvvm从模型中填充wpf树视图;英文特;水平,c#,wpf,entity-framework,treeview,C#,Wpf,Entity Framework,Treeview,我有一个自内的实体框架模型,在这个模型中,用户可以根据需要将子类别转换为子类别 公共类类别 { 公共类别() { 子类别=新的ObservableCollection(); } [列(“id”)] 公共int Id{get;set;} [长度(100)] 公共字符串名称{get;set;} [列(“父ID”)] public int?ParentID{get;set;} [ForeignKey(“ParentID”)] 公共虚拟可观察集合子类别{get;set;} } 我正在考虑使用forea
公共类类别
{
公共类别()
{
子类别=新的ObservableCollection();
}
[列(“id”)]
公共int Id{get;set;}
[长度(100)]
公共字符串名称{get;set;}
[列(“父ID”)]
public int?ParentID{get;set;}
[ForeignKey(“ParentID”)]
公共虚拟可观察集合子类别{get;set;}
}
我正在考虑使用foreach填充树视图,如下所示:
Categories=newobserveCollection(db.Categories.Where(x=>x.ParentID==null));
foreach(类别中的var项目)
{
SubCategoriesModel=新的ObservableCollection(db.Categories.Where(x=>x.ParentID==item.Id));
foreach(子类别模型中的var子项)
{
项目。子类别。添加(子项目);
}
}
我意识到这是行不通的。有更好的方法吗?方法1 当您处理可能无限多的子级别时(例如,因为项目可以相互引用,并且在递归期间会导致无限循环),我建议在项目首次展开时填充这些项目 方法2 如果您没有递归,并且希望一次加载所有数据,那么只需通过递归方法加载即可(不过要小心,如果级别太深,可能会出现StackOverflowException)
示例方法1 对于这种情况,非常简单的viewmodel可能如下所示:
公共类节点
{
公共uint节点ID{get;set;}
公共字符串DisplayName{get;set;}
public bool ChildrenLoaded{get;set;}
公共可观测集合子项{get;set;}
公共节点()
{
ChildrenLoaded=false;
Children=新的ObservableCollection();
}
公共void LoadChildNodes()
{
如果(儿童加载)返回;
//例如,具有此节点ID的父ID的每个子类别
var newChildren=您的数据来自.LoadChildNodes(NodeId)的位置;
儿童。清除();
foreach(newChildren中的节点子节点)
添加(child);
ChildrenLoaded=true;
}
}
如下设置Treeview,其中节点
是您首先加载的一个或多个根节点。(Categories
,在您的示例中ParentId=null)
该事件是一个所谓的btw。它不是由TreeView触发的,而是TreeView本身,只是在你的视觉树上冒泡(这是它的实际技术术语,还有隧道和直接)
每当第一次展开节点时,只需加载TreeViewItem\u expanded
事件处理程序中的所有子节点即可
private void TreeViewItem\u已展开(对象发送方、路由目标方)
{
Node Node=((FrameworkElement)e.OriginalSource).DataContext作为节点;
if(node==null)返回;
LoadChildNodes();
}
因此,无论您有多少个项目,如果这些项目相互引用,您都只加载根节点,其他一切都会按需进行
将这一原则转化为您的具体示例,我只需将数据的加载方法拆分为根类别
条目,并在扩展的事件处理程序中加载子类别
,而不是预加载所有内容
由于您的大多数代码已经几乎相同,我认为这应该是一个相当简单的修改
示例方法2
private void LoadRootCategories()
{
Categories=newobserveCollection(db.Categories.Where(x=>x.ParentID==null));
foreach(类别中的var项目)
{
装载子类别(项目)
}
}
专用void loads子类别(类别项)
{
item.SubCategories=新的ObservableCollection(db.Categories.Where(x=>x.ParentID==item.Id));
foreach(项.子类别中的var子项)
{
//递归调用
装载子类别(子项);
}
}
@dymanoid很抱歉,这是一个输入错误,它只获取数据的一个级别,除非我想在前面重复foreach语句。我看到的唯一选项是在项目展开时加载它,而不是在此之前。
private void LoadRootCategories()
{
Categories = new ObservableCollection<Category>(db.Categories.Where(x => x.ParentID == null));
foreach (var item in Categories)
{
LoadSubCategories(item)
}
}
private void LoadSubCategories(Category item)
{
item.SubCategories = new ObservableCollection<Category>(db.Categories.Where(x => x.ParentID == item.Id));
foreach (var subitem in item.SubCategories)
{
// Recursive call
LoadSubCategories(subitem);
}
}