- The product classes implement IProduct.Description and Price.
- Each Description uses the exact product-specific format below.
- Changes to description inputs raise a Description notification through the product view model.
11.5 Assignment
Work through the stories in order. Use the acceptance criteria to check each feature, and complete the nested tasks using the specified names, values, and scenarios.
Implement the IProduct interface in the product classes. The Description properties for each of the products should return a concatenated string formatted as shown below:
DisinfectingWipes: "{Brand} {Name} - {WipeCount} count"
HandSanitizer: "{Brand} {Name} - {FluidOunces}FL OZ"
ToiletPaper: "{Brand} {Name} - {NumberOfRolls} rolls"In each of the product view model's HandlePropertyChanged, also call OnPropertyChanged and pass in "Description" if the PropertyChangedEventArgs parameter's PropertyName is one of the properties that is part of the description.
In each of the properties, get or set the LineItemViewModel's Entity corresponding property. Call OnPropertyChanged and pass in the property name in each of the setters.
For ProductDescription and ProductPrice, return the Entity's Product's Description and Price.
Change the instantiation of the obj variable to use the selected type instead.
This will hold your line item's product.
Instantiate a new LineItem object and assign its Product property to the variable holding your line item's product.
Instantiate a new LineItemViewModel object passing in the LineItem object into the constructor.
Pass the LineItemViewModel object into the EntityWindow's constructor.
We want to be able to edit a line item's product and change its properties. We are going to add a button that launches a new window with controls for the product.
using System;
using System.Windows.Input;
namespace ReflectionScenario
{
public class DelegateCommand : ICommand
{
private readonly Action<object> command;
private readonly Predicate<object> canExecute;
public DelegateCommand(Action<object> command)
: this(command, null)
{
}
public DelegateCommand(Action<object> command, Predicate<object> canExecute)
{
if (command == null)
{
throw new Exception("Command was null.");
}
this.command = command;
this.canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
public bool CanExecute(object parameter)
{
return this.canExecute == null ? true : this.canExecute(parameter);
}
public void Execute(object parameter)
{
this.command(parameter);
}
}
}Instantiate the dictionary at the field definition and add entries for each of the products and their corresponding view models. Use the type of the model as the key.
Get the line item's product's corresponding view model using the ViewModelConverter's ModelToViewModel.
Use Activator.CreateInstance to create an instance of the proper view model. Also pass in the line item's Product into the call to CreateInstance.
Attach the LineItemViewModel's HandlePropertyChanged to the view model's PropertyChanged.
Cast the viewModel as an INotifyPropertyChanged.
Instantiate a new EntityWindow and pass in the view model.
Call ShowDialog on the window.
return new DelegateCommand(c => this.EditProduct());Edit the values of the product. Any changes that affect the product's price and description should automatically appear in the line item's window.
Pending,
Shipped,
InTransit,
Delivered,/// <summary>
/// The order's customer.
/// </summary>
/// <summary>
/// The order's customer.
/// </summary>
public string Customer { get; set; }
/// <summary>
/// The date the order was placed.
/// </summary>
/// <summary>
/// The date the order was placed.
/// </summary>
public DateTime OrderDate { get; set; }
/// <summary>
/// The order's shipping status.
/// </summary>
/// <summary>
/// The order's shipping status.
/// </summary>
public ShippingStatus ShippingStatus { get; set; }In each of the properties, get and/or set the Entity's corresponding property. In the setters, also call OnPropertyChanged and pass in the name of the property.
In the HandlePropertyChanged method, if the PropertyChangedEventArgs parameter's PropertyName is "CalculatedCost", call OnPropertyChanged and pass in "OrderTotal".
Instantiate a new LineItemViewModel passing in the lineItem.
Attach the OrderViewModel's HandlePropertyChanged method to the view model's PropertyChanged.
Add the view model to the LineItemViewModels's AllEntities.
Instantiate the lineItemViewModels field.
For each line item in the order's line items, call OnEntityAdded and pass in the line item.
public static bool HasColumn(MemberInfo memberInfo)
{
}
public static string GetColumnDescription(MemberInfo memberInfo)
{
}
public static int GetColumnSequence(MemberInfo memberInfo)
{
}
public static int GetColumnWidth(MemberInfo memberInfo)
{
}Get the column description, width, and control type from the property and store them in variables.
Call CreateBinding and store the result in a variable.
Define a variable of type DataGridColumn named dataGridColumn. Assign it to null.
Make a switch statement that switches on the control type.
If the case is ControlType.Button:
Assign the dataGridColumn variable to a new DataGridTemplateColumn.
Define and instantiate a variable named buttonTemplate of type DataTemplate.
Define and instantiate a variable named bfactory of type FrameworkElementFactory, passing in the typeof(Button) into the constructor.
Call SetBinding on bfactory and pass in Button.CommandProperty and the binding variable.
Call SetValue on bfactory and pass in Button.ContentProperty and the columnDescription.
assign buttonTemplate's VisualTree to bfactory.
Assign the dataGridColumn's CellTemplate to the buttonTemplate.
Cast the dataGridColumn as a DataGridTemplateColumn.
If the case is TextBox:
Assign the dataGridColumn to a new DataGridTextColumn.
Assign the dataGridColumn's Binding to the binding variable.
Assign the dataGridColumn's IsReadOnly property to false;
If the case is Label:
follow the same steps as the control for a TextBox but set the IsReadOnly property to true.
After the switch statement, assign the dataGridColumn's Header and Width to the columnDescription and columnWidth.
Return the dataGridColumn.
Copy the contents from the EntityView's CreateBinding into the method body.
Remove the line that assigns the binding's source.
Make sure to attach UserControl_Loaded to the MultiEntityView's loaded event.
Instantiate the dataGrid field.
Assign its AutoGenerateColumns to false.
Call SetBinding on the dataGrid and pass in DataGrid.ItemsSourceProperty and the code below for the binding:
new Binding("AllEntities") { Source = this.DataContext }));Add this line:
Type type = this.DataContext.GetType().GetGenericArguments()[1];Get the properties with columns sorted by the column sequence with the following code:
var properties =
from p in type.GetProperties()
where DisplayUtil.HasColumn(p)
orderby DisplayUtil.GetColumnSequence(p)
select p;For each of the PropertyInfos in the properties variable:
Call BuildColumn and pass in the current propertyinfo object.
Add the result from the call to BuildColumn to the dataGrid's Columns.
After the foreach loop, assign the MultiEntityView's Content to the dataGrid.
Define and instantiate a new combo box with a Height of 25 and a width of 150. Populate it with the types of products and add it to the ContentGrid's list of children.
Define and instantiate a new Button with a Height of 25, a Width of 50, a Content equal to "Add Item", and a Margin equal to a new Thickness(0, 50, 0, 0).
(object sender, RoutedEventArgs e) => ovm.AddLineItem(new LineItem() { Product = Activator.CreateInstance(productComboBox.SelectedItem as Type) as IProduct })Add a new MultiEntityView with a Margin equal to new Thickness(0, 250, 0, 0) to the ContentGrid's list of children. Pass in ovm's LineItemViewModels into the MultiEntityView's constructor.
Controls for the order, a combo box with the different products, and a data grid with the order's line items should appear in the window.
Change different values of the line items in the data grid. Any other properties in the order or the line item that depend on that value should automatically update.
Return to each story and verify its acceptance criteria. Preserve the submission format and destination stated in the activity; a reading, setup guide, lab, video demonstration, and oral final may require different evidence.
Update the products Add functionality for LineItems Allow for the editing of a line item's product Add support for orders Add support for multi entity views Add support for viewing multi entities Add order functionality to the MainWindow