2016-03-29 1 views
0

Ich könnte Hilfe verwenden, versuchen zu verstehen, wie die Befehle in Wpf mit Mvvm funktionieren und wie Sie eine Schaltfläche an sie binden. Habe viele Artikel über Befehle und WPF gelesen, aber sie scheinen alle unterschiedlich zu sein.Erstellen Sie einen Suchbefehl in WPF mit Mvvm, das neue Daten in meine Listenansicht lädt

Ich habe ein WPF-Projekt mit MVVM-Muster erstellt. Haben Sie eine Listenansicht, die mit Kunden gefüllt wird.

Jetzt möchte ich einen Suchbefehl machen, damit ich die Daten in der Listenansicht ändern kann.

CustomerViewModel

public class CustomerViewModel : INotifyPropertyChanged, ICommand 
{ 
    private List<Customer> CustomerList; 

    public CustomerViewModel() 
    { 
     CustomerList = LoadCustomerData(); 
    } 

    public List<Customer> LoadCustomerData() 
    { 
     List<Customer> data = new List<Customer>(); 
     data.Add(new Customer() { Id = 1, FirstName = "Alexander", LastName = "Malkovich", PhoneNumber = "43215678", Email = "[email protected]" }); 
     data.Add(new Customer() { Id = 2, FirstName = "Mikkel", LastName = "Larsen", PhoneNumber = "87654321", Email = "[email protected]" }); 

     return data; 
    } 

    public List<Customer> CustomerDataLoadedOnSearch() 
    { 
     List<Customer> data = new List<Customer>(); 
     data.Add(new Customer() { Id = 1, FirstName = "Ulrik", LastName = "Trissel", PhoneNumber = "35325235", Email = "[email protected]" }); 
     data.Add(new Customer() { Id = 2, FirstName = "Michael", LastName = "Mortensen", PhoneNumber = "14214124", Email = "[email protected]" }); 

     return data; 
    } 

    public List<Customer> Customer 
    { 
     get 
     { 
      return CustomerList; 

     } 

    } 

    // Search Command 


    #region INotifyPropertyChanged members 

    public event PropertyChangedEventHandler PropertyChanged; 

    private void OnPropertyChanged(string propertyName) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 

     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    #endregion 

} 

Grundsätzlich laufe ich die LoadCustomerData() in der Ctor, und bekommt das Customer mit der get-Methode.

Ich versuche, einen Suchbefehl zu erstellen, der die andere Methode (CustomerDataLoadedOnSearch) ausführen wird, und dann den Aufruf erneut in der Ansicht auslösen.

XML-Ansicht Code:

<StackPanel Orientation="Vertical"> 
      <Button Command="{Binding SearchCommand}" Padding="15, 5" HorizontalAlignment="Right">Search</Button> 
     </StackPanel> 
     <GroupBox Header="Customers"> 
      <StackPanel Margin="10, 10" Orientation="Vertical"> 
       <ListView Height="250" Width="Auto" ItemsSource="{Binding Customer}" Grid.Row="1"> 
        <ListView.View> 
         <GridView > 
          <GridViewColumn Header="ID" Width="Auto"> 
           <GridViewColumn.CellTemplate> 
            <DataTemplate> 
             <TextBlock Text="{Binding Id}" TextAlignment="Right" Width="40"/> 
            </DataTemplate> 
           </GridViewColumn.CellTemplate> 
          </GridViewColumn> 
          <GridViewColumn DisplayMemberBinding="{Binding FirstName}" Header="First name" Width="100"/> 
          <GridViewColumn DisplayMemberBinding="{Binding LastName}" Header="Last name" Width="100"/> 
          <GridViewColumn DisplayMemberBinding="{Binding PhoneNumber}" Header="Phone" Width="100"/> 
          <GridViewColumn DisplayMemberBinding="{Binding Email}" Header="Email" Width="200"/> 
         </GridView> 
        </ListView.View> 
       </ListView> 
      </StackPanel> 
     </GroupBox> 

Haben Sie einen Befehl namens SearchCommand binded. Jetzt bin ich mir nicht so sicher, was ich als nächstes tun soll. Soll ich einen Ordner mit dem Namen "Command" erstellen und alle Befehle dort für alle meine Buttons speichern?

Oder sollte ich den gesamten ICommand-Code im ViewModel behalten? Hoffe jemand kann mir zeigen, wie das geht.

Guten Tag.

Update:

Bisher Dank für Ihre replys.

Ich habe es geschafft, die ViewModelBase & RelayCommand-Klasse zu implementieren. Außerdem habe ich den Befehl der Suchschaltfläche implementiert, aber wenn ich darauf klicke, wird die Liste gelöscht (die Ansicht verliert ihre Kunden).

void SearchCommand_DoWork(object obj) 
{ 
    CustomerList.Clear(); 
    CustomerList = CustomerDataLoadedOnSearch();    
} 

