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);
    }
}