Announcement

Collapse
No announcement yet.

WPF: SelectedItem aus mehreren DataGrid erhalten

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • WPF: SelectedItem aus mehreren DataGrid erhalten

    Hallo Leute,

    ich habe in verschiedenen TreeView-Elementen dazugehörige DataGrids. Wenn der Benutzer nun eine Reihe aus einem beliebigen DataGrid anwählt, so möchte ich, dass das SelectedItem an andere Controls (Textboxen) gebunden wird. Das klappt aber leider nur beim Selektieren der ersten DataGrid.



    Ich habe die Frage zuvor auch schon auf StackOverflow gestellt, wobei ich bisher allerdings noch auf keine Lösung gekommen bin.

    Das TreeView mit samt deren DataGrid wird wie folgt dargestellt und gebunden:
    [highlight=c#]
    <TreeView ItemsSource="{Binding Path=PlaceList}">
    <TreeView.ItemTemplate>
    <DataTemplate>
    <TreeViewItem Header="{Binding Path=Name}">
    <DataGrid ItemsSource="{Binding MachinesInPlace, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
    SelectedItem="{Binding SelectedMachine, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    </TreeViewItem>
    </DataTemplate>
    </TreeView.ItemTemplate>
    </TreeView>
    [/highlight]

    Die Textboxen, die die selektierte Eigenschaft abgreifen sollen, funktionieren wie folgt:
    [highlight=c#]
    <TextBox Text="{Binding PlaceList/SelectedMachine.Id, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    [/highlight]

    Ich arbeite mit dem MvvmLight-Framework. Innerhalb des ViewModels habe ich eine ObservableCollection mit Places angelegt. An diese ist die TreeView gebunden.
    [highlight=c#]
    public ObservableCollection<PlaceModel> PlaceList { get; set; } = new ObservableCollection<PlaceModel>();
    [/highlight]

    Das PlaceModel an sich beinhaltet dann noch eine Maschinen-Liste, die angibt, welche Maschinen im Platz vorhanden sind. Außerdem ist dort die selektierte Maschine enthalten.
    [highlight=c#]
    public class PlaceModel
    {
    public int Id { get; set; }
    public string Name { get; set; } = "_CurrentObjectName";
    public ObservableCollection<MachineModel> MachinesInPlace { get; set; }
    public MachineModel SelectedMachine { get; set; }
    }
    [/highlight]

    Jetzt besteht der Fehler, dass die Textbox nur die Items aus dem ersten Datagrid annimmt. Jedes nachfolgende Datagrid wird ignoriert.

    Meine Idee wäre es jetzt innerhalb des ViewModels die Eigenschaft SelectedMachine anzulegen. Würde mMn. auch mehr Sinn machen, als dies in jedem Platz-Modell zu tun. Das Problem ist dann das zwar die Textbox auf die Property aus dem ViewModel zugreifen kann, ich aber nicht mehr das SelectedItem-Property der DataGrid daran binden kann. Das SelectedItem-Property kann ich glaube ich nur an Eigenschaften aus der zuvor gebundenen PlatzListe (PlaceList) binden.

    Falls sich das Problem genauer anschauen möchte, habe ich ein Beispiel-Projekt angelegt, welches noch gebuilded werden muss (bin- und obj-Ordner habe ich entfernt): https://www.file-upload.net/download...Error.zip.html

    Hätte jemand eine Ahnung, wie ich das Binding-Problem beseitigt bekomme?

  • #2
    Ich bin kein großer WPF Guru, aber

    PlaceList/SelectedMachine.Id

    Das kann doch eigentlich gar nicht funktionieren. Das ist wahrscheinlich einfach eine Konvention dass er in Deinem Fall das erste gewählte Element nimmt. Wenn nur eines ausgewählt werden kann und dann in den Textboxen angezeigt werden soll, dann darf das auch nur eine Eigenschaft sein. Du hast aber eine Liste in der jedes PlaceModel sein eigenes ausgewähltes Element hat.

    Also quasi so in etwa:

    Code:
    public class AllPlacesModel
    {
      public ObservableCollection<PlaceModel> PlaceList { get; set; }
      public MachineModel SelectedMachine { get; set; }
    }
    
    public class PlaceModel
    {
      public int Id { get; set; }
      public string Name { get; set; } = "_CurrentObjectName";
      public ObservableCollection<MachineModel> MachinesInPlace { get; set; }        
    }
    Das erscheint mir das einzige sinnvolle Model für Deine Problemstellung. Die Bindings müssten dann entsprechend angepasst werden. Funktioniert das so?

    Comment


    • #3
      Danke für deinen Lösungsvorschlag, fanderlf.

      Originally posted by fanderlf View Post
      Das ist wahrscheinlich einfach eine Konvention dass er in Deinem Fall das erste gewählte Element nimmt.
      Ja, anscheinend.. Das beigefügte Beispiel-Projekt zeigt ja auch, dass das Binding im ersten DataGrid auf alle Elemente-Einträge funktioniert. Wählt man auf dem Beispiel-Bild "Mewag" (Element-Eintrag #2) aus, so würde dies ja auch auf die Textboxen übernommen werden. :- /

      Deinen Ansatz, die beiden Properties PlaceList und SelectedMachine innerhalb einer Klasse zu verwenden habe ich durch das ViewModel auch schon ausprobiert und kam dann zu dem Ergebnis, dass ich die SelectedProperty nicht an eine Eigenschaft außerhalb der zuvor definierten PlatzListe (PlaceList) binden kann.. :- (


      [highlight=c#] <TreeView ItemsSource="{Binding AllPlaceModel.PlaceList, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
      <TreeView.ItemTemplate>
      <DataTemplate>
      <TreeViewItem Header="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
      <DataGrid ItemsSource="{Binding MachinesInPlace, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
      SelectedItem="{Binding AllPlaceModel.SelectedMachine, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
      </DataGrid>
      <!-- AllPlaceModel.SelectedMachine kann nicht innerhalb von PlaceModel gefunden werden -->
      </TreeViewItem>
      </DataTemplate>
      </TreeView.ItemTemplate>
      </TreeView>
      [/highlight]

      Anhand des obigen Code-Beispiels heißt das konkret, dass SelectedItem nicht an AllPlaceModel.SelectedMachine gebunden werden kann, weil durch das TreeView schon definiert wurde, dass es sich um eine PlaceList handelt. Der Compiler sagt dann: "Ich kann die Property SelectedMachine nicht innerhalb des Objektes PlaceModel finden.":
      Originally posted by Visual Studio
      System.Windows.Data Error: 40 : BindingExpression path error: 'AllPlaceModel' property not found on 'object' ''PlaceModel' (HashCode=2174348)'. BindingExpression:Path=AllPlaceModel.SelectedMachi ne; DataItem='PlaceModel' (HashCode=2174348); target element is 'DataGrid' (Name=''); target property is 'SelectedItem' (type 'Object')
      Das kann doch nicht richtig sein?!?
      Zuletzt editiert von kogen; 09.03.2017, 16:15.

      Comment


      • #4
        Hallo Leute,

        auf stackoverflow hat noch jemand geantwortet. Diese Lösung möchte ich hier natürlich auch (auf deutsch) zur Verfügung stellen:

        Die für mich logische Lösung sieht vor das Property SelectedMachine in das ViewModel zu packen. Wichtig ist dabei auch, dass dieses das PropertyChanged-Event berührt:
        [highlight=c#]
        class ViewModel : ViewModelBase
        {
        ...
        private MachineModel _selectedMachine;
        public MachineModel SelectedMachine
        {
        get
        {
        return _selectedMachine;
        }
        set
        {
        // raises Event PropertyChanged after setting value
        Set(ref _selectedMachine, value);
        }
        }
        ...
        }
        [/highlight]

        Innerhalb des DataGrid musste die Property SelectedItem dann gesondert auf das übergeordnete Element vom Typ Window gerichtet werden, in dem sich die Eigenschaft DataContext.SelectedMachine befindet:
        [highlight=c#]
        <DataGrid ItemsSource="{Binding MachinesInPlace, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
        SelectedItem="{Binding DataContext.SelectedMachine, RelativeSource={RelativeSource AncestorType=Window},Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        [/highlight]

        Ich bin darauf selbst nicht gekommen, weil mir VisualStudio diese Eigenschaft im Bindings-Fenster nicht anzeigt:


        Letztendlich muss noch das Binding der Textboxen abgeändert werden. Die Property SelectedMachine befindet sich ja nun nicht mehr in der PlaceList, sondern im ViewModel:
        [highlight=c#]
        <TextBox Text="{Binding SelectedMachine.Id, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        [/highlight]

        VG
        Zuletzt editiert von kogen; 13.03.2017, 16:45.

        Comment

        Working...
        X