分层代码首先EF绑定到WPF Treeview ...不可能 [英] Hierarchical Code First EF Binding to WPF Treeview... Impossible

查看:220
本文介绍了分层代码首先EF绑定到WPF Treeview ...不可能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在过去,我不得不诉诸于使用DataSets和DataTables,因为使用Binding仍然阻止我...

In the past, I had to resort to using DataSets and DataTables, as doing it with Binding still eludes me...

顶级:我在VB 2012中创建了一系列课程,对它们进行了注释,并使用Code First在EF6中编写了EF模型。这个想法是表示路由器配置,配置的子部分是子节点到主要部分。很简单的想法

Top Level: I created a series of classes in VB 2012, annotated them, and crated the EF model in EF6 using Code First. The idea is to represent router configs, with sub-sections of the config being children to the major sections. Very simple idea.

原理:使用简单的WPF Treeview,说明在路由器中显示(逻辑上)的配置部分和子部分。

Rationale: With a simple WPF Treeview, illustrate the config sections and subsections as they appear (logically) in the router.

我已经开始非常简单地使用这些类,打算稍后使用双向绑定来更新每种方式等等。这是前2个顶级类(为了简洁而剪切) ):

I have started very simply with these classes, intending later to use 2-way binding to update each way, etc. Here are the first 2 top classes (snipped for brevity):

这是标准的EF CodeFirst票价,DBContext按照您的预期由EF布局。这是顶级2级课程(Access_Group& Access_List)的布局:

This is standard EF CodeFirst fare, and the DBContext is laid out by EF as you'd expect. This is the layout of the top 2 level classes (Access_Group & Access_List):

...一切都在EF-Land ...

...and all is well in EF-Land...

因为这可能很重要,这里是实际的Access_Group类:

Because it will likely be important, here is the actual Access_Group class:

Public Class Access_Group
    Inherits EntityTypeConfiguration(Of Access_Group)
    Implements IAccess_Group

    <Key>
    Public Property Access_GroupID As Integer Implements IAccess_Group.Access_GroupID
    Public Property Name As String Implements IAccess_Group.Name
    Public Property LastUpdated As Date Implements IAccess_Group.LastUpdated
    Public Property Active As Boolean Implements IAccess_Group.Active
    '------------------------------------------------------------------
    Public Property Access_Lists As ObservableCollection(Of Access_List) Implements IAccess_Group.Access_Lists
    Public Sub New()
        Me.Access_Lists = New ObservableCollection(Of Access_List)
    End Sub
End Class

我还没有添加许多基于事件的组件,因为我只是想让基础工作(在Treeview中分层显示),然后我添加铃声和口哨...

There are many event-based components that I have not added yet, because I just want the basics to work (display hierarchically in a Treeview) before I add the bells & whistles...

所以这就是如何在代码中创建类,首先填充数据库(SQL 2012):

So this is how the classes are created in code, that populated the database (SQL 2012) in the first place:

[Window Class contd.]     
Private Sub AddData()
    Try
        ctx = New entitiesContext
        Dim d As Date = Now
        '--------------------------------
        Dim al As New Access_List
        ' lower classes not needed to be shown...
        With al
            .Active = True
            .Checked = True
            .LastUpdated = d
            .Name = "some access-list at " & d.ToLongTimeString
        End With
        '--------------------------------
        Dim ag As Access_Group = New Access_Group
        With ag
            .Access_Lists.Add(al)
            .Active = True
            .LastUpdated = d
            .Name = "some access-group at " & d.ToLongTimeString
        End With
        '
        ctx.Access_Groups.Add(ag)
        '
        Dim i As Integer = ctx.SaveChanges()
        Console.WriteLine("Seed complete! -> " & i)
    Catch ex As Exception
        Dim exText As String = "Seed Failed "
        Console.WriteLine(exText & "(Message): " & ex.Message)
        Console.WriteLine(exText & "(ToString): " & ex.ToString)
        Console.WriteLine(exText & "(StackTrace): " & ex.StackTrace)
        Console.WriteLine("EntityValidationErrors: ")
        For Each eve As System.Data.Entity.Validation.DbEntityValidationResult In ctx.GetValidationErrors()
            Console.WriteLine("eve: OK? " & eve.IsValid & " - " & eve.Entry.ToString)
            For Each devr As System.Data.Entity.Validation.DbValidationError In eve.ValidationErrors
                Console.WriteLine("devr invalid property: " & devr.PropertyName)
                Console.WriteLine("devr error message : " & devr.ErrorMessage)
            Next
        Next
    End Try
