2012-02-07 24 views
5

Grazie ad alcuni dei consigli che ho ricevuto in precedenza su Stack Overflow, ho compiuto notevoli progressi nella comprensione di MVVM. Tuttavia, è quando le cose cominciano a diventare più complicate che sto ancora lottando.MVVM WPF Dettagli principali Combobox

Ho la vista qui sotto che è per lo scopo di inserire ordini. È associato a un DataContext di OrderScreenViewModel.

<StackPanel> 
    <ComboBox Height="25" Width="100" DisplayMemberPath="CustomerCode" SelectedItem="{Binding Path=Order.Customer}" ItemsSource="{Binding Path=Customers}"></ComboBox> 
    <ComboBox Height="25" Width="100" DisplayMemberPath="ProductCode" SelectedItem="{Binding Path=CurrentLine.Product}" ItemsSource="{Binding Path=Products}"></ComboBox> 
</StackPanel> 

La prima casella combinata viene utilizzata per selezionare un cliente. La seconda casella combinata viene utilizzata per selezionare un ProductCode per una nuova OrderLine.

Ci sono le voci che non riesco a capire come ottenere in MVVM:
1) quando un cliente si seleziona aggiornare i prodotti casella combinata in modo che la sua fonte voce mostra solo i prodotti che hanno la stessa CustomerId come il CustomerDto record selezionato nella casella combinata
2) Quando viene chiamato Carica l'oggetto selezionato nella casella combinata Clienti in modo che visualizzi il cliente con l'ID cliente uguale a quello sul OrderDto.
3) Applicare, lo stesso processo di 1) in modo che solo i Prodotti appartenenti a quel Cliente siano visualizzati/caricati e impostare l'Oggetto Selezionato sulla casella combinata Prodotti in modo che punti alla voce con la stessa ID Prodotto come è contenuta in the OrderLineDto

Non sono sicuro di come procedere o anche se ho corretto le responsabilità dei miei modelli di visualizzazione. Forse ha qualcosa a che fare con NotifyPropertyChanged? Qualsiasi suggerimento su come posso ottenere quanto sopra sarà molto apprezzato. Sono sicuro che se avrò ragione mi aiuterà molto nella mia app. Mille grazie, Alex.

public class OrderScreenViewModel 
    { 
     public WMSOrderViewModel Order { get; private set; } 
     public WMSOrderLineViewModel CurrentLine { get; private set; } 

     public OrderScreenViewModel() 
     { 
      Order = new WMSOrderViewModel(); 
      CurrentLine = new WMSOrderLineViewModel(new OrderLineDto()); 
     } 

     public void Load(int orderId) 
     { 
      var orderDto = new OrderDto { CustomerId = 1, Lines = new List<OrderLineDto> { new OrderLineDto{ProductId = 1 }} }; 
      Order = new WMSOrderViewModel(orderDto); 
     } 

     public List<CustomerDto> Customers 
     { 
      get{ 
       return new List<CustomerDto> { 
         new CustomerDto{CustomerId=1,CustomerCode="Apple"}, 
         new CustomerDto{CustomerId=1,CustomerCode="Microsoft"}, 
       }; 
      } 
     } 

     public List<ProductDto> Products 
     { 
      get 
      { 
       return new List<ProductDto> { 
        new ProductDto{CustomerId=1,ProductId=1,ProductCode="P100",Description="Pepsi"}, 
        new ProductDto{CustomerId=1,ProductId=2,ProductCode="P110",Description="Coke"}, 
        new ProductDto{CustomerId=2,ProductId=3,ProductCode="P120",Description="Fanta"}, 
        new ProductDto{CustomerId=2,ProductId=4,ProductCode="P130",Description="Sprite"} 
       }; 
      } 
     } 
    public class WMSOrderLineViewModel 
    { 
     private ProductDto _product; 
     private OrderLineDto _orderLineDto; 

     public WMSOrderLineViewModel(OrderLineDto orderLineDto) 
     { 
      _orderLineDto = orderLineDto; 
     } 

     public ProductDto Product { get { return _product; } 
      set{_product = value; RaisePropertyChanged("Product"); } 
    } 

    public class WMSOrderViewModel 
    { 
     private ObservableCollection<WMSOrderLineViewModel> _lines; 
     private OrderDto _orderDto; 
     public ObservableCollection<WMSOrderLineViewModel> Lines { get { return _lines; } } 
     private CustomerDto _customer; 

     public CustomerDto Customer { get{return _customer;} set{_customer =value; RaisePropertyChanged("Customer") } 

     public WMSOrderViewModel(OrderDto orderDto) 
     { 
      _orderDto = orderDto; 
      _lines = new ObservableCollection<WMSOrderLineViewModel>(); 
      foreach(var lineDto in orderDto.Lines) 
      { 
       _lines.Add(new WMSOrderLineViewModel(lineDto)); 
      } 
     } 

     public WMSOrderViewModel() 
     { 
      _lines = new ObservableCollection<WMSOrderLineViewModel>(); 
     } 
    } 

risposta

4

È necessario creare prodotti e clienti come ObservableCollection.

Quando si modificano queste osservazioni nella viewmodel, la vista verrà aggiornata, poiché OC implementa già INotifyPropertyChanged.

Order e CurrentLine dovrebbero essere solo un tipo e non essere realmente chiamati ViewModel.

1) Dovrete farlo quando viene chiamato il setter sull'oggetto Selected della casella combinata Cliente.

2) È necessario eseguire questa operazione probabilmente nel ctr di OrderScreenViewModel utilizzando la logica per determinare quale Cliente modificare anche il cliente di CurrentLine. Se lo fai nel ctr, questo imposterà il valore prima che l'associazione abbia luogo.

3) Di nuovo, finché si apportano modifiche a ObservableCollection a cui è associata la casella combinata, aggiornerà l'interfaccia utente. Se apporti una modifica a ciò che l'oggetto SelectedItem è associato, assicurati di chiamare l'evento RaisedPropertyChanged.

