Button in DataGrid-Zelle - Index übergeben als CommandParameter

  • WPF MVVM
  • .NET (FX) 4.5–4.8

Es gibt 17 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Button in DataGrid-Zelle - Index übergeben als CommandParameter

    Einen wunderschönen Tag euch allen :)

    Ich habe folgendes Szenario:

    Ich habe ein DataGrid gebunden an eine ObservableCollection(Of Class). Eine Spalte des DataGrid enthält in jeder Zeile einen Button:

    XML-Quellcode

    1. <DataGrid ItemsSource="{Binding MIDIControl, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" AutoGenerateColumns="False" CanUserResizeRows="False" IsReadOnly="False" HeadersVisibility="Column" SelectionMode="Single">
    2. <DataGrid.Columns>
    3. [...weitere Spalten...]
    4. <DataGridTemplateColumn Header="Mapping..." Width="10*">
    5. <DataGridTemplateColumn.CellTemplate>
    6. <DataTemplate>
    7. <Button Name="btnStartMapping" Content="{Binding ButtonText, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
    8. </DataTemplate>
    9. </DataGridTemplateColumn.CellTemplate>
    10. </DataGridTemplateColumn>
    11. </DataGrid.Columns>
    12. </DataGrid>


    Nun möchte ich dem Button als CommandParameter den Zeilenindex des DataGrid bzw. von MIDIControl mitgeben, wenn ich draufklicke.

    Kann mir jemand sagen wie ich da vorgehe, ich wette MVVM machts möglich :P

    Grüssle, kafffee
    Hallo

    kafffee schrieb:

    Da weiss ich aber wie das geht.

    Das mach das doch mal bitte, ich glaube wenn du das machst erübrigt sich die Frage nämlich, da du merken wirst das du hier einen kleinen Denkfehler hast.
    Ansonsten melde dich dann wieder.

    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. ##

    @Nofear23m

    Das würde ich dann so machen:

    XML-Quellcode

    1. <Button Name="btnStartMapping" Content="{Binding ButtonText, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Command="{Binding StarteMapping}" CommandParameter="{???}"/>


    VB.NET-Quellcode

    1. Private _StarteMapping As ICommand
    2. Public ReadOnly Property StarteMapping() As ICommand
    3. Get
    4. If _StarteMapping Is Nothing Then _StarteMapping = New RelayCommand(AddressOf StarteMapping_Execute, Function(o) True)
    5. Return _StarteMapping
    6. End Get
    7. End Property
    8. Private Sub StarteMapping_Execute(obj As Object)
    9. Throw New NotImplementedException()
    10. End Sub


    Das Einzige was mir dazu noch einfällt ist, der Klasse, deren Instanzen im DataGrid angezeigt werden, noch eine Property mit den Indexes mitzugeben und dann wie in deinem Kapitel 2.1.1.8 CommandBinding und CommandParameter das Item, auf dem sich der Button befindet, mitzugeben... Weisst du wie ich meine?

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „kafffee“ ()

    kafffee schrieb:

    Das würde ich dann so machen

    Würde?
    Hast du es gemacht?

    Du bindest hier ja auf das Item selbst, nicht auf die Klasse auf die das Datagrid selbst gebunden ist. Was soviel bedeutet das du dich ja innerhalb (oder wenn man so will auf der Ebene) des Items befindest.
    Was also willst du mit dem Index? Verstehst du auf was ich hinaus wollte? Deshalb wollte ich das du es wirklich probierst.

    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. ##

    Nofear23m schrieb:

    Würde?
    Hast du es gemacht?


    Ja hab ich. Das "Das würde ich dann so machen" bezog sich lediglich auf die zwei Quellcodes von mir in Post 5, also nicht auf das, was ich hinter "Das Einzige was mir dazu noch einfällt ist..."

    Ich verstehe noch nicht worauf du hinaus willst.

    Hintergrund ist der, dass ich, wenn ich auf den Button in der jeweiligen Zeile drücke, mittels des Index die Werte für MIDI-Gerät, Min. Max und MIDI Control-ID per Code ausfüllen möchte. Siehe Screenshot:
    Bilder
    • screenshot_midimapper.png

      104,83 kB, 1.320×970, 56 mal angesehen
    Jaja, aber du denkst zu sehr im View. Denke mal rein in "Daten".

    Zumindest wenn ICH es richtig verstehe, du zeigst so wenig Code das ich hier nun mit Pseudodaten arbeiten muss.

    Sagen wir mal dein Datagrid ist die Garage, in der Garage befinden sich Autos. Jedes Auto hat einen Startknopf.

    Das Datagrid ist also die Garage, jede Zeile in dem Datagrid ist ein Auto. Und der Button einer Zeile ist der Startknopf.
    Die Button (somit der Command) befindet sich also in der Klasse "Auto".

    Jetzt willst du ja quasi der Index in der Auflistung von Autos der Garage ermitteln, das musst du aber nicht. Der Button befindet sich in der Instanz eines Autos.
    Also ist dieser dem Auto zugeordnet und kann dieses einfach starten.

    Versuchs einfach.

    Ansonsten zeig doch mehr Code oder mach ein kleines Reproduzierbares Pseusobeispiel. Sowas ist in 5 Minuten erstellt und man kann sich damit spielen.

    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. ##

    Nofear23m schrieb:

    Sagen wir mal dein Datagrid ist die Garage, in der Garage befinden sich Autos. Jedes Auto hat einen Startknopf.

    Das Datagrid ist also die Garage, jede Zeile in dem Datagrid ist ein Auto. Und der Button einer Zeile ist der Startknopf.
    Die Button (somit der Command) befindet sich also in der Klasse "Auto".

    Genau. Soweit alles gut.

    Nofear23m schrieb:

    Jetzt willst du ja quasi der Index in der Auflistung von Autos der Garage ermitteln, das musst du aber nicht. Der Button befindet sich in der Instanz eines Autos.
    Also ist dieser dem Auto zugeordnet und kann dieses einfach starten.

    Genau. Was ich aber noch nicht verstehe, wie ich das ohne Index machen soll...

    Hier mal ein repräsentativer Datensatz:

    VB.NET-Quellcode

    1. Public Sub New()
    2. MIDIControl.Add(New ViewModel.MIDIMapperDataViewModel(Model.MIDIMapperData.SoftwareControl.MicVolumeCC, "", Nothing, Nothing, Nothing, Nothing, True))
    3. MIDIControl.Add(New ViewModel.MIDIMapperDataViewModel(Model.MIDIMapperData.SoftwareControl.MicVolumePlus, "", Nothing, Nothing, Nothing, Nothing, True))
    4. MIDIControl.Add(New ViewModel.MIDIMapperDataViewModel(Model.MIDIMapperData.SoftwareControl.MicVolumeMinus, "", Nothing, Nothing, Nothing, Nothing, True))


    Diesem folgen alle drei DataGrids.

    MIDIControl selbst ist so deklariert:

    VB.NET-Quellcode

    1. Public Property MIDIControl As ObservableCollection(Of ViewModel.MIDIMapperDataViewModel) = New ObservableCollection(Of ViewModel.MIDIMapperDataViewModel)


    Dann habe ich im Model eine Klasse MIDIMapperData, welche mit den Properties befüllt ist, die du in den DataGrids siehst. So. Damit ich die dann einzeln gut ändern kann, hab ich diese im ViewModel in der Klasse MIDIMapperDataViewModel abstrahiert. Ausserdem sind da noch Enums für Software-Control und MIDI-Control-Typ drinne.

    So, das Ganze soll dazu dienen, eingehende MIDI-Ereignisse zu empfangen und die empfangenen Werte in die Tabellen einzutragen. Die entsprechenden Klassen für das Empfangen der MIDI-Ereignisse hab ich schon geschrieben. Das Ganze soll so gehen, wie auf dem Screenshot ganz oben in rot in einem Textblock.
    Also, entsprechenden Button in der Zeile drücken, die Hardware-Taste oder den Fader triggern ---> Werte sollen eingetragen werden.

    Mein Plan war der folgende (vorausgesetzt man hat den Index):

    VB.NET-Quellcode

    1. Private Sub StarteMapping_Execute(obj As Object)
    2. Dim index As Integer = DirectCast(obj, Integer)
    3. MeinMIDIControlIndex = index
    4. StartListeningToMIDIEvents ' weist das Programm an, auf eingehende MIDI-Events zu hören (PseudoCode)
    5. End Sub
    6. Private MeinMIDIControlIndex As Integer
    7. Public Sub ReceiveMIDIEvents(Event As MIDIEvent)
    8. MIDIControl(MeinMIDIControlIndex).MIDIGeraet = Event.MIDIGeraet
    9. MIDIControl(MeinMIDIControlIndex).MIDIControlID = Event.MIDIControlID
    10. ...
    11. End Sub


    Ist bloss PseudoCode, aber ich denke man versteht den Punkt. Wenn nicht, dann lad ich auch gern mal das Projekt hoch, ist halt etwas umfangreicher als was du jetzt siehst...

    Du hast geschrieben, dass sich der Button in der Instanz jedes Autos befindet. Und das könnte meiner Ansicht nach auch der Knackpunkt sein. Denn der Button ist keiner Property in der Instanz von MIDIControl
    zugeordnet. Gibt es eine Möglichkeit das zu tun, ich meine bei einer Checkbox in einer Zelle einfach an ein Boolean binden, aber ein Button?

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „kafffee“ ()

    Hallo

    Machen wir es nicht so kompliziert.
    Mach doch ein kleines Minibeispiel (bitte nicht das Originalprojekt mit zig Abhängigkeiten welches dann nicht lauffähig ist) einfach nur mit den zwei bis drei Klassen und einer View und ich schau mir das gerne an, ich denke hier handelt es sich nur um einen kleinen Denkfehler, oder wir reden aneinander vorbei.

    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. ##

    warum mit IndexOf danach suchen?
    Wenn du es übergeben hast, dann hast du es ja.
    meine Buttons hatten oft sowas:

    XML-Quellcode

    1. CommandParameter="{Binding DataContext, RelativeSource={RelativeSource Self}}"
    und gut war.

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

    Sorry das ich mich dem nicht annehmen konnte, Beruflich geht leider drunter und drüber. ;(
    Freut mich aber das du es geschafft hast.
    Ich würde den Tipp von ErfinderDesRades aber beherzigen, ist um einiges sauberer.

    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. ##

    Ich hatte da an sowas gedacht:

    ​Command="{Binding DataContext.InterpretZuPlaylistZufuegen, ElementName=lstInterpreten}"

    Wenn ich mir das so anschaue, dann bewirkt das exakt das Gleiche oder? Bloss ne andere Schreibweise....

    InterpretZuPlaylistZufuegen ist dabei der Name des Buttons, lstInterpreten der Name des DataGrid...
    @ErfinderDesRades

    Jou meins funzt hervorragend. Hab den Button auch in einem DataTemplate.
    Ich gebe meinen Controls oft Namen, dann sind sie einfacher im XAML wiederzufinden :)

    Wie sieht das dann bei dir im ViewModel aus? Was wird dann genau als Objekt im Commandparameter übergeben?

    Bei mir ist es ja so, dass ich eine Kopie der "Zeile" / des Datensatzes bekomme, dann danach in der OC nach dem Index suche und dann mittels des Indexes die Zeile verändere.

    Kann man das bei deiner Funktion dann direkt verändern, ohne dass eine Kopie gemacht wird?