none
Datagrid in Datagrid RRS feed

  • Frage

  • Hallo ich habe ein Datagrid mit einen User, im RowDetails habe ich auch ein Datagrid welche die zu den User zugeordneten Autos zeigen soll. Dies sind beides 2 zwei SQL Tabellen die über das EntityFramework bereitgestellt werden. In der Autotabelle ist die UID (UserID) als Fremdschlüssel hinterlegt.

    <DataGrid x:Name="dgUserCar" Margin="10,10,10,10" AutoGenerateColumns="False">
                <DataGrid.Columns>
    				<DataGridTextColumn Binding="{Binding UID}" Header="UID"/>
                    <DataGridTextColumn Binding="{Binding Name}" Header="Name"/>
                    <DataGridTextColumn Binding="{Binding Vorname}" Header="Vorname"/>
    			</DataGrid.Columns>			
    			<DataGrid.RowDetailsTemplate>
                    <DataTemplate>
    					<DataGrid <!-- Hier weis ich nicht wie ich es machen soll -->/>
                    </DataTemplate>
    			</DataGrid.RowDetailsTemplate>
    </DataGrid>

    Mein Problem ist wenn ich den DataGrid über x:name einen Namen zuweise und ich Programm die Itemsource zuweisen will. Kann ich das Datagrid nicht finden. Außerdem weis ich nicht wie ich es machen soll das wenn das RowDetail angezeigt wird das Datagrid die Sicht so anzeigt das man nur die Autos aus der Tabelle sieht die zu den ausgewählten User gehören.

    Hoffe ihr könnt mir helfen.


    • Bearbeitet MietzeTatze Mittwoch, 23. November 2016 18:57
    Mittwoch, 23. November 2016 18:57

Antworten

  • Hi,
    Details im DataGrid werden typischerweise aus den Eigenschaften Details im eigentlichen Datenobjekt angezeigt. Wenn es sich bei den Details um eine Liste von untergeordneten Datenobjekten handeln soll, dann sollte jedes Datenobjekt eine Liste mit dem dazugehörenden Unterobjekten enthalten. Diese Liste kann in der Oberfläche für die Bindung eines Datagrids im RowDetailsTemplate genutzt werden. Wenn sich die Daten in zwei verschiedenen Tabellen befinden und über Fremdschlüsselbeziehungen in Verbindung stehen, kann man zuerst eine Liste mit den im äußeren DataGrid darzustellen Daten laden und dann zu jedem Datenobjekt die im Detail darzustellen Daten hinzufügen.

    Nachfolgend eine kleine Demo:

    XAML:

    <Window x:Class="Window40"
            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:WpfApplication1VB"
            mc:Ignorable="d"
            Title="Window40" Height="300" Width="300">
      <Window.Resources>
        <local:Window40VM x:Key="vm"/>
      </Window.Resources>
      <Grid DataContext="{StaticResource vm}">
        <DataGrid ItemsSource="{Binding View}" Margin="10,10,10,10" AutoGenerateColumns="False">
          <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding UID}" Header="UID"/>
            <DataGridTextColumn Binding="{Binding Name}" Header="Name"/>
            <DataGridTextColumn Binding="{Binding Vorname}" Header="Vorname"/>
          </DataGrid.Columns>
          <DataGrid.RowDetailsTemplate>
            <DataTemplate>
              <DataGrid ItemsSource="{Binding Autos}" IsReadOnly="True"/>
            </DataTemplate>
          </DataGrid.RowDetailsTemplate>
        </DataGrid>
      </Grid>
    </Window>

    Der ViewModel dazu (in VB.NET):

    Imports System.Collections.ObjectModel
    Imports System.ComponentModel
    
    Public Class Window40VM
      Public Sub New()
        Dim tab1 = GetTab1.ToList
        For Each auto In GetTab2()
          tab1.Where(Function(u)
                       Return u.UID = auto.FK
                     End Function).FirstOrDefault.Autos.Add(auto)
        Next
        cvs.Source = tab1
      End Sub
    
      Private cvs As New CollectionViewSource
      Public ReadOnly Property View As ICollectionView
        Get
          Return cvs.View
        End Get
      End Property
    
      Private Iterator Function GetTab1() As IEnumerable(Of Window40User)
        For i = 1 To 9
          Dim d = New Window40User With {.UID = i,
            .Name = $"Name {i}",
            .Vorname = $"Vorname {i}",
            .Autos = New ObservableCollection(Of Window40Auto)}
          Yield d
        Next
      End Function
    
      Private rnd As New Random
      Private Iterator Function GetTab2() As IEnumerable(Of Window40Auto)
        For i = 1 To 33
          Dim d = New Window40Auto With {
            .Farbe = If(rnd.NextDouble > 0.5, "Grün", "Rot"),
            .Kennzeichen = $"abd-def {i}",
            .FK = rnd.Next(1, 10)}
          Yield d
        Next
      End Function
    End Class
    
    Public Class Window40User
      Public Property UID As Integer
      Public Property Name As String
      Public Property Vorname As String
      Public Property Autos As ObservableCollection(Of Window40Auto)
    End Class
    
    Public Class Window40Auto
      Public Property Kennzeichen As String
      Public Property Farbe As String
      Public Property FK As Integer
    End Class


    --
    Viele Grüsse
    Peter Fleischer (MVP Reconnect, Partner)
    Meine Homepage mit Tipps und Tricks

    • Als Antwort markiert MietzeTatze Donnerstag, 24. November 2016 08:43
    Donnerstag, 24. November 2016 06:57

