Skip to content
Matthieu MEZIL (MSFT) edited this page Jun 7, 2015 · 6 revisions

In previous workshops, you use a combobox to select order details product.

However, if you have thousands of products, the combobox is obviously not the best control.

One solution for this is to use a paginated list.

In this workshop you will create this popup:

WAQS also helps you with pagination.

So now you don't need to load products anymore in CustomerWindowViewModel. You just need to get the ProductFullName with OrderDetails.

So you can use this method:

private async Task LoadAsync(string customerId)
{
    Customer = await _context.Customers.AsAsyncQueryable().FirstOrDefault(c => c.Id == customerId).IncludeOrdersWithExpression(orders => orders.IncludeOrderDetailsWithExpression(ods => ods.WithProductFullName()).WithHasInvoice()).ExecuteAsync();
}

Then update the CustomerWindow.xaml with this xaml.

Create a ProductsWindow.xaml using this one.

Note how easy it is to use pagination:

<ListBox ItemsSource="{Binding ProductsPaginatedQuery.Items}"
         DisplayMemberPath="FullName"
         SelectedItem="{Binding SelectedProduct}" />
<controls:NavigationPanel Source="{Binding ProductsPaginatedQuery}"
                          Grid.Row="1" />

Add the SelectClick method on ProductsWindow.xaml.cs.

Now you will create the ProductsWindowViewModel.

From a WAQS LINQ query, you can call the ToPaginatedQuery method to get a query that manages pagination for you.

public class ProductsWindowViewModel : ViewModelBase
{
    private INorthwindClientContext _context;
    private OrderDetail _orderDetail;

    public ProductsWindowViewModel(INorthwindClientContext context, OrderDetail orderDetail) : base(context)
    {
        _context = context;
        _orderDetail = orderDetail;
        ProductsPaginatedQuery.LoadPage();
    }

    private PaginatedQuery<Product> _productsPaginatedQuery;
    public PaginatedQuery<Product> ProductsPaginatedQuery
    {
        get
        {
            return _productsPaginatedQuery ?? (_productsPaginatedQuery =
                (from p in _context.Products.AsAsyncQueryable()
                let fullName = p.FullName
                orderby fullName, p.Id
                select new Product { Id = p.Id, FullName = fullName })
               .ToPaginatedQuery(10, 
                   callBack: () => NotifyPropertyChanged.RaisePropertyChanged(() => SelectedProduct)));
        }
    }

    public Product SelectedProduct
    {
        get { return _orderDetail.Product; }
        set
        {
            _orderDetail.Product = value;
            if (value != null)
            {
                _orderDetail.ProductFullName = value.FullName;
            }
            NotifyPropertyChanged.RaisePropertyChanged(nameof(SelectedProduct));
        }
    }
}

Then you just have to show the ProductsWindow in the CustomerWindowViewModel from the CustomerWindowViewModel:

private RelayCommand _selectProductCommand;
public ICommand SelectProductCommand
{
    get
    {
        return _selectProductCommand ?? (_selectProductCommand = new RelayCommand(od =>
            {
                var productsWindow = new ProductsWindow(); // this is not good for an MVVM point of view
                var productsWindowViewModel = new ProductsWindowViewModel(_context, (OrderDetail)od);
                productsWindow.DataContext = productsWindowViewModel;
                productsWindow.ShowDialog();
            }));
    }
}

Note that the button bound on the previous command is only visible when the Grid cell is on edit mode.

This works fine but it would be better if, when you edit an existing item, you open the ProductsWindow on the page that contains the current order detail product.

WAQS supports this scenario.

So instead of calling

ProductsPaginatedQuery.LoadPage();

in the ProductsWindowViewModel constructor, you can use this code:

if (orderDetail.ProductId == 0)
{
    ProductsPaginatedQuery.LoadPage();
}
else
{
    ProductsPaginatedQuery.LoadPage(
        new LoadPageParameter { PropertyName = "FullName", Value = orderDetail.ProductFullName },
        new LoadPageParameter { PropertyName = "Id", Value = orderDetail.ProductId });
}

As always, you can get the final solution here.