# 04 OO Continued [toc] # Theory subject OO concepts: * **Inheritance** … is a … * **Composition** … has a … * **Polymorphism** * **Abstract & virtual** keywords * **Abstract classes & interfaces** # Lab subjects * All OO concepts mentioned in ‘theory subjects’ * using existing interfaces * *(see also: ‘what did we learn today’ at the end of the document)* # Demo https://github.com/howest-mct/DEVPROG_DEMO_03 * Demo on ‘Object Oriented programming’ with screencasts * See <i class="fa fa-book"></i>note: [04 Object Oriented Progamming - demo](/R8AqTQqQStChHzDO6jeD2w) * Inheritance, interfaces, abstract, virtual, object composition,… # Assignments Assignment repository to clone: https://classroom.github.com/a/A6-dt6_9 How? See <i class="fa fa-book"></i>note: [Join the classroom](https://hackmd.io/@frewaeyaert/deviceprogramming/%2FrDOTGvcaTm6RYC05z2TdHw#Join-the-classroom) ## Ex01 – Collectible Items ### General This app displays all kinds of collectible items in one list (wines, post stamps and comic books). As you can see, each time the actual name of the object is shown as main text left above. Underneath that, the type of object is displayed. On the right side we see the year of origin and the start bid price. Possible collectible items are: * Wine * Comic books * Post stamps * .... ![](https://hackmd.io/_uploads/HkYcb5fXo.png) ### Project Setup * Create a project Ex01 in this lab's repository ### Models * Create a model called Wine based on the data you can find in the given csv file * Click [here to download](https://leho-howest.instructure.com/files/2635650/download?download_frd=1) the csv file. * Create a model called PostStamp based on the data you can find in the given csv file * Click [here to download](https://leho-howest.instructure.com/files/2635646/download?download_frd=1) the csv file. * Create a model called ComicBook based on the data you can find in the given csv file * Click [here to download](https://leho-howest.instructure.com/files/2635649/download?download_frd=1) the csv file. ### Repository class * Add all the above csv files to your project. Make sure you set the correct resource type. * Create a folder "Repositories" * In this folder, create a class called "**CollectiblesRepository**" :::warning **Warning!** Based on your pc settings, decimal numbers might be interpreted differently (think about 1,23 vs 1.23). Try to force the desired interpretation of the '.' by using the us culture flag while converting: ::: ```cs= Price = double.Parse(<string_value_to_convert>, CultureInfo.GetCultureInfo("en-US")); //<string\_value\_to_convert> is the value from csv ``` * Create a method called "**GetWines()**" that returns a list of **Wine** objects read from the given csv file. * Create a method called "**GetPostStamps()**" that returns a list of **PostStamp** objects read from the given csv file. * Create a method called "**GetComicBooks()**" that returns a list of **ComicBook** objects read from the given csv file. ### Test models & repository class * In **MainPage.xaml.cs**, create a method called **TestModelsAndRepository()** and call it from your constructor * Call **GetWines()** and investigate the returned list: * does it contain the same data as the csv file? * are all property values filled as they should? * Next, call **GetPostStamps()** and **GetComicBooks()** and also compare the data / properties to the csv file. ### Apply Inheritance + test * Create a **base class** (not an interface) called "**Collectible**". * this will act as a base model for the Wine, PostStamp and ComicBook models, * make sure all three classes inherit from the Collectible model * Compare the Wine, PostStamp and ComicBook class: * check which properties are the same for all 3 * move these properties to the collectible class (make sure you remove them from the other classes!) * The start bid price of all collectible items should be 80% of the actual Price * add a **calculated property** "**StartBidPrice**" in the Collectible model to handle this * each collectible item should have **their own value** for the type of collectible they are * add a property (string) "**CollectType**" in the Collectible model with only a get (no set) * make this property **abstract**; this means the Collectible class has **no default value** for this property * **read the error** that occurs in the Collectible model and solve it * by creating an abstract property, we now **created a contract** for all deriving classes to follow; therefore all models that inherit Collectible now suddenly raise an error (they do not follow the contract yet that says they **MUST** have a CollectType implementation) * implement the abstract property in each class and give it a value (hint: use the light bulb): * PostStamp returns "post stamp" * ComicBook returns "comic book" * Wine returns the type of wine followed by "wine", eg.: "red wine" ### Test again * Go to your test code in the main page & debug it again * Check the StartBidPrice and CollectType values of a few items in each list * Make sure all other properties also still work properly * Ask your teacher for feedback to make sure your solution is ok! ### Repository class – extension * Create a method called "**GetCollectibles**()" that returns a list of all comic books, wines and post stamps: * do this by calling GetWines(), GetComicBooks() and GetPostStamps() in the method, * this method returns exactly **one list** that contains all the above items; think about the return type and how you can solve this, * you cannot change the existing methods to accomplish this ### Sorting - IComparable interface All collectible items should always be **sorted based on their Name**. We will use an existing interface to accomplish this. * [Have a look at the existing **IComparable interface** and determine:](https://docs.microsoft.com/en-us/dotnet/api/system.icomparable?view=netframework-4.8) * **where** you have to implement this interface (is it in Collectible, Wine, ComicBook, PostStamp, or all of them?) * **how** you can sort based on their name using the IComparable interface * make sure all getters in your Repository class now return a sorted list **except for the GetPostStamps**, which keeps his default sort order ### Extend your tests * Go to your test code in the main page * Add a call to the Repository class GetCollectibles() method * For each list you request from the Repository class, write the names of the objects + their collect type to the output window (using Debug.WriteLine) to easily check the following items: * GetWines() should now return the same list but sorted based on the name, just like GetComicBooks() * GetPostStamps() should still return the same list in the default order * GetCollectibles() should return a mixed list of wines, comic books and post stamps, ordered by their name **_The tests are now finished. Do not forget to comment out the call of the test method in your constructor so that is no longer being called!_** ### Frond end - Mainpage All there is left to do is display the sorted list of collectible items in the front end. ![](https://hackmd.io/_uploads/Hy0ArczQj.png) * Copy the given xaml code to Mainpage.xaml ```cs= <ListView Margin="8" x:Name="lvwCollectibleItems" RowHeight="100"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <Frame Margin="8"> <Grid> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <Label Text="{Binding Name}" /> <Label Text="{Binding YearOfOrigin}" HorizontalOptions="End" FontAttributes="Bold" /> <Label Text="{Binding CollectType}" FontSize="Micro" Grid.Row="1" /> <StackLayout Orientation="Horizontal" Grid.Row="1" HorizontalOptions="End" Spacing="0"> <Label Text="Starting bid: €" FontAttributes="Bold" TextColor="Orange" /> <Label Text="{Binding StartBidPrice}" FontAttributes="Bold" TextColor="Orange"> </Label> </StackLayout> </Grid> </Frame> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> ``` * in the constructor, load the list of all collectible items in the listview using the CollectibleRepository * Done! ## Ex02 – Arts Centre Program ### General Based on a data we get from csv files, we will create an app to display the agenda of an arts centre. The user can see a list of all productions for the current month. If he clicks on production, a detail page appears allowing to order tickets for that particular production. ![](https://hackmd.io/_uploads/rJ7E29f7i.png) ### Project Setup * Create a project Ex02 in this lab's repository * [Download the necessary images here](https://leho-howest.instructure.com/files/2635645/download?download_frd=1) and add them as **embedded resource** in an 'Assets' folder * Copy the given xaml code to MainPage.xaml ```cs= <!-- please hide navigation bar --> <StackLayout Margin="16,8"> <Label Text="Productions this month" FontSize="Large"/> <ListView x:Name="lvwProductions" RowHeight="200"> <!--Please uncomment the itemtemplate below AFTER you tested the itemssource as text--> <!--<ListView.ItemTemplate> <DataTemplate> <ViewCell> <Grid> <Frame BackgroundColor="White" Margin="16" Padding="0"> <Grid RowSpacing="0"> <Grid.RowDefinitions> <RowDefinition Height="3*" /> <RowDefinition Height="1*" /> <RowDefinition Height="0.75*" /> </Grid.RowDefinitions> <Image Source="{Binding TypeImage}" Grid.RowSpan="3" Aspect="AspectFill" /> <Label Text="{Binding Name}" Grid.Row="1" FontSize="Medium" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" BackgroundColor="#BB000000" TextColor="White" /> <Label Text="{Binding DateAndTime}" Grid.Row="2" FontSize="Small" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" BackgroundColor="#BB000000" TextColor="White" /> </Grid> </Frame> <Frame BackgroundColor="DarkRed" Padding="4" Margin="4,24" VerticalOptions="Start" HorizontalOptions="End" > <Label Text="{Binding Type}" TextColor="White" /> </Frame> </Grid> </ViewCell> </DataTemplate> </ListView.ItemTemplate>--> </ListView> </StackLayout> ``` * Create a DetailPage in a 'Views' folder and paste this xaml code in it: ```cs= <!-- please hide navigation bar --> <ScrollView> <StackLayout Margin="16" Spacing="0"> <Image x:Name="imgType" Aspect="AspectFill" /> <StackLayout BackgroundColor="Black" Padding="8"> <Label x:Name="lblDateTime" Text="(date)" TextColor="White" /> <Label x:Name="lblType" Text="(type)" TextColor="White" /> <Label x:Name="lblPrice" Text="(price)" TextColor="White" /> </StackLayout> <StackLayout Padding="8"> <Label x:Name="lblDirectorAssociation" Text="(director/association)" TextColor="Black" /> <Label x:Name="lblName" FontSize="Large" Text="(name)" TextColor="Black" /> <Label x:Name="lblDescription" Text="(description)" TextColor="Black" /> </StackLayout> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Button x:Name="btnBack" Text="Go back" Margin="0,0,4,0" /> <Button x:Name="btnOrder" Grid.Column="1" Text="Order tickets!" Margin="4,0,0,0" /> </Grid> </StackLayout> </ScrollView> ``` ### Models * Study all 3 given csv files to determine which properties are common. ***Draw a class diagram and feel free to ask the teacher for feedback before continuing!*** * [download educational performances csv here ](https://leho-howest.instructure.com/files/2635648/download?download_frd=1) * [download guest performances csv here](https://leho-howest.instructure.com/files/2635647/download?download_frd=1) * [download theatre performances here](https://leho-howest.instructure.com/files/2613885/download?download_frd=1) * The dates in the csv files are stored as a timestamp. This is a very common way to handle dates (uniform platform for all countries). * More information: [https://en.wikipedia.org/wiki/Unix_time  ](https://en.wikipedia.org/wiki/Unix_time) * Information on how to convert: [https://stackoverflow.com/questions/249760/how-to-convert-a-unix-timestamp-to-datetime-and-vice-versa)](https://stackoverflow.com/questions/249760/how-to-convert-a-unix-timestamp-to-datetime-and-vice-versa)) * Store the common properties in a **base class** called ‘**Production**’. * This class cannot be instantiated * Add two **properties** that only contain a getter (no setter): **Type** (eg. “Educational”) and **TypeImage** (type ImageSource). These properties must be implemented by the inheriting classes – the production class itself provides no implementation (see 'Sign' in demo). **Hint**: an imagesource can be created from a resourceID like this: `ImageSource src = ImageSource.FromResource(<resourceId>) ` * Add a **method** called ‘**OrderNow**’. This method can be overridden, but by default it prints the following line to the debug window: `"Ticket ordered for production <name> for the price of €<price>." ` * Create a **class** ‘**EducationalProduction**’ that inherits the Production baseclass. * Add extra properties if necessary (based on csv) * The Type is always “Educational” (see embedded images for TypeImage) * Enhance the ‘**OrderNow**’ method so that it behaves just like the production in the baseclass, but prints an extra line that looks like this: `-- associated educational material can be found here: <url>` * Create a **class** ‘**GuestPerformance**’ that inherits the Production baseclass. * Add extra properties if necessary (based on csv) * The Type is always “Guest” (see embedded images for TypeImage) * Placing an order is different for a guest performance. The user receives a message that he should contact the guest association instead of the default ‘ticket ordered’ message: `Please contact <association> to order tickets.` * Create a **class** ‘**TheatreProduction**’ that inherits the Production baseclass. * Add extra properties if necessary (based on csv) * The Type is equal to the Genre of the theatre production. * The TypeImage is also based on that genre (see embedded images for images by genre => TypeImage). * Placing an order is no different from a base production. ### Repository * Create a class called **ProductionRepository** * Add a method ‘**GetEducationalProductions()**’ that returns the educational productions read from the associated csv file, filtered by the **current month**. * Add a method ‘**GetGuestPerformances()**’ that returns the guest performances read from the associated csv file, filtered by the **current month**. * Add a method ‘**GetTheatreProductions()**’ that returns the theatre productions read from the associated csv file, filtered by the **current month**. * Add a method '**GetAllProductions()**' that fills a list of all productions calling the 3 get methods above and returns this complete list. ### Test repository!! * In **MainPage.xaml.cs** create a method called **TestModelsAndRepository()** and call it from your constructor * Call all 4 methods to check if they work as they should. * The number of elements after calling GetAllProductions should be the sum of the three others. Write your test code so that you can check this. ### Frond end – MainPage ![](https://hackmd.io/_uploads/r1kpo2fmi.png) * Read all guest, educational and theatre productions into this list and set it as the itemssource of the listview. :::warning Don’t forget to check if the Binding properties in the given xaml have the same name as yours; change them in xaml if needed ::: * Once a production is chosen, the app navigates to a detail page, passing the selected Production object. Make sure the navigation bar is **hidden** on both the main and the (modeless) detail page. ### Frond end – DetailPage ![](https://hackmd.io/_uploads/B1hfnnfXs.png) * Show all details in the detail page. Mind the format of the date & time (experiment with the **toString function possibilities for a datetime**). * Make sure the ‘go back’ button navigates back to the main page (as well as the physical back button, which should be default). * There is one special label, called ‘**lblDirectorAssociation**’. This label is hidden for an educational performance, shows the director for a theatre performance, and the association for a guest performance. :::warning Hint: check the actual type of the Production object, and cast it to that type if necessary. ::: ## Ex03 - Call for experts ### General Every now and then, you might find extra optional exercises called ‘call for experts’, for the motivated ones among you. This uses elements that were not (yet) explicitly handled during the past weeks. ‘Call for experts’ is an **optional** part, meaning, it will not affect your permanent evaluation grades if you didn’t make it. However, it can be very educational and you’ll end up with just that extra knowledge and self-reliance :::success You can always ask the teachers for feedback on these exercises! Just add an ‘Issue’ to your repository and mention your teacher’s name (@teachername). ::: We want to create a tab for all productions, and filtered by type (education, theatre, guest). It would be overkill to create a single page for each one of those. Instead, we will add a filter property to our existing MainPage, and use that same MainPage 4 times in a **TabbedPage**. You can solve this in several ways, including the use of reflection (ask your teacher for more information on this). * Add a property of type ‘**Type**’ in MainPage.xaml.cs. Name it ‘**FilterType**’. Override the **OnAppearing** event and load the productions there, filtered on type FilterType. (t*his means you should no longer load them in the constructor*) * Create a new TabbedPage. Add 4 instances of the MainPage, each with a different title and value for FilterType. You can provide a Type in xaml like this: ``` <view:MainPage … TypeFilter="{x:Type model:TheatreProduction}" /> ``` Mind that you need to add the namespace in the ContentPage tag (this can be compared to a 'using' statement in code). In this case, we choose 'view' as a prefix, but you can choose whatever you like: ``` <xmlns:view="clr-namespace:the_namespace_of_your_mainpage" ``` * In App.Xaml.cs, change your startup page to the TabbedPage instead of MainPage. This tabbed page is not a navigation page. * Test if it works. A problem might occur if you try to navigate to the detail page now. Problem: MainPage is no longer created as a NavigationPage. Solution: In your TabbedPage, place every MainPage tag inside a NavigationPage tag: ``` <NavigationPage Title="…"> <x:Arguments> <view:MainPage … /> </x:Arguments> </NavigationPage> ``` # What did we learn? * You are aware of how you can make a list of different types by **creating a base class or interface** that define common behavior. * You know when and how to use **inheritance** to: * **add behavior** to subclasses * **replace behavior** in subclasses * It is clear to you how you can **determine the specific type** of an object, and how you can **cast** to an object to that type. * You can implement & use **existing interfaces** by making use of the official documentation # Commit your work (GitHub) Please commit your final working project to GitHub before your next lab starts. :::success **You can always ask the teachers for feedback on the exercises if you’re not sure of the result! Just add an ‘Issue’ to your repository and mention your teacher’s name (@teachername).** ::: * Finish your assignment in time and commit: * open a command window * browse to your solution folder * execute these commands, using the comment “**finished lab**”: ![](https://hackmd.io/_uploads/HJLE_SjZo.png) ![](https://hackmd.io/_uploads/ByMBuBo-s.png) ![](https://hackmd.io/_uploads/S1zU_SiWi.png) ###### tags: `Device Programming` `MCT` `Syllabus`