2012-02-07 65 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> 

第一个组合框用于选择客户。第二个组合框用于为新的OrderLine选择一个ProductCode。

有,我可以不知道如何在MVVM实现项目:
1)当客户选择更新的产品组合框,以便其项目源只能说明具有相同的customerId作为CustomerDto产品在组合框中选择的记录
2)当调用Load时,在Customers组合框中设置SelectedItem,使其显示CustomerId与OrderDto上的CustomerId相等的Customer。
3)应用与1)相同的过程,以便仅显示/装载属于该客户的产品,并在产品组合框上设置SelectedItem,以便它指向具有相同ProductId的条目OrderLineDto

我不知道如何继续,或者即使我有我的viewmodels的责任正确。也许它与NotifyPropertyChanged有关?任何关于如何实现上述目标的指针都将不胜感激。我相信,如果我得到这个权利,它会帮助我在我的应用程序。非常感谢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>(); 
     } 
    } 

回答

4

您需要使Products和Customers类型为ObservableCollection。

在viewmodel中更改这些observablecollections时,它们将更新视图,因为OC已经实现了INotifyPropertyChanged。

Order和CurrentLine应该只是一个类型,并不是所谓的ViewModel。

1)当您选择客户组合框的SelectedItem时调用setter时,您必须执行此操作。

2)您需要在OrderScreenViewModel的ctr中执行此操作,方法是使用您的逻辑来确定客户也要更改CurrentLine.Customer。如果你在ctr中这样做,这将在绑定发生之前设置该值。 3)再一次,只要你修改ObservableCollection组合框绑定到的ObservableCollection,它就会更新UI。如果您对SelectedItem绑定的内容进行了更改,请确保调用RaisedPropertyChanged事件。

ETA:更改XAML这一点,结合SelectedProduct和SelectedCustomer的的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> 

这应该让你在正确的方向开始,一切,所有的逻辑由客户建立的客户和产品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的setter是在WMSOrderViewModel上的,我没有参考OrderScreenViewModel上的产品 - 我如何将这两者连接在一起? – lostinwpf 2012-02-07 23:38:08

+0

会回来给你,并建立一些示例代码 – 2012-02-08 00:43:56

+0

添加了一些代码开始。 – 2012-02-08 17:08:36