2016-07-29 19 views
0

Ich habe eine einzige Ansicht, die Aufgaben über ICommand ausführt. Die Ansicht führt eine Aufgabe in einer Liste ausgewählter Elemente aus einer Listenansicht aus. Ich erhalte die Liste der ausgewählten Artikel über das selection_changed-Ereignis im Code dahinter. Die Aktion für diese Elemente wird über einen Befehl ausgeführt. Die Liste der ausgewählten Elemente im Ansichtsmodell stimmt nicht zwischen den beiden Aufrufen überein. Die Liste der ausgewählten Elemente nach der Auswahl der Elemente ist korrekt, die Liste der ausgewählten Elemente, auf die der Befehl verweist, ist leer. Ich habe festgestellt, dass die Liste nicht wiederhergestellt oder gelöscht wird, indem die Speicheradressen der Listen überprüft werden. Die Speicheradressen sind unterschiedlich.Mehrere Instanzen von ViewModel

Warum habe ich zwei Instanzen von SelectedPrices?

anzeigen XAML

... 
<Window.Resources> 
    <viewModels:AdminViewModel x:Key="ViewModel" /> 
</Window.Resources> 
<Window.DataContext> 
    <viewModels:AdminViewModel/> 
</Window.DataContext> 
<ListView x:Name="lvCustomerPrices" 
    HorizontalAlignment="Left" 
    Margin="14,82,0,32" 
    Width="1362" 
    ItemsSource="{Binding Prices}" 
    Grid.ColumnSpan="3" 
    SelectionChanged="lvCustomerPrices_SelectionChanged"> 
... 

Code anzeigen Hinter

public partial class ExportAdminView : Window 
{ 
    protected AdminViewModel ViewModel 
    { 
     get { return (AdminViewModel)Resources["ViewModel"]; } 
    } 

    public ExportAdminView() 
    { 
     InitializeComponent(); 
    } 

    private void lvCustomerPrices_SelectionChanged(object sender, SelectionChangedEventArgs e) 
    { 
     ViewModel.SetSelectedPrices(lvCustomerPrices.SelectedItems.Cast<DailyCustomerPrice>()); 
    } 
} 

Ansicht Modell

public class AdminViewModel : INotifyPropertyChanged 
{ 
    public List<DailyCustomerPrice> SelectedPrices { get; set; } = new List<DailyCustomerPrice>(); 

    public bool CanExportToEmail => (SelectedPrices.Count > 0 && !string.IsNullOrEmpty(ExportEmailAddress)); 

    public ICommand ExportPricesToEmailCommand { get; set; } 

    public AdminViewModel() 
    { 
     ExportPricesToEmailCommand = new RelayCommand(ExportPrices,() => CanExportToEmail); 
     PriceEffectiveDate = DateTime.Now.Date.AddDays(1); 
    } 

    public void SetSelectedPrices(IEnumerable<DailyCustomerPrice> selectedItems) 
    { 
     SelectedPrices.Clear(); 
     SelectedPrices.AddRange(selectedItems); 
    } 
} 

RelayCommand (Ich brauche das, um aufzuräumen und eine separate Klasse für Parameter machen)

public class RelayCommand : ICommand 
{ 
    private Action<object> _executeWithParameter; 
    private Action _execute; 
    private Func<bool> _canExecute; 
    private event EventHandler CanExecuteChangedInternal; 

    public RelayCommand(Action<object> execute) 
     : this(execute, DefaultCanExecute) 
    {} 

    public RelayCommand(Action execute) : this(execute, DefaultCanExecute) 
    {} 

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

     if (canExecute == null) 
      throw new ArgumentNullException(nameof(canExecute)); 

     this._execute = execute; 
     this._canExecute = canExecute; 
    } 


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

     if (canExecute == null) 
     { 
      throw new ArgumentNullException(nameof(canExecute)); 
     } 

     this._executeWithParameter = execute; 
     this._canExecute = canExecute; 
    } 

    public event EventHandler CanExecuteChanged 
    { 
     add 
     { 
      CommandManager.RequerySuggested += value; 
      this.CanExecuteChangedInternal += value; 
     } 

     remove 
     { 
      CommandManager.RequerySuggested -= value; 
      this.CanExecuteChangedInternal -= value; 
     } 
    } 

    public bool CanExecute() 
    { 
     return _canExecute(); 
    } 

    public bool CanExecute(object parameter) 
    { 
     return CanExecute(); 
    } 

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

    bool ICommand.CanExecute(object parameter) 
    { 
     return CanExecute(); 
    } 

    void ICommand.Execute(object parameter) 
    { 
     Execute(); 
    } 

    public void Execute() 
    { 
     _execute(); 
    } 

    public void OnCanExecuteChanged() 
    { 
     EventHandler handler = this.CanExecuteChangedInternal; 
     //DispatcherHelper.BeginInvokeOnUIThread(() => handler.Invoke(this, EventArgs.Empty)); 
     handler?.Invoke(this, EventArgs.Empty); 
    } 

    public void Destroy() 
    { 
     _canExecute =() => false; 
     _executeWithParameter = _ => { return; }; 
     _execute = null; 
    } 

    private static bool DefaultCanExecute() 
    { 
     return true; 
    } 
} 

Die SelectedPrices in der Eigenschaft AdminViewModel.CanExportToEmail haben eine andere Speicheradresse als die SelectedPrices in der Methode SetSelectedPrices.

Ich brauche diese synchron zu sein.

+0

Wenn Sie ein Element zu einem hinzufügen, wird es nicht zu dem anderen hinzugefügt? –

+0

Ja. Elemente, die im SelectionChanged-Ereignis hinzugefügt wurden, sind in der CanExportToEmail-Eigenschaft nicht vorhanden, aber die im selectionChanged-Ereignis hinzugefügten Elemente bleiben in der Kopie der Liste erhalten, wenn das Ereignis erneut ausgelöst wird. Darüber hinaus kann ich Elemente zu der Auflistung "SelectedPrices" in der CanExportToEmail -Eigenschaft über den Debugger hinzufügen, und sie bleiben auch zwischen Anrufen bestehen. – TonyStewart871

+0

Ich denke, es gibt eine Chance, dass Sie zwei Instanzen von 'AdminViewModel' haben; Wenn ja, dann sollte auch der Wert von "this" an diesen beiden Stellen abweichen. –

Antwort

3

Um das Problem zu beheben, entfernen Sie entweder AdminViewModel von XAML oder von Code-Behind.

Um Zugriff darauf in Code-Behind, greifen Sie Ihre AdminViewModel mit (AdminViewModel)this.DataContext.

Prost