ETA: Modificare il codice XAML per questo, l'associazione a SelectedProduct e SelectedCustomer per le proprietà SelectedItem

<StackPanel> 
    <ComboBox Height="25" Width="100" DisplayMemberPath="CustomerCode" SelectedItem="{Binding Path=SelectedCustomer}" ItemsSource="{Binding Path=Customers}"></ComboBox> 
    <ComboBox Height="25" Width="100" DisplayMemberPath="ProductCode" SelectedItem="{Binding Path=SelectedProduct}" ItemsSource="{Binding Path=Products}"></ComboBox> 
</StackPanel> 

questo dovrebbe iniziare nella giusta direzione, tutto, tutta la logica per la costruzione di clienti e prodotti da parte del cliente id deve succedere nei tuoi repository.

public class OrderScreenViewModel : INotifyPropertyChanged 
    { 
     private readonly IProductRepository _productRepository; 
     private readonly ICustomerRepository _customerRepository; 

     public OrderScreenViewModel(IProductRepository productRepository, 
     ICustomerRepository customerRepository) 
     { 
     _productRepository = productRepository; 
     _customerRepository = customerRepository; 

     BuildCustomersCollection(); 
     } 

     private void BuildCustomersCollection() 
     { 
     var customers = _customerRepository.GetAll(); 
     foreach (var customer in customers) 
      _customers.Add(customer); 
     } 

     private ObservableCollection<Customer> _customers = new ObservableCollection<Customer>(); 
     public ObservableCollection<Customer> Customers 
     { 
     get { return _customers; } 
     private set { _customers = value; } 
     } 

     private ObservableCollection<Product> _products = new ObservableCollection<Product>(); 
     public ObservableCollection<Product> Products 
     { 
     get { return _products; } 
     private set { _products = value; } 
     } 

     private Customer _selectedCustomer; 
     public Customer SelectedCustomer 
     { 
     get { return _selectedCustomer; } 
     set 
     { 
      _selectedCustomer = value; 
      PropertyChanged(this, new PropertyChangedEventArgs("SelectedCustomer")); 
      BuildProductsCollectionByCustomer(); 
     } 
     } 

     private Product _selectedProduct; 
     public Product SelectedProduct 
     { 
     get { return _selectedProduct; } 
     set 
     { 
      _selectedProduct = value; 
      PropertyChanged(this, new PropertyChangedEventArgs("SelectedProduct")); 
      DoSomethingWhenSelectedPropertyIsSet(); 
     } 
     } 

     private void DoSomethingWhenSelectedPropertyIsSet() 
     { 
     // elided 
     } 

     private void BuildProductsCollectionByCustomer() 
     { 
     var productsForCustomer = _productRepository.GetById(_selectedCustomer.Id); 
     foreach (var product in Products) 
     { 
      _products.Add(product); 
     } 
     } 

     public event PropertyChangedEventHandler PropertyChanged = delegate { }; 
    } 

    public interface ICustomerRepository : IRepository<Customer> 
    { 
    } 

    public class Customer 
    { 
     public int Id { get; set; } 
    } 

    public interface IProductRepository : IRepository<Product> 
    { 
    } 

    public class Product 
    { 
    } 

Ecco ciò che la norma IRepository sembra, questo è chiamato il Pattern Repository:

public interface IRepository<T> 
    { 
     IEnumerable<T> GetAll(); 
     T GetById(int id); 
     void Save(T saveThis); 
     void Delete(T deleteThis); 
    } 
+0

Quando si dice Ordine e CurrentLine dovrebbe essere solo un tipo si fa a dire come OrderDto? Con riferimento a 1) è quello che pensavo avrei dovuto fare. Mi blocco un po 'perché il setter per il cliente è su WMSOrderViewModel e non ho alcun riferimento ai prodotti su OrderScreenViewModel da qui - come faccio a collegarli insieme? – lostinwpf

+0

Tornerà da te e costruirà il codice di esempio –

+0

aggiunto del codice per iniziare. –