[英]MVVM WPF Master Detail Comboboxes
感謝我之前在Stack Overflow上提出的一些建議,我在理解MVVM方面取得了很好的進展。 然而,當事情開始變得更加復雜時,我仍然在苦苦掙扎。
我在下面的視圖是為了輸入訂單。 它綁定到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)選擇客戶時更新Products組合框,以便其項目源僅顯示與組合框中選擇的CustomerDto記錄具有相同CustomerId的產品
2)當調用Load時,在Customers組合框中設置SelectedItem,以便它顯示CustomerId等於OrderDto上的CustomerId。
3)應用與1)相同的過程,以便只顯示/加載屬於該Customer的產品,並在Products組合框上設置SelectedItem,使其指向與OrderLineDto中包含的ProductId相同的條目
我不知道如何繼續,或者即使我的視圖模型的責任是正確的。 也許它與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>();
}
}
您需要使產品和客戶鍵入ObservableCollection。
當您在viewmodel中更改這些observablecollections時,它們將更新視圖,因為OC已經實現了INotifyPropertyChanged。
Order和CurrentLine應該只是一種類型而不是真正的ViewModel。
1)當選擇Customer組合框的SelectedItem上調用setter時,你將不得不這樣做。
2)您可能需要在OrderScreenViewModel的ctr中執行此操作,方法是使用您的邏輯來確定哪些Customer也可以更改CurrentLine.Customer。 如果在ctr中執行此操作,則將在綁定發生之前設置該值。
3)同樣,只要你對組合框綁定的ObservableCollection進行更改,它就會更新UI。 如果您對SelectedItem綁定的內容進行了更改,請確保調用RaisedPropertyChanged事件。
ETA:將xaml更改為this,綁定到SelectedItem屬性的SelectedProduct和SelectedCustomer
<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);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.