2013-08-02 18 views
10

Ich verwende das MVVM-Muster, und ich habe eine Bindung in XAML für das SelectedItem eines DataGrid erstellt. Ich programmiere das SelectedItem programmatisch, aber wenn das so ist, scrollt das DataGrid nicht zu der Auswahl. Gibt es eine Möglichkeit, dies zu erreichen, ohne das MVVM-Muster vollständig zu durchbrechen?ScrollIntoView für WPF DataGrid (MVVM)

fand ich die folgende Lösung, aber ich erhalte eine Fehlermeldung, wenn ich versuche, die Behavior Klasse zu implementieren, obwohl ich Blend-SDK installiert haben: http://www.codeproject.com/Tips/125583/ScrollIntoView-for-a-DataGrid-when-using-MVVM

+0

Welchen Fehler bekommen Sie, wenn Sie versuchen, das 'Verhalten' zu implementieren? – Gjeltema

+0

@Gjeltema 'Der Typ oder Namespace-Name 'Behaviour' konnte nicht gefunden werden (fehlt eine using-Direktive oder eine Assembly-Referenz?)' – Andy

+0

Haben Sie einen Verweis auf System.Windows.Interactivity.dll in Ihrem Projekt? – Gjeltema

Antwort

29

Diese funktionieren sollte. Die Idee ist, dass Sie diese angehängte Eigenschaft haben, die Sie an die DataGrid anhängen werden. In der XAML, wo Sie es anhängen, binden Sie es an eine Eigenschaft auf Ihrem ViewModel. Wenn Sie dem Wert SelectedItem programmgesteuert einen Wert zuweisen möchten, legen Sie auch einen Wert für diese Eigenschaft fest, an die die angefügte Eigenschaft gebunden ist.

Ich habe den angehängten Eigenschaftstyp gemacht, was auch immer der SelectedItem Typ ist, aber ehrlich gesagt ist es egal, was der Typ ist, solange Sie es auf etwas anderes als das, was es vorher war, setzen. Diese angefügte Eigenschaft wird nur dazu verwendet, um Code auf dem Ansichtssteuerelement (in diesem Fall ein DataGrid) in einer MVVM-freundlichen Weise auszuführen.

Also, das heißt, hier ist der Code für die angefügten Eigenschaft:

namespace MyAttachedProperties 
{ 
    public class SelectingItemAttachedProperty 
    { 
     public static readonly DependencyProperty SelectingItemProperty = DependencyProperty.RegisterAttached(
      "SelectingItem", 
      typeof(MySelectionType), 
      typeof(SelectingItemAttachedProperty), 
      new PropertyMetadata(default(MySelectionType), OnSelectingItemChanged)); 

     public static MySelectionType GetSelectingItem(DependencyObject target) 
     { 
      return (MySelectionType)target.GetValue(SelectingItemProperty); 
     } 

     public static void SetSelectingItem(DependencyObject target, MySelectionType value) 
     { 
      target.SetValue(SelectingItemProperty, value); 
     } 

     static void OnSelectingItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
     { 
      var grid = sender as DataGrid; 
      if (grid == null || grid.SelectedItem == null) 
       return; 

      // Works with .Net 4.5 
      grid.Dispatcher.InvokeAsync(() => 
      { 
       grid.UpdateLayout(); 
       grid.ScrollIntoView(grid.SelectedItem, null); 
      }); 

      // Works with .Net 4.0 
      grid.Dispatcher.BeginInvoke((Action)(() => 
      { 
       grid.UpdateLayout(); 
       grid.ScrollIntoView(grid.SelectedItem, null); 
      })); 
     } 
    } 
} 

Und hier ist die XAML-Code-Schnipsel:

<Window ... 
     xmlns:attachedProperties="clr-namespace:MyAttachedProperties"> 
    ... 
     <DataGrid 
      attachedProperties:SelectingItemAttachedProperty.SelectingItem="{Binding MyViewModel.SelectingItem}"> 
      ... 
     </DataGrid> 
    </Grid> 
+0

+1 Vielen Dank für Ihre Antwort. Allerdings bekomme ich den folgenden Fehler: 'System.Windows.Threading.Dispatcher 'enthält keine Definition für' InvokeAsync 'und keine Erweiterungsmethode' InvokeAsync ', die ein erstes Argument vom Typ' System.Windows.Threading.Dispatcher 'akzeptiert, könnte gefunden werden (fehlt Ihnen eine using-Direktive oder eine Assembly-Referenz?) '. Irgendwelche Ideen warum? Ich habe 'MySelectionType' geändert – Andy

+0

@Andy Entschuldigungen, ich arbeite noch in .Net 4.5. Ich werde meine Antwort aktualisieren, um .NET 4.0 widerzuspiegeln. – Gjeltema

+0

oh ok haha, das ist in Ordnung! Es funktioniert jetzt perfekt - eine DLL weniger! Ich wünschte, ich könnte deine Antwort noch einmal auffrischen! – Andy

6

Ich bin neu in MVVM. Ich verstehe die Idee von MVVM und versuche alles richtig zu implementieren. Ich hatte ein ähnliches Problem wie oben und ich endete mit 1 Zeile in XAML und 1 Zeile in Code hinter. Der Rest des Codes befindet sich in der VM. habe ich folgende in XAML

<ListBox DockPanel.Dock="Top" 
    Name="Selection1List" 
    ItemsSource="{Binding SelectedList1ItemsSource}" 
    SelectedItem="{Binding SelectedList1Item}" 
    SelectedIndex="{Binding SelectedList1SelectedIndex}" 
    SelectionChanged="Selection1List_SelectionChanged"> 

Und dies in der Code-behind:

private void Selection1List_SelectionChanged(object sender, SelectionChangedEventArgs e) { 
    Selection1List.ScrollIntoView(Selection1List.SelectedItem); 
} 

und das funktioniert gut.

Ich weiß, einige Leute wollen nicht einmal eine Codezeile im Code hinter dem Fenster. Aber ich denke diese 1 Zeile ist nur für die Ansicht. Es hat nichts mit den Daten oder mit der Logik der Daten zu tun. Also würde ich denken, dass dies keine Verletzung des MVVM-Prinzips ist - und so viel einfacher zu implementieren.

Kommentare sind willkommen.

Verwandte Themen