本文介绍了MVVM WPF主从组合框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于一些我在堆栈溢出了以前我在MVVM的理解已经取得良好进展的建议。但是,它是当事情开始变得更加复杂,我还在挣扎。



我有以下看法是对输入订单的目的。它势必OrderScreenViewModel的一个DataContext

 <&StackPanel的GT; 
<组合框高度=25WIDTH =100的DisplayMemberPath =CustomerCode的SelectedItem ={绑定路径= Order.Customer}的ItemsSource ={绑定路径=客户}>< /组合框> ;
<组合框高度=25WIDTH =100的DisplayMemberPath =产品代码的SelectedItem ={绑定路径= CurrentLine.Product}的ItemsSource ={绑定路径=产品}>< /组合框> ;
< / StackPanel的>

第一个组合框用来选择客户。第二个组合框用来选择一个新的订单行一个产品代码。



有,我可以不知道如何在MVVM实现项目:结果
1)当客户选择更新的产品组合框,以便其项目源只能说明具有相同的客户ID如在组合框中搜索
选择CustomerDto记录产品的 2):当载荷称为设置的SelectedItem在该客户组合框,使其显示与客户编号客户等于在OrderDto的人。结果
3)应用,同样的过程为1),这样只有产品属于作为被包含在OrderLineDto如果客户示/装入并设置在产品组合框的SelectedItem使得它指向具有相同的产品编号的条目



我不不确定如何操作,甚至如果我有我的ViewModels正确的责任。也许它是与NotifyPropertyChanged?我如何能实现上述任何指针将不胜感激。我相信,如果我得到这个权利会帮我大忙了我的应用程序。 。非常感谢亚历

 公共类OrderScreenViewModel 
{
公共WMSOrderViewModel令{搞定;私人集; }
公共WMSOrderLineViewModel CurrentLine {搞定;私人集; }

公共OrderScreenViewModel()
{
阶=新WMSOrderViewModel();
CurrentLine =新WMSOrderLineViewModel(新OrderLineDto());
}

公共无效负载(INT的orderId)
{
变种orderDto =新OrderDto {客户ID = 1,行=新的List< OrderLineDto> {新OrderLineDto {=产品编号1}}};
阶=新WMSOrderViewModel(orderDto);
}

公开名单< CustomerDto>客户
{
获得{
返回新的List< CustomerDto> {
新CustomerDto {客户ID = 1,CustomerCode =苹果},
新CustomerDto {客户ID = 1,CustomerCode =微软},
};
}
}

公开名单< ProductDto>产品
{
得到
{
返回新的List< ProductDto> {
新ProductDto {客户ID = 1,产品编号= 1,产品代码=P100,说明=百事可乐},
新ProductDto {客户ID = 1,产品编号= 2,产品代码=P110说明=可乐},
新ProductDto {客户ID = 2,产品编号= 3,产品代码=P120,说明=芬达},
新ProductDto {客户ID = 2,产品编号为4,产品代码=P130,说明=雪碧}
};
}
}
公共类WMSOrderLineViewModel
{
私人ProductDto _product;
私人OrderLineDto _orderLineDto;

公共WMSOrderLineViewModel(OrderLineDto orderLineDto)
{
_orderLineDto = orderLineDto;
}

公共ProductDto产品{{返回_product; }
集合{_product =价值; RaisePropertyChanged(产品); }
}

公共类WMSOrderViewModel
{
私人的ObservableCollection< WMSOrderLineViewModel> _lines;
私人OrderDto _orderDto;
公众的ObservableCollection< WMSOrderLineViewModel>行{{返回_lines; }}
私人CustomerDto _customer;

公共CustomerDto客户{{返回_customer;}集合{_customer =价值; RaisePropertyChanged(客户)}

公共WMSOrderViewModel(OrderDto orderDto)
{
_orderDto = orderDto;
_lines =新的ObservableCollection< WMSOrderLineViewModel>();
的foreach(在orderDto.Lines VAR lineDto)
{
_lines.Add(新WMSOrderLineViewModel(lineDto));
}
}

公共WMSOrderViewModel()
{
_lines =新的ObservableCollection< WMSOrderLineViewModel>();
}
}


解决方案

您需要让产品和客户类型的ObservableCollection。



当您更改视图模型这些observablecollections他们将更新视图,因为业主立案法团的已实现INotifyPropertyChanged。



订单和CurrentLine应该只是一个类型,并没有真正被称为视图模型。



1)你'重新将不得不这样做时,调用setter时对客户组合框被选中的的SelectedItem。



2)你需要做到这一点可能是CTR通过使用你的逻辑,以确定哪些客户改变CurrentLine.Customer太OrderScreenViewModel。如果你这样做的点击率,结合发生之前,这将设置的值。



3)此外,只要您进行更改的ObservableCollection组合框必然,这将更新UI。如果你更改了什么的SelectedItem势必只是确保你叫RaisedPropertyChanged事件



ETA:更改XAML这一点,绑定到SelectedProduct和SelectedCustomer为性能的SelectedItem

 <&StackPanel的GT; 
