2016-07-29 4 views
0

私は、ICommandを介してタスクを実行する単一のビューを持っています。ビューは、リストビューから選択した項目のリストに対してタスクを実行します。私は選択された項目のリストをコードのselection_changedイベント経由で取得します。これらの項目に対するアクションは、コマンドによって実行されます。ビューモデル内の選択された項目のリストが、2つの呼び出し間で一致しません。アイテムが選択された後に選択されたアイテムのリストが正しい場合、コマンドによって参照される選択されたアイテムのリストは空です。リストのメモリアドレスをチェックすることによって、リストが再インスタンス化されていないか、またはクリアされていないと判断しました。メモリアドレスは異なります。ViewModelの複数のインスタンス

SelectedPricesのインスタンスが2つあるのはなぜですか?

ビュー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"> 
... 

コードの表示

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>()); 
    } 
} 

ビューモデル

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(私はこれをクリーンアップし、パラメータの別のクラスを作成する必要があります)の後ろ

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; 
    } 
} 

AdminViewModel.CanExportToEmailプロパティのSelectedPricesには、SetSelectedPricesメソッドのSelectedPricesとは異なるメモリアドレスがあります。

これらは同期する必要があります。

+0

アイテムを1つに追加すると、もう一方のアイテムに追加されませんか? –

+0

はい。 SelectionChangedイベントで追加されたアイテムはCanExportToEmailプロパティには存在しませんが、selectionChangedイベントで追加されたアイテムは、イベントが再び発生したときにリストのコピーを保持します。また、アイテムをCanExportToEmailプロパティのSelectedPricesコレクションにデバッガ経由で追加することもできます。 – TonyStewart871

+0

私は 'AdminViewModel'の2つのインスタンスがあると思います。もしそうなら、その2つの場所における 'this 'の値も異なっているはずです。 –

答えて

3

問題を解決するには、AdminViewModelをXAMLまたはコードビハインドから削除します。

コードビハインドでアクセスするには、AdminViewModel(AdminViewModel)this.DataContextで取得します。

乾杯

関連する問題