Alle Antworten

  • Hi,
    Details im DataGrid werden typischerweise aus den Eigenschaften Details im eigentlichen Datenobjekt angezeigt. Wenn es sich bei den Details um eine Liste von untergeordneten Datenobjekten handeln soll, dann sollte jedes Datenobjekt eine Liste mit dem dazugehörenden Unterobjekten enthalten. Diese Liste kann in der Oberfläche für die Bindung eines Datagrids im RowDetailsTemplate genutzt werden. Wenn sich die Daten in zwei verschiedenen Tabellen befinden und über Fremdschlüsselbeziehungen in Verbindung stehen, kann man zuerst eine Liste mit den im äußeren DataGrid darzustellen Daten laden und dann zu jedem Datenobjekt die im Detail darzustellen Daten hinzufügen.

    Nachfolgend eine kleine Demo:

    XAML:

    <Window x:Class="Window40"
            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:WpfApplication1VB"
            mc:Ignorable="d"
            Title="Window40" Height="300" Width="300">
      <Window.Resources>
        <local:Window40VM x:Key="vm"/>
      </Window.Resources>
      <Grid DataContext="{StaticResource vm}">
        <DataGrid ItemsSource="{Binding View}" Margin="10,10,10,10" AutoGenerateColumns="False">
          <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding UID}" Header="UID"/>
            <DataGridTextColumn Binding="{Binding Name}" Header="Name"/>
            <DataGridTextColumn Binding="{Binding Vorname}" Header="Vorname"/>
          </DataGrid.Columns>
          <DataGrid.RowDetailsTemplate>
            <DataTemplate>
              <DataGrid ItemsSource="{Binding Autos}" IsReadOnly="True"/>
            </DataTemplate>
          </DataGrid.RowDetailsTemplate>
        </DataGrid>
      </Grid>
    </Window>

    Der ViewModel dazu (in VB.NET):

    Imports System.Collections.ObjectModel
    Imports System.ComponentModel
    
    Public Class Window40VM
      Public Sub New()
        Dim tab1 = GetTab1.ToList
        For Each auto In GetTab2()
          tab1.Where(Function(u)
                       Return u.UID = auto.FK
                     End Function).FirstOrDefault.Autos.Add(auto)
        Next
        cvs.Source = tab1
      End Sub
    
      Private cvs As New CollectionViewSource
      Public ReadOnly Property View As ICollectionView
        Get
          Return cvs.View
        End Get
      End Property
    
      Private Iterator Function GetTab1() As IEnumerable(Of Window40User)
        For i = 1 To 9
          Dim d = New Window40User With {.UID = i,
            .Name = $"Name {i}",
            .Vorname = $"Vorname {i}",
            .Autos = New ObservableCollection(Of Window40Auto)}
          Yield d
        Next
      End Function
    
      Private rnd As New Random
      Private Iterator Function GetTab2() As IEnumerable(Of Window40Auto)
        For i = 1 To 33
          Dim d = New Window40Auto With {
            .Farbe = If(rnd.NextDouble > 0.5, "Grün", "Rot"),
            .Kennzeichen = $"abd-def {i}",
            .FK = rnd.Next(1, 10)}
          Yield d
        Next
      End Function
    End Class
    
    Public Class Window40User
      Public Property UID As Integer
      Public Property Name As String
      Public Property Vorname As String
      Public Property Autos As ObservableCollection(Of Window40Auto)
    End Class
    
    Public Class Window40Auto
      Public Property Kennzeichen As String
      Public Property Farbe As String
      Public Property FK As Integer
    End Class


    --
    Viele Grüsse
    Peter Fleischer (MVP Reconnect, Partner)
    Meine Homepage mit Tipps und Tricks

    • Als Antwort markiert MietzeTatze Donnerstag, 24. November 2016 08:43
    Donnerstag, 24. November 2016 06:57
  • Danke hatte es zwar mit C# gemacht. Aber es lies sich gut umstellen =)
    Donnerstag, 24. November 2016 08:44