End Sub

你看到上面提到的Access_List是第二级,这是那个类:

You see Access_List referred to above as the 2nd level down, and this is that class:

Public Class Access_List
    Inherits EntityTypeConfiguration(Of Access_Group)
    Implements toag.entities.IAccess_List

    <Key>
    Public Property Access_ListID As Integer Implements IAccess_List.Access_ListID
    Public Property Name As String Implements IAccess_List.Name
    Public Property LastUpdated As Date Implements IAccess_List.LastUpdated
    Public Property Active As Boolean Implements IAccess_List.Active
    Public Property Checked As Boolean Implements IAccess_List.Checked
    Public Property Object_Groups As ObservableCollection(Of Object_Group) Implements IAccess_List.Object_Groups
    Public Sub New()
        Me.Object_Groups = New ObservableCollection(Of Object_Group)
    End Sub
End Class

如果我可以如何获得这两个类的行为,我可以模板&得到其他的一切也是这样做的...

If I can figure out how to get these 2 classes to behave, I can template & get the rest to do so as well...

我已经尝试了几十年的代码和XAML组合,所以我会安排一个,至少在Treeview上显示某些:

I have tried HUNDREDS of code & XAML combinations, so I'll settle down with one that at least shows something on the Treeview:

<TreeView Grid.Column="0" 
    x:Name="ACLTreeView" 
    HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" 
    ItemsSource="{Binding Access_Group}">
</TreeView>

当此XAML与此代码隐藏组合时:

When this XAML is combined with this code-behind:

Public Class ConfigWindow

    Property ctx As entitiesContext
    Public Access_Group_List As IEnumerable(Of Access_Group)

    Sub New()
        ' This call is required by the designer.
        InitializeComponent()
       Startup()
    End Sub

    Public Sub Startup()
        Try
            ctx = New vASAContext
            Me.Access_Group_List = From ag In ctx.Access_Groups Select ag
            Me.ACLTreeView.ItemsSource = Access_Group_List.ToList
        Catch ex As Exception
            Debug.Print("ex: " & ex.Message)
        End Try
    End Sub

End Class

将产生以下内容:

对于不得不模糊命名空间... )这是很好的,因为在XAML中没有HierarchicalTemplate甚至TreeViewItem 。

(sorry about having to obfuscate the namespace...) Which is fine, as there is no HierarchicalTemplate or even TreeViewItem in XAML.

这是修改的XAML:







...将显示Access_Group实体的Name属性tead的这个类的名字[在编辑帖子时不能添加它的屏幕截图,所以你可能必须相信我在这一个! :)]

...which will show the Name property of the Access_Group entity instead of it's class name [can't add a screenshot of it when editing a post, so you may have to trust me on this one! :)]

但是,Window类中还有一个子层指向层级结构可能无法识别的问题。可能是我一直在尝试正确的示例,我的EF类没有正确设置?此子应显示所有元素及其子元素:

But there is another sub in the Window class that points to a problem with the hierarchy possibly not being recognized. Could it be that I've been trying examples that were correct, and my EF classes weren't set up properly? This sub should show all the elements and their children:

Public Sub PrintDebug(TheList As IEnumerable(Of Access_Group))
    For Each ag As Access_Group In TheList
        Console.WriteLine("=======================================")
        Console.WriteLine("ag: " & ag.Name & " has " & ag.Access_Lists.Count & " Access_List entries")
        For Each al As Access_List In ag.Access_Lists
            Console.WriteLine("ag -> al: " & al.Name & " has " & al.Object_Groups.Count & " Object_Group entries")
            For Each og As Object_Group In al.Object_Groups
                Console.WriteLine("ag -> al -> og: " & og.Name & " has " & og.Network_Objects.Count & " Network_Object entries")
                '...
            Next
        Next
        Console.WriteLine("=======================================")
    Next
End Sub

但是这是调试类提出的:

But this is what that debug class puts out:

=======================================
ag: some access-group at 5:00:49 PM has 0 Access_List entries
=======================================
=======================================
ag: some access-group at 5:08:56 PM has 0 Access_List entries
=======================================
=======================================
ag: some access-group at 5:09:14 PM has 0 Access_List entries
=======================================
=======================================
ag: some access-group at 5:12:31 PM has 0 Access_List entries
=======================================
[...]

?这是否意味着我的Treeview没有机会?但是,数据在DB中是正确的:

? Does this mean that my Treeview doesn't have a chance? But, but... the data is correct in the DB:

当我使用上面的代码时,所有这些键都被EF填充(仅在保存顶级类(Access_Group)这是ObservableCollections ...)

All of those keys were populated by EF when I used the above code (only saving the top level class (Access_Group) after populating it's ObservableCollections...)

???

我已经尝试过HierarchicalTemplate,网格中的每个组合/窗口资源,嵌套等等,我在3天后回到正方形... :)是的,各种LINQ查询也是...现在我正在考虑SQL( GASP )或者LINQ / SQL中的JOIN,但是我也可以一路走回DataSets&数据表,如果我准备好放弃...

I've tried every combination of HierarchicalTemplate, in grid/window resources, nested, etc. And I'm back to square 1 after 3 days... :) Yes, all kinds of LINQ queries, too... And now I'm contemplating SQL (GASP) or JOINs in either LINQ/SQL, but then I may as well go all the way back to DataSets & DataTables if I'm ready to really give up...

任何帮助赞赏...我只能不能移动,直到我可以让这些实体正确绑定...

Any help appreciated... I just can't move on until I can get these entities to bind correctly...

推荐答案

我已经创建了您的实体(AccessGroup,AccessList和ObjectGroup)的示例对象模型,此代码可能有帮助你:

I've created sample object model of your entities (AccessGroup, AccessList and ObjectGroup) and this code might help you:

代码隐藏

Imports System.Collections.ObjectModel

Class MainWindow

    Property AccessGroups As New ObservableCollection(Of AccessGroup)

    Public Sub New()

        ' This call is required by the designer.
        InitializeComponent()

       ' Add any initialization after the InitializeComponent() call.
        Me.DataContext = Me

        Dim ag1 = New AccessGroup With {.Name = "AG1"}
        Dim ag2 = New AccessGroup With {.Name = "AG2"}

        Dim al1 = New AccessList With {.Name = "AL1"}
        Dim al2 = New AccessList With {.Name = "AL2"}
        Dim al3 = New AccessList With {.Name = "AL3"}

        Dim og1 = New ObjectGroup With {.Name = "OG1"}
        Dim og2 = New ObjectGroup With {.Name = "OG2"}

        al1.ObjectGroups = New List(Of ObjectGroup) From {og1}
        al2.ObjectGroups = New List(Of ObjectGroup) From {og2}

        ag1.AccessList = New List(Of AccessList) From {al1, al2}
        ag2.AccessList = New List(Of AccessList) From {al3}

        AccessGroups.Add(ag1)
        AccessGroups.Add(ag2)
    End Sub
End Class

Public Class AccessGroup
    Property Name As String
    Property AccessList As IEnumerable(Of AccessList)
End Class

Public Class AccessList
    Property Name As String
    Property ObjectGroups As IEnumerable(Of ObjectGroup)
End Class

Public Class ObjectGroup
    Property Name As String
End Class

XAML

<TreeView ItemsSource="{Binding AccessGroups}">
    <!-- AccessGroup template -->
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding AccessList}">
            <TextBlock Text="{Binding Name}" />

            <!-- AccessList template -->
            <HierarchicalDataTemplate.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding ObjectGroups}">
                    <TextBlock Text="{Binding Name}" />

                    <!-- ObjectGroup template -->
                    <HierarchicalDataTemplate.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Name}" />
                        </DataTemplate>
                    </HierarchicalDataTemplate.ItemTemplate>

                </HierarchicalDataTemplate>
            </HierarchicalDataTemplate.ItemTemplate>

        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

在下面的图片中,您可以看到结果

On the picture bellow you can see the result

这篇关于分层代码首先EF绑定到WPF Treeview ...不可能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