2012-02-07 15 views
5

私は以前、スタックオーバーフローに関する助言をいただきましたので、私はMVVMの理解を進めています。しかし、物事がより複雑になり始めて、私はまだ苦労しています。MVVM WPFマスター詳細コンボボックス

私は下に注文を入力するためのビューを持っています。これは、OrderScreenViewModelのDataContextにバインドされています。

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

最初のコンボボックスは、顧客を選択するために使用されます。 2番目のコンボボックスは、新しいOrderLineのProductCodeを選択するために使用されます。

私はMVVMで達成する方法を考え出すことができない項目があります。お客様が選択されている場合、その項目のソースが唯一CustomerDtoと同じ得意先持っている製品を表示されるように
1)は、製品のコンボボックスを更新コンボボックスで選択したレコード
2) Loadが呼び出されると、CustomersコンボボックスにSelectedItemを設定して、OrderDtoのCustomerIdと等しいCustomerIdを持つCustomerを表示します。
3) 1)と同じプロセスを適用して、その顧客に属する製品のみが表示/ロードされ、製品コンボボックスにSelectedItemが設定され、同じProductIdのエントリを指し示すように設定されますOrderLineDto

私はどのように進むか、または私が自分のビューモデルの責任を正しく持っているかどうかはわかりません。たぶんNotifyPropertyChangedと関係がありますか?どのように私は上記を達成することができます上の任意のポインターは大いに感謝されます。私はこれが私のアプリで大きく役立つだろうと確信しています。多くの感謝のアレックス。

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

答えて

4

ObservableCollectionと入力する必要があります。

ビューモデルでこれらの観察可能なコレクションを変更すると、OCはすでにINotifyPropertyChangedを実装しているため、ビューを更新します。

OrderとCurrentLineは実際にはViewModelと呼ばれることはありません。

1)CustomerコンボボックスのSelectedItemでセッターが呼び出されたときにこれを行う必要があります。

2)これは、お客様のロジックを使用してCurrentLine.Customerを変更する顧客を決定することによって、おそらくOrderScreenViewModelのctrで行う必要があります。 ctrでこれを行うと、バインディングが行われる前に値が設定されます。

3)また、ObservableCollectionを変更してコンボボックスにバインドすると、UIが更新されます。 SelectedItemがバインドされているものに変更を加えた場合は、RaisedPropertyChangedイベントを必ず呼び出してください。

ETA:、すべてのもの、これはあなたが正しい方向に始める必要があるの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> 

ためSelectedProductとSelectedCustomerに結合し、これに顧客が顧客や製品を構築するためのすべてのロジックをXAMLを変更IDはあなたのリポジトリで起こる必要があります。ここで

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

これは、リポジトリパターンと呼ばれ、標準IRepositoryは次のようになります。

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

あなたが注文とCurrentLineはちょうどあなたがOrderDtoのような意味ですかタイプのものでなければならないと言いますか? 1)を参照すると、それは私が行う必要があると思ったものです。 CustomerのセッターがWMSOrderViewModel上にあり、ここからOrderScreenViewModel上のProductsへの参照がありません。これらの2つをリンクするにはどうすればいいですか? – lostinwpf

+0

あなたに戻り、いくつかのサンプルコードを作成します –

+0

にはいくつかのコードを追加しました。 –

関連する問題