Databindung hierarchisch

  • WPF

Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von MasterQ.

    Databindung hierarchisch

    Moin,

    in folgendem (gekürzten) UserControl möchte ich für den Button in der Zelle des DataGrid, Zeile 9-10, Command an MenuItemClick des Viewmodels (DataContext des Controls) binden. Das kriege ich nicht hin.

    Da das Grid an Data des Viewmodels gebunden ist, wird gemeckert, weil Data kein MenuItemClick enthält. Ich habe mit RelativeSource etc. rumgespielt und keinen Erfolg erzielt. Wie mache ich es denn, dass der im DataGrid liegende Button denselben Datenkontext sieht wie der Button direkt im Control?

    XML-Quellcode

    1. <UserControl x:Class="Klasse">
    2. <StackPanel>
    3. <DataGrid x:Name="dataGrid"
    4. ItemsSource="{Binding Data}">
    5. <DataGrid.Columns>
    6. <DataGridTemplateColumn Width="50">
    7. <DataGridTemplateColumn.CellTemplate>
    8. <DataTemplate>
    9. <Button Command="{Binding MenuItemClickCommand}"
    10. CommandParameter="Parameter"/>
    11. </DataTemplate>
    12. </DataGridTemplateColumn.CellTemplate>
    13. </DataGridTemplateColumn>
    14. </DataGrid.Columns>
    15. </DataGrid>
    16. <Button Command="{Binding MenuItemClickCommand}"
    17. CommandParameter="Drucken"/>
    18. </StackPanel>
    19. </UserControl>


    Gruß

    MQ
    Du kannst deinem Button einen expliziten DataContext mitteilen, sodass dieser (und alle unter ihm liegenden Elemente) diesen Context nutzen statt dem seines Parent:

    XML-Quellcode

    1. ...
    2. <DataGridTemplateColumn.CellTemplate>
    3. <DataTemplate>
    4. <Button Command="{Binding MenuItemClickCommand}"
    5. CommandParameter="Parameter"
    6. DataContext="{...}"/>
    7. </DataTemplate>
    8. </DataGridTemplateColumn.CellTemplate>
    9. ...


    und im DataContext kannst du an das ViewModel binden, das den Parameter trägt, du kannst aber auch an andere DataContext binden, etc.
    Hallo

    Wenn du direkt auf das UserControl binden willst dann kannst du das mittels FindAncestor machen.

    XML-Quellcode

    1. <DataGrid x:Name="dataGrid"
    2. ItemsSource="{Binding Data}">
    3. <DataGrid.Columns>
    4. <DataGridTemplateColumn Width="50">
    5. <DataGridTemplateColumn.CellTemplate>
    6. <DataTemplate>
    7. <Button Command="{Binding RelativeSource={RelativeSource
    8. FindAncestor,
    9. AncestorType={x:Type UserControl},
    10. AncestorLevel=2},Path=MenuItemClickCommand}"
    11. CommandParameter="Parameter"/>
    12. </DataTemplate>
    13. </DataGridTemplateColumn.CellTemplate>
    14. </DataGridTemplateColumn>
    15. </DataGrid.Columns>
    16. </DataGrid>


    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Das hatte ich schon probiert, erhalte aber die Meldung, Quelle nicht gefunden.

    konkret handelt es sich um einen XML-Bindungsfehler

    Datenkontext: null
    Bindungspfad: MenuItemClickCommand
    Ziel: Button.Command
    Zieltyp: ICommand
    Beschreibung: Quelle nicht gefunden: RelativeSource FindAncestor, AncestorType='XYZControl', AncestorLevel='2'

    Eigentlich muss ich an das Viewmodel des Controls binden. Um aber mal herauszukriegen, was da schief läuft, habe ich MenuItemClickCommand auch im Control angelegt und vom Viewmodel durchgeschleift.

    An der Fehlermeldung ändert sich nix.
    Da dein Control aber zum Beispiel x:Class="Klasse" kautet, müsste dein Binding auch auf diese aufsetzen:

    mittels: AncestorType={x:Type Klasse}

    Und auf die Angabe von AncestorLevel würde ich hier erstmal verzichten, da gerade am Anfang es verwirrend sein kann, da er nach exakt zwei Ancestoren aufhört, aber manchmal übersieht man vielleicht, wie viele Ancestoren wirklich dazwischen sind. Deshalb nutze die x:Type Anweisung, damit du sagst, welche Klasse er finden soll. Wenn es im MainWindow ist, kann es auch lauten AncestorType={x:Type MainWindow} oder jede andere Klasse, die dazwischen enthalten sein kann.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „PadreSperanza“ ()

    Hallo

    1.) Wenn ein Code nicht funktioniert dann Poste diesen auch. (also den code)
    2.) Du suchst das XYZControl (laut Fehlermeldung) du sollt aber das nächste USERCONTROL suchen.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hier mal etwas mehr Code.

    Mein Steuerelement OrdersOpenControl ist von UserControl abgeleitet und dient als Inhalt eines TabControls. DataContext von OrdersOpenControl wird im Constructor auf das Viewmodel gesetzt, dessen Property Data als Datenquelle für das DataGrid dient.


    Wie man sieht, hat OrdersOpenControl eine Kopfzeile, ein DataGrid als Inhalt und eine Fußzeile. Sowohl in Kopf- als auch Fußzeile liegen Buttons, die über MenuItemClickCommand erreicht werden und genau das machen was sie sollen.

    Für den Button im DataGrid ist MenuItemClickCommand nicht erreichtbar.

    C#-Quellcode

    1. <UserControl x:Class="OrdersOpenControl"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    5. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    6. xmlns:local="clr-namespace:MeinProjekt"
    7. xmlns:p="clr-namespace:MeinProjekt.Properties"
    8. mc:Ignorable="d"
    9. d:DesignHeight="450" d:DesignWidth="800">
    10. <Grid>
    11. <Grid.RowDefinitions>
    12. <RowDefinition Height="{StaticResource HeaderHeight}"/>
    13. <RowDefinition Height="*"/>
    14. <RowDefinition Height="{StaticResource FooterHeight}"/>
    15. </Grid.RowDefinitions>
    16. <Border Grid.Row="0"
    17. Background="{StaticResource UserColorDefault}">
    18. <Grid>
    19. <Label Grid.Row="0"
    20. Content="{x:Static p:Translate.OffeneAufträgeHeader}"
    21. Style="{StaticResource HeaderLabelStyleUser}"
    22. HorizontalAlignment="Left"/>
    23. <Button Grid.Row="0"
    24. Style="{StaticResource IconButtonStyle}"
    25. ToolTip="{x:Static p:Translate.DockUndock}"
    26. Command="{Binding MenuItemClickCommand}"
    27. CommandParameter="DockUndock"
    28. HorizontalAlignment="Right"
    29. VerticalAlignment="Center"
    30. Visibility="Visible">
    31. <Image Source="/Images/dock_window_icon_138670.png"
    32. Style="{StaticResource IconButtonIconStyle}"/>
    33. </Button>
    34. </Grid>
    35. </Border>
    36. <Border Grid.Row="1">
    37. <DataGrid x:Name="dataGrid"
    38. AutoGenerateColumns="false"
    39. RowBackground="{StaticResource DataGridRowColor}"
    40. AlternatingRowBackground="{StaticResource DataGridAlternatingRowColor}"
    41. HeadersVisibility="All"
    42. RowHeaderStyle="{StaticResource RowHeaderStyle}"
    43. ItemsSource="{Binding Data}"
    44. SelectedItem="{Binding SelectedItem}"
    45. SelectionMode="Single"
    46. SelectionUnit="FullRow"
    47. IsReadOnly="True"
    48. >
    49. <DataGrid.Columns>
    50. <DataGridTemplateColumn Width="50">
    51. <DataGridTemplateColumn.CellTemplate>
    52. <DataTemplate>
    53. <Button
    54. Command="{Binding Path=MenuItemClickCommand,
    55. RelativeSource={RelativeSource FindAncestor,
    56. AncestorType={x:Type local:OrdersOpenControl},
    57. AncestorLevel=4}}"
    58. CommandParameter="Bearbeiten"
    59. Width="auto"
    60. ToolTip="{x:Static p:Translate.Bearbeiten}">
    61. <Button.Content>
    62. <Image Source="/Images/pencil-8x.png"
    63. Width="20"
    64. Height="20" />
    65. </Button.Content>
    66. </Button>
    67. </DataTemplate>
    68. </DataGridTemplateColumn.CellTemplate>
    69. </DataGridTemplateColumn>
    70. </DataGrid.Columns>
    71. </DataGrid>
    72. </Border>
    73. <Border Grid.Row="2"
    74. Background="{StaticResource UserColorDefault}">
    75. <StackPanel Grid.Row="2"
    76. Orientation="Horizontal"
    77. HorizontalAlignment="Right"
    78. Background="{StaticResource UserColorDefault}">
    79. <Button x:Name="btnDrucken"
    80. Style="{StaticResource IconButtonStyle}"
    81. ToolTip="{x:Static p:Translate.Drucken}"
    82. Command="{Binding MenuItemClickCommand}"
    83. CommandParameter="Drucken"
    84. HorizontalAlignment="Right"
    85. Margin="0,0,10,0">
    86. <Image Source="/Images/print-8x.png"
    87. Style="{StaticResource IconButtonIconStyle}"/>
    88. </Button>
    89. <Button x:Name="btnSchließen"
    90. Style="{StaticResource IconButtonStyle}"
    91. ToolTip="{x:Static p:Translate.Schließen}"
    92. Command="{Binding MenuItemClickCommand}"
    93. CommandParameter="Schließen"
    94. HorizontalAlignment="Right">
    95. <Image Source="/Images/x-8x.png"
    96. Style="{StaticResource IconButtonIconStyle}"/>
    97. </Button>
    98. </StackPanel>
    99. </Border>
    100. </Grid>
    101. </UserControl>


    Ich habe mit FindAnvestor nach "OpenOrdersControl" gesucht und auch nach "UserControl". UserControl kennt er in diesem Kontext gar nicht und OrdersOpenControl gibt die Meldung aus, die ich vorher gepostet hatte.
    Nochmals

    Es sollte funktionieren wenn du nach einem Usercontrol suchst. (wie ich es gepostet hatte)

    XML-Quellcode

    1. <Button
    2. Command="{Binding Path=MenuItemClickCommand,
    3. RelativeSource={RelativeSource FindAncestor,
    4. AncestorType={x:Type UserControl},
    5. AncestorLevel=4}}"
    6. CommandParameter="Bearbeiten"
    7. Width="auto"
    8. ToolTip="{x:Static p:Translate.Bearbeiten}">
    9. <Button.Content>
    10. <Image Source="/Images/pencil-8x.png"
    11. Width="20"
    12. Height="20" />
    13. </Button.Content>
    14. </Button>


    Alternativ setze den Name für das Usercontrol mit x:Name=mycontrol und setze damit den DataContext fest.

    Ansonsten mach ein kleines Minibeispiel welches den Fahler reproduziert, dann können wir besser sehen was nicht stimmt.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##