<组合框高度=25WIDTH =100的DisplayMemberPath =CustomerCode的SelectedItem ={绑定路径= SelectedCustomer}的ItemsSource ={绑定路径=客户}>< /组合框>
<组合框高度=25WIDTH =100的DisplayMemberPath =产品代码的SelectedItem ={绑定路径= SelectedProduct}的ItemsSource ={绑定路径=产品}>< /组合框>
< / StackPanel的>

这应该让你在正确的方向开始,应有尽有,所有的逻辑由建立的客户和产品。客户ID需要在你的仓库发生

 公共类OrderScreenViewModel:INotifyPropertyChanged的
{
私人只读IProductRepository _productRepository;
私人只读ICustomerRepository _customerRepository;

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

BuildCustomersCollection();
}

私人无效BuildCustomersCollection()
{
VAR的客户= _customerRepository.GetAll();
的foreach(在客户VAR客户)
_customers.Add(客户);
}

私人的ObservableCollection<客户> _customers =新的ObservableCollection<客户>();
公众的ObservableCollection<客户>客户
{
{返回_customers; }
私人集合{_customers =价值; }
}

私人的ObservableCollection<产品与GT; _产品展示=新的ObservableCollection<产品及GT;();
公众的ObservableCollection<产品与GT;产品
{
得到{_产品展示; }
私人集合{_产品展示=价值; }
}

私人客户_selectedCustomer;
公共客户SelectedCustomer
{
{返回_selectedCustomer; }

{
_selectedCustomer =价值;
的PropertyChanged(这一点,新PropertyChangedEventArgs(SelectedCustomer));
BuildProductsCollectionByCustomer();
}
}

私人产品_selectedProduct;
公共产品SelectedProduct
{
{返回_selectedProduct; }

{
_selectedProduct =价值;
的PropertyChanged(这一点,新PropertyChangedEventArgs(SelectedProduct));
DoSomethingWhenSelectedPropertyIsSet();
}
}

私人无效DoSomethingWhenSelectedPropertyIsSet()
{
//省略
}

私人无效BuildProductsCollectionByCustomer()
{
VAR productsForCustomer = _productRepository.GetById(_selectedCustomer.Id);
的foreach(在产品增值版产品)
{
_products.Add(产品);
}
}

公共事件PropertyChangedEventHandler的PropertyChanged =委托{};
}

公共接口ICustomerRepository:IRepository<客户>
{
}

公共类客户
{
公众诠释标识{搞定;组; }
}

公共接口IProductRepository:IRepository<产品与GT;
{
}

公共类产品
{
}

下面就是标准的IRepository的样子,这就是所谓的存储库模式:

 公开接口IRepository< T> 
{
IEnumerable的< T>得到所有(); $ B $(B T)GetById(INT ID);
无效保存(T saveThis);
无效删除(T deleteThis);
}


Thanks to some of the advice I have got previously on Stack Overflow I have been making good progress in my understanding of MVVM. However, it is when things start to get more complicated that I am still struggling.

I have the view below which is for the purpose of entering orders. It is bound to a DataContext of 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>

The first combobox is used to select a Customer. The second combobox is used to select a ProductCode for a new OrderLine.

There are the items that I cannot work out how to achieve in MVVM:
1) When a Customer is selected update the Products combobox so that its item source only shows Products that have the same CustomerId as the CustomerDto record selected in the combobox
2) When Load is called set the SelectedItem in the Customers combobox so that it displays the Customer with the CustomerId equal to the one on the OrderDto.
3) Apply, the same process as 1) so that only Products belonging to that Customer are shown / loaded and set the SelectedItem on the Products combobox so that it is pointing to the entry with the same ProductId as is contained on the OrderLineDto

I am not sure how to proceed or even if I have got the responsibilities of my viewmodels correct. Maybe it has something to do with NotifyPropertyChanged? Any pointers on how I can achieve the above will be greatly appreciated. I am sure if I get this right it will help me greatly in my app. Many thanks 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>();
        }
    }
解决方案

You need to make Products and Customers type ObservableCollection.

When you change these observablecollections in your viewmodel they will update the view, because OC's already implement INotifyPropertyChanged.

Order and CurrentLine should just be a type and not really be called a ViewModel.

1) You're going to have to do this when the setter is called on the SelectedItem of the Customer combobox is selected.

2) You'll need to do this probably in the ctr of the OrderScreenViewModel by using your logic to determine what Customer to change the CurrentLine.Customer too. If you do this in the ctr, this will set the value before the binding takes place.

3) Again, as long as you make changes to the ObservableCollection the combobox is bound to, it will update the UI. If you make a change to what the SelectedItem is bound to just make sure you call RaisedPropertyChanged event.

ETA: Change the xaml to this, bind to SelectedProduct and SelectedCustomer for the SelectedItem properties

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

this should get you started in the right direction, everything, all logic for building customers and products by the customer id needs to happen in your repositories.

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

Here's what the standard IRepository looks like, this is called the Repository Pattern:

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

这篇关于MVVM WPF主从组合框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-07 09:07