5. Build MultipleSuggestions Window
Create MealPlan and ViewModel classes
MealPlan class is for containing breakfast, lunch, and dinner dish names for one day. ViewModel holds a list of MealPlan instances that will be bound and will update the data grid for suggestions.
Create a class named MealPlan and put this code.
internal class MealPlan
{
public string Breakfast { get; set; }
public string Lunch { get; set; }
public string Dinner { get; set; }
}
Create a class named ViewModel and put this code.
internal class ViewModel
{
public IList MealPlans { get; set; }
}
Add UI Components
- Go to MultipleSuggestions.xaml file.
- Modify backBtn and add a button (getSuggestionBtn), slider (daysSlider), data grid, and text blocks. Check the provided code below to understand better. It is for the most outer grid.
<Grid> <Button x:Name="backBtn" Content="Back to Main" HorizontalAlignment="Left" Margin="26,26,0,0" VerticalAlignment="Top" Width="140" Height="45" Click="backBtn_Click"/> <DataGrid AutoGenerateColumns="False" HorizontalAlignment="Left" Height="368" Margin="354,26,0,0" VerticalAlignment="Top" Width="417"> <DataGrid.Columns> <DataGridTextColumn Header="Breakfast" Width="*"/> <DataGridTextColumn Header="Lunch" Width="*"/> <DataGridTextColumn Header="Dinner" Width="*"/> </DataGrid.Columns> </DataGrid> <Slider x:Name="daysSlider" Minimum="1" Maximum="30" IsSnapToTickEnabled="True" TickFrequency="1" HorizontalAlignment="Left" Margin="26,166,0,0" VerticalAlignment="Top" Height="19" Width="306"/> <Button x:Name="getSuggestionBtn" Content="Get Suggestions" HorizontalAlignment="Left" Margin="26,244,0,0" VerticalAlignment="Top" Width="306" Height="53" /> <TextBlock Text="" HorizontalAlignment="Left" Margin="136,190,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="25"/> <TextBlock Text="Day(s)" HorizontalAlignment="Left" Margin="161,190,0,0" TextWrapping="Wrap" VerticalAlignment="Top"/> </Grid>
Add Database Context
This part is the same as the last chapter.
- Go to MultipleSuggestions.xaml.cs file.
- Under declaration for ParentWindow, declare a private MealSuggestionContainer field named _context.
private MealSuggestionContainer _context;
- Inside of the constructor, create a new MealSuggestionContainer for _context.
//create data context _context = new MealSuggestionContainer();
Add Controller
- Go to MultipleSuggestions.xaml.cs file.
- Add variables needed for getSuggestionBtn_Click function under declaration for _context.
private ViewModel viewModel; private int lastBreakfastDish = -1; private int lastLunchDish = -1; private int lastDinnerDish = -1;
- Add the code below for viewModel to the constructor. Note that _context is used to communicate with the database while viewModel is for populating the UI components. Data retrieved using _context is stored in viewModel, and viewModel feeds data to the data grid on this window.
//set viewModel as data context and create its MealPlans viewModel = new ViewModel(); viewModel.MealPlans = new ObservableCollection(); this.DataContext = this.viewModel;
- Add getSuggestionBtn_Click function. Check the code below.
private void getSuggestionBtn_Click(object sender, RoutedEventArgs e) { Dish[] breakfasts; Dish[] nonBreakfasts; //get dishes from database and store them in arrays try { var dishes = from d in _context.Dishes where d.Breakfast == true select d; breakfasts = dishes.ToArray(); dishes = from d in _context.Dishes where d.Breakfast == false select d; nonBreakfasts = dishes.ToArray(); } catch (Exception ex) { MessageBox.Show(ex.Message); return; } //when there is not enough dish if (nonBreakfasts.Length == 0 || breakfasts.Length == 0) { MessageBox.Show("Please add dishes (at least 1 breakfast & 1 lunch or dinner) first."); return; } //clear previous suggestions viewModel.MealPlans.Clear(); //generate suggestions Random random = new Random(); for (int i = 0; i < daysSlider.Value; i++) { int breakfastIndex = random.Next(0, breakfasts.Length); //if enough candidates, avoid getting same dish as last breakfast if (breakfasts.Length > 1) { while (breakfastIndex == lastBreakfastDish) { breakfastIndex = random.Next(0, breakfasts.Length); } } lastBreakfastDish = breakfastIndex; int lunchIndex = random.Next(0, nonBreakfasts.Length); //if enough candidates, avoid getting same dish as last lunch if (nonBreakfasts.Length > 1) { while (lunchIndex == lastLunchDish) { lunchIndex = random.Next(0, nonBreakfasts.Length); } } lastLunchDish = lunchIndex; int dinnerIndex = random.Next(0, nonBreakfasts.Length); //if enough candidates, avoid getting same dish as last dinner or this day's lunch if (nonBreakfasts.Length > 2) { while (dinnerIndex == lastDinnerDish || dinnerIndex == lunchIndex) { dinnerIndex = random.Next(0, nonBreakfasts.Length); } } lastDinnerDish = dinnerIndex; //create new mealPlan and add it to viewModel's MealPlans MealPlan mealPlan = new MealPlan { Breakfast = breakfasts[breakfastIndex].Name, Lunch = nonBreakfasts[lunchIndex].Name, Dinner = nonBreakfasts[dinnerIndex].Name }; viewModel.MealPlans.Add(mealPlan); } }
- Go to MultipleSuggestions.xaml file.
- Add
Click="getSuggestionBtn_Click"
for getSuggestionBtn button. - Add
ItemsSource="{Binding MealPlans}"
for the data grid. - Add
Binding="{Binding Breakfast}"
,Binding="{Binding Lunch}"
,Binding="{Binding Dinner}"
for each data grid text column. - Replace
Text
property of the empty text block withText="{Binding ElementName=daysSlider, Path=Value, UpdateSourceTrigger=PropertyChanged}"
.
Check Your Code
After following this chapter, your app should be able to:
- Provide a list of meal plan suggestions for days (number of days provided using the slider) on the data grid while avoiding getting the same breakfast as the breakfast on the day before (applies the same to lunch and dinner).