Haben die Customer debuggt und als ich die CustomerDataLoadedOnSearch nennen, haben es zwei Reihen mit neuen Kunden innen, aber die Liste hasen't besiedelt.

+0

Verwenden Sie ein Framework, zum Beispiel mvvm light? – sexta13

+0

Nein, habe 3 Ordner namens Models, ViewModels und Views gemacht :) Ist es viel einfacher mit Mvvm Licht? – Mikkel

+0

Es wird Ihr Leben in einigen Punkten erleichtern. Du wirst einen IoC haben, einen Messenger haben um zu kommunizieren wenn nötig ... unter vielen anderen Dingen – sexta13

Antwort

1

Lassen Sie mich versuchen, dies zu beantworten und ich hoffe, dass dies die Dinge ein wenig für Sie klären wird.

Wie sexta13 sagte, gibt es einige Frameworks, die Sie verwenden können. Persönlich mag ich sie überhaupt nicht.

Was ich stattdessen tun soll ist RelayCommand zu implementieren, das ist die einfachste Lösung meiner Meinung nach.

RelayCommand:

public class RelayCommand : ICommand 
{ 
    readonly Action<object> _execute; 
    readonly Func<bool> _canExecute; 

    public RelayCommand(Action<object> execute, Func<bool> canExecute = null) 
    { 
     if (execute == null) 
      throw new ArgumentNullException(nameof(execute)); 

     _execute = execute; 
     _canExecute = canExecute; 
    } 

    public bool CanExecute(object parameter) 
    { 
     return _canExecute == null || _canExecute.Invoke(); 
    } 

    public event EventHandler CanExecuteChanged 
    { 
     add { CommandManager.RequerySuggested += value; } 
     remove { CommandManager.RequerySuggested -= value; } 
    } 

    public void Execute(object parameter) 
    { 
     _execute(parameter); 
    } 
} 

Darüber hinaus implementieren ich ViewModelBase, die wie folgt aussieht:

public abstract class ViewModelBase : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    protected void OnPropertyChanged(string propertyName) 
    { 
     VerifyPropertyName(propertyName); 

     var handler = PropertyChanged; 
     if (handler == null) return; 
     var e = new PropertyChangedEventArgs(propertyName); 
     handler(this, e); 
    } 

    [Conditional("DEBUG")] 
    [DebuggerStepThrough] 
    private void VerifyPropertyName(string propertyName) 
    { 
     // Verify that the property name matches a real, 
     // public, instance property on this object. 
     if (TypeDescriptor.GetProperties(this)[propertyName] != null) return; 
     var msg = "Invalid property name: " + propertyName; 
     Debug.WriteLine(msg); 
    } 
} 

Mit diesen beiden Klassen, die Sie bereit sind, MVVM zu gehen.

Und zurück zu Ihrem Beispiel:

Zu allererst Ihre private List<Customer> CustomerList; sollte public und nicht private sein. Und dann sollte es Getter und Setter haben. Andernfalls wird es von Ihrer Ansicht nicht erreichbar sein.

public List<Customer> CustomerList{get; private set} 

Wenn dies gesagt ist, dann werde ich vorschlagen, dass Sie ObservableCollection<T> anstelle eines List<T> verwenden. Observable collections implementiert INotifyPropertyChanged, und jedes Mal, wenn Ihre Sammlung geändert wird, wird Ihre view wissen. Wenn Sie List<T> verwenden, müssen Sie Ihrer Ansicht manuell mitteilen, dass sich die Sammlung geändert hat.

Wenn dies geschehen ist, dann können Sie einen Befehl in Ihrer VM erstellen:

public ICommand SearchCommand{get;set;} 

public CustomerViewModel() 
{ 
    CustomerList = LoadCustomerData(); 
    SearchCommand = new RelayCommand(SearchCommand_DoWork,()=>false); 
} 

void SearchCommand_DoWork(object obj) 
{ 
    CustomerList.Clear(); 
    CustomerList.Add(New Customer()); //Or iterate the search list to your collection. 
} 

Der ()=>false Teil der Aufgabe des Befehls ist optional. Wenn Sie das Feld leer lassen, wird die Suchschaltfläche aktiviert. Wenn Sie dieses Beispiel mögen, verwenden Sie ()=>false, es wird immer deaktiviert. Sie können ein anderes Attribut oder einen anderen Delegaten verwenden, der einen booleschen Wert zurückgibt.

+0

Bitte beachten Sie mein Update. – Mikkel

+0

Mikkel, was auch immer Sie in der 'CustomerDataLoadedOnSearch();' Tun Sie es im Suchbefehl und anstelle von CustomerList = CustomerDataLoadedOnSearch(); dann benutze CustomerList.Add() und füge die neuen Elemente zur Liste hinzu ... –

+0

Okay, werde ich versuchen. gib mir 5min :) – Mikkel