2011-01-17 6 views
4

Ich verwende das WPF DataGrid und habe SelectionUnit = "Cell" und SelectionMode = "Extended". Ich versuche auch, die MVVM-Prinzipien so gut wie möglich einzuhalten.WPF Datagrid: MVVM-freundliche Möglichkeit, SelectedCells an mein ViewModel zu binden

Ich brauche mein ViewModel, um die aktuellen SelectedCells zu verfolgen.

Das Leben wäre einfach, wenn ich nur seine SelectedCells-Eigenschaft an mein ViewModel binden könnte. Merkwürdigerweise wird SelectedCells nur einmal ausgelöst - wenn wir zuerst eine Zelle im Raster auswählen.

MS erklärt es hier: http://social.msdn.microsoft.com/Forums/en/wpf/thread/737117f4-6d20-4232-88cf-e52cc44d4431

Kann jemand denken Sie an einem MVVM freundlichen Ansatz um es zu bekommen?

Danke!

Antwort

7

Ich erkennen meine letzte Antwort für SelectedItems war statt selectedCells, so schrieb ich ein komplettes angefügten Eigenschaft Klassendaten zu tun für mehrere selectedCells Bindung, die wie folgt funktioniert:

<controls:DataGrid ItemsSource="{StaticResource list}" 
         SelectionMode="Extended" 
         themes:DataGridHelper.SelectedCells="{Binding Path=myViewModelSourceList, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"              

         />   

ich habe einen Arbeits Quellcode und ein Demo-Projekt davon here.

+0

T.Websters Antwort ist gut, wenn Sie .NET4 verwenden. Offenbar, wenn Sie .NET3.5 verwenden und das DataGrid aus dem WPF-Toolkit nehmen, gibt es wahrscheinlich keine einfache Antwort und Sie müssen das SelectedCellsChanged-Ereignis abfangen und manuell 'myGrid.SelectedCells' holen und es an Ihr ViewModel weitergeben . Ich weiß, es klingt lahm, aber es gibt wahrscheinlich keinen anderen Weg. – GuYsH

+0

Ich überprüft Sie Raster ist ziemlich gut, aber es ist schmerzhaft langsam, wenn wir ein Kontrollkästchen alle Spalten auf einmal aktivieren/deaktivieren – Quantbuff

0

Irgendwo zwischen perfekt MVVM Bindungen und vollständige Event-Handler codebehinds gibt es den grauen Bereich der Interaktivität Eventtriggers (siehe Ausblenden SDK) :)
Wenn Sie einen Eventtrigger an das Datagrid setzen und auf „Selection“ und die EventArgs passieren wie gesagt in dem MS-Thread zu einem Befehl (einen EventToCommand actiontrigger verwenden), um die ausgewählten Elemente aus der EventArgs hoffentlich ...
Oder nutzen Sie die mehrbindigen bekommen könnte :)

+0

TDaver: Es klingt wie eine gute Idee, aber seltsam SelectionChanges wird nicht ausgelöst, wenn eine Zelle ausgewählt ist und das DataGrid auf SelectionMode = Cell gesetzt ist, wie wenn eine Zeile ausgewählt ist, wenn SelectionMode = "FullRow". Es ist seltsam aber wahr ..... – GuYsH

+0

SelectionChanges oder SelectionChanged? – TDaver

+0

Ja und noch eins ... Benötigen Sie die CELLS oder die ITEMS, die in Ihrer VM enthalten sind? Die erste ist nicht großartig MVVM, aber die erste erfordert nur SelectedItems Eigenschaft nicht SelectedCells, und ich glaube, die zweite wird jedes Mal ausgelöst, wenn eine Zelle in einer anderen Zeile ausgewählt wird (da es das gleiche Element ist, wenn die Zellen in der gleichen Zeile sind .. .) – TDaver

1

Sie könnten in der Booklibrary Probe interessiert sein Anwendung der WPF Application Framework (WAF). Es zeigt, wie die DataGrid.SelectedItems mit dem ViewModel synchronisiert werden. Dies könnte SelectedCells sehr ähnlich sein.

+1

Nur um eine kleine Info für andere Leser hinzuzufügen: Das Beispiel basiert auf Code-Behind-Ereignishandlern, die das ViewModel im 'SelectionChangedEvent' aktualisieren, nicht die Datenbindung zwischen einer ViewModel-Eigenschaft und der 'DataGrid.SelectedItems'-Eigenschaft. Trotzdem nützlich, wenn jemand nicht zu strengen MVVM-Regeln folgen möchte. – Slauma

+0

Model-View-ViewModel (MVVM) ist ein Designmuster. Entwurfsmuster beschreiben, wie Objekte interagieren dürfen. Aber sie verbieten nicht Aspekte wie Code-Behind. Wenn Sie sehen, wie Bindung oder Verhalten intern funktionieren, sehen Sie, dass sie auch Methoden auf ViewModels oder Models aufrufen. Dies ist nicht von MVVM verboten. – jbe

2

Benötigen Sie die SelectedCells, die ständig mit Daten verknüpft sind oder nur wenn der Benutzer die OK/Accept-Taste drückt? Wenn Sie es nur am Ende des Prozesses, in dem sich der Benutzer befindet, benötigen, können Sie die SelectedCells beispielsweise an die CommandParameter-Eigenschaft eines Buttons binden. Die SelectedCells ist eine IList, und Sie wissen genug, um einen Cast für jeden Objekttyp durchzuführen, der tatsächlich ausgewählt ist. Die andere Option ist unordentlicher, Sie können eine angefügte Eigenschaft verwenden, um die Ereignisbehandlung aus Ihren Ansichten herauszuhalten. Diese angefügte Eigenschaft würde entweder eine ListBox oder in Ihrem Fall ein DataGrid (MultiSelector) behandeln.

public class Attach 
{ 
    public static IList GetSelectedItems(DependencyObject obj) 
    { 
     return (IList)obj.GetValue(SelectedItemsProperty); 
    } 

    public static void SetSelectedItems(DependencyObject obj, IList value) 
    { 
     obj.SetValue(SelectedItemsProperty, value); 
    } 

    /// <summary> 
    /// Attach this property to expose the read-only SelectedItems property of a MultiSelector for data binding. 
    /// </summary> 
    public static readonly DependencyProperty SelectedItemsProperty = 
     DependencyProperty.RegisterAttached("SelectedItems", typeof(IList), typeof(Attach), new UIPropertyMetadata(new List<object>() as IList, OnSelectedItemsChanged)); 



    static SelectionChangedEventHandler GetSelectionChangedHandler(DependencyObject obj) 
    { 
     return (SelectionChangedEventHandler)obj.GetValue(SelectionChangedHandlerProperty); 
    } 
    static void SetSelectionChangedHandler(DependencyObject obj, SelectionChangedEventHandler value) 
    { 
     obj.SetValue(SelectionChangedHandlerProperty, value); 
    } 
    static readonly DependencyProperty SelectionChangedHandlerProperty = 
     DependencyProperty.RegisterAttached("SelectionChangedHandler", typeof(SelectionChangedEventHandler), typeof(Attach), new UIPropertyMetadata(null)); 


    //d is MultiSelector (d as ListBox not supported) 
    static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs args) 
    { 
     if (GetSelectionChangedHandler(d) != null) 
      return; 

     if (d is MultiSelector)//DataGrid 
     { 
      MultiSelector multiselector = d as MultiSelector; 
      SelectionChangedEventHandler selectionchanged = null; 
      foreach (var selected in GetSelectedItems(d) as IList) 
       multiselector.SelectedItems.Add(selected); 

      selectionchanged = (sender, e) => 
      { 
       SetSelectedItems(d, multiselector.SelectedItems); 
      }; 
      SetSelectionChangedHandler(d, selectionchanged); 
      multiselector.SelectionChanged += GetSelectionChangedHandler(d); 
     } 
     else if (d is ListBox) 
     { 
      ListBox listbox = d as ListBox; 
      SelectionChangedEventHandler selectionchanged = null; 

      selectionchanged = (sender, e) => 
      { 
       SetSelectedItems(d, listbox.SelectedItems); 
      }; 
      SetSelectionChangedHandler(d, selectionchanged); 
      listbox.SelectionChanged += GetSelectionChangedHandler(d); 
     }}} 

Verwendung in XAML:

<DataGrid ItemsSource="{Binding Path=SourceList}" 
       myControls:Attach.SelectedItems="{Binding Path=myMvvmSelectedItems, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
       SelectionMode="Extended" /> 
Verwandte Themen