0

To explain the background of my WPF application:

In my database I have three tables: docs, doctypes, metadata
Every doc has one doctype. Doctype has metadata that is entered by the user.

For example: I have two doctypes: Invoice and Mail. If a user adds a doc, he need to to select one of the doctypes.

If the user choose Invoice, he is asked to enter a InvoiceNumber and an Amount as metadata. If the user choose Mail, he is asked for Sender and Subject as metadata.

In the WPF application I have a datagrid the should show all documents and related data. For each metadata one column should be created automatically.

For my example this means I want to have a datagrid with the following columns to be created:
docname|doctype|InvoiceNumber|Amount|Sender|Subject

The values for this are for example:
doc1|Invoice|IN1234|10.00| |
doc2|Mail| | |Tom|Testmail

Empty values because of missing metadata for a doctype should be just left empty in the datagrid.

I have the following code to create example data and bind it to my datagrid:

Class MainWindow

  Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
        Dim lst As New ObservableCollection(Of doc)

        'Example doctypes
        Dim DoctypeExampleInvoice As New Dictionary(Of String, String)
        DoctypeExampleInvoice.Add("InvoiceNumber", "IN1234")
        DoctypeExampleInvoice.Add("InvoiceAmount", "10.00")

        Dim DoctypeExampleMail As New Dictionary(Of String, String)
        DoctypeExampleMail.Add("Sender", "Tom")
        DoctypeExampleMail.Add("Subject", "Testmail")

        'Example docs
        Dim _doc As New doc With {.docname = "doc1", .doctype = "Invoice", .metadata = DoctypeExampleInvoice}
        lst.Add(_doc)

        Dim _doc2 As New doc With {.docname = "doc2", .doctype = "Mail", .metadata = DoctypeExampleMail}
        lst.Add(_doc2)

        dgv.ItemsSource = lst
    End Sub
End Class

Public Class doc
    Property docname As String
    Property doctype As String
    Property metadata As New Dictionary(Of String, String)
End Class

My XAML looks like this:

<Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <DataGrid x:Name="dgv" ItemsSource="{Binding lst}" SelectionMode="Single" SelectionUnit="FullRow" AutoGenerateColumns="True"/>
    </Grid>
</Window>

This is what my result is actually:
Result

As you see, metadata is not shown as columns, it is shown as one column with collection. How to get this done?

Thanks in advance, Marco

MUnna
  • 15
  • 3

2 Answers2

0

These modifications to your doc class will allow you to display keys 1-3 in your grid:

Public Class doc

    Public Property docname As String
    Public Property doctype As String
    Public Property metadata As New Dictionary(Of String, String)

    ''' <summary>
    ''' Gets 'key1' from <see cref="metadata"/>
    ''' </summary>
    Public ReadOnly Property Key1 As String
        Get
            Return GetKey(0)
        End Get
    End Property

    ''' <summary>
    ''' Gets 'key3' from <see cref="metadata"/>
    ''' </summary>
    Public ReadOnly Property Key2 As String
        Get
            Return GetKey(1)
        End Get
    End Property

    ''' <summary>
    ''' Gets 'key3' from <see cref="metadata"/>
    ''' </summary>
    Public ReadOnly Property Key3 As String
        Get
            Return GetKey(2)
        End Get
    End Property

    ''' <summary>
    ''' Gets an item from <see cref="metadata"/> using 'key' + index.
    ''' </summary>
    ''' <param name="keyIndex"></param>
    Private Function GetKey(keyIndex As Integer) As String
        If metadata.Count > keyIndex Then
            Return metadata.ElementAt(keyIndex).Value
        Else
            Return "N/A"
        End If
    End Function

End Class

Binding to indexed properties is possible and you can look that up but this should get you a little further in displaying what you want. If the value sin metadata change, you should also consider implementing INotifyPropertyChanged on this class.

Étienne Laneville
  • 4,697
  • 5
  • 13
  • 29
0

I have solved it using a bindable dynamic dictionary. Details can be found here: Binding DataGrid to ObservableCollection<Dictionary>

MUnna
  • 15
  • 3