Lesson 09.2: Adding the Trade Screen

Since we now have traders in the world, we need to add a trade screen.

 

 

 

Lesson Steps

 

Step 1: Create a new Window in the WPFUI project named TradeScreen

Add the ViewModels namespace and set DataContext. When we instantiate a TradeScreen window, we’ll set its DataContext to the GameSession object from the main game window (on lines 6 and 7).

When we define the datagrids to show the inventories (the player’s and the trader’s), we set “AutoGenerateColumns” to “false” (lines 41 and 72). This is because we want to add a button to buy or sell the listed item.

The button definitions are on lines 56-64 and 87-95. This is how we can define the template for the cells however we want – in this case to display a button. Each button calls a function in the code-behind page to manage the purchase or sale of the selected item.

 

In the code-behind page (TradeScreen.xaml.cs), we have a private property named Session. It is the DataContext object, cast as a GameSession object. This is how we’ll reference the GameSession object, when we change the player’s gold, the player’s inventory, and the trader’s inventory.

We don’t really need a property for this – we could just cast the DataContext as a GameSession object whenever we need to access it. But, this eliminates doing that multiple times for the buy and sell functions.

 

In the buy and sell functions, the first thing we do is get the item that sent the click event (the row in the datagrid where the user clicked the buy or sell button) and cast it as a GameItem object. This is the object we will add/remove from the inventories, and use to determine the price.

In both functions, we check that the cast “item” variable is not null – in case the case to a GameItem didn’t work. It always should work, but it’s good to have a check.

In the “sell” function, if we have a GameItem object, we give the player gold, add the item to the trader’s inventory, and remove the item from the player’s inventory.

In the “buy” function, we do an additional check to see if the player has enough gold to buy the item. If they don’t we display a message and do nothing else. If the player has enough gold, we subtract the price of the item from their gold, remove the item from the trader’s inventory, and add the item to the player’s inventory.

We don’t need to do anything else. Because the properties all raise propertychanged events, the UI is automatically updated.

 

TradeScreen.xaml

 

TradeScreen.xaml.cs

 

 

Step 2: Modify MainWindow.xaml and MainWindow.xaml.cs

On line 266 of MainWindow.xaml, add the Click event handler “OnClick_DisplayTradeScreen” to the Trade button.

In MainWindow.xml.cs, add the new ” OnClick_DisplayTradeScreen ” function. This function instantiates a new Trade window, set its DataContext with the GameSession, and display the Trade window.

Instances of classes we define (like the GameSession object) are passed to other classes “by reference”, instead of “by value”.

So, there is only one GameSession object, which will be used by the main game screen and the trade screen. Any changes to the GameSession’s properties in the TradeScreen window will be reflected in MainWindow, because they both reference the same object.

We use ShowDialog(), instead of Show(), to prevent the player from clicking buttons on the game screen, until they close the trade screen. ShowDialog() is “modal”, because it prevents clicking on the other screen. Show() would be “non-modal”, because it would let you click on the other screen.

We want to prevent clicking on the other screen, because it would let the player move to a different location, which may not have a trader, or may have a different trader. That could be confusing to the player.

 

MainWindow.xaml

 

MainWindow.xaml.cs

 

 

Step 3: Test the game

Move to a location that has a trader, click the “Trade” button, and try to buy or sell items. You should notice the player’s gold change, along with their inventory in the main game screen. This is because these properties all have propertychanged events. So, the UI is automatically notified of changes.

 

 

Return to main page

6 thoughts on “Lesson 09.2: Adding the Trade Screen

  1. Is there any practical difference between t.DataContext = _gameSession and tradescreeen.DataContext = DataContext?
    My guess is that in the first case we’re passing a reference and in the second we’re passing a reference to a reference, but I’m not 100% sure.

    1. It should work the same for both ways. I just fell it is a little clearer to use “_gameSession”, because that makes me think I am probably passing a GameSession object. If I only used “DataContext”, and this was a larger program, I might forget what datatype the DataContext object is for the current window and need to scroll up to find that information.

  2. How would you make a sell all button, so you wont have to press +100 times to sell all that snakeskin?
    Thanks for this awesome tutorial Scott!

    1. You’re welcome!

      Here are some hints, to help you try to find the answer yourself.

      In TradeScreen.xaml.cs, you could add a new function OnClick_SellAll, like OnClick_Sell (lines 19-29). Inside the “if” block (lines 23-28), check the player’s inventory to see the quantity the player has of that item. Then, surround the other lines (gold and inventory updating) for a “for” loop, so the loop runs once for each quantity the player has of the item.

      Then, add another DataGridTemplateColumn between lines 64 and 65 of TradeScreen.xaml (like the one for the “Sell” button), with a new Button Click eventhandler that calls the new OnClick_SellAll function.

      If you have a problem or question, let me know.

  3. Here is one method of doing the sell all button function.
    private void OnClick_SellAll(object sender, RoutedEventArgs e)
    {
    GameItem item = ((FrameworkElement)sender).DataContext as GameItem; //gets the item that sent the click event.. in this case the row in the datagrid click by the player

    if (item != null)
    {

    for(int i = Session.CurrentPlayer.Inventory.Count -1; i > 0; i–)
    {
    if(Session.CurrentPlayer.Inventory[i].Name == item.Name)
    {
    Session.CurrentPlayer.Gold += Session.CurrentPlayer.Inventory[i].Price;
    Session.CurrentTrader.AddItemToInventory(Session.CurrentPlayer.Inventory[i]);
    Session.CurrentPlayer.RemoveItemFromInventory(Session.CurrentPlayer.Inventory[i]);
    }
    }

    }
    }

    Scott in your hint, you mention checking the player’s inventory to see the quantity of the item the player. Is there a better way then just iterating through the inventory and getting a count of how many times an items name or id is present?

    1. Thanks for sharing your code.

      You could write new AddItemToInventory and RemoveItemFromInventory functions that accept new “quantity” parameters. Then, you could use LINQ to find the item (or see if it doesn’t exist) and increase that object’s Quantity by the passed-in amount. You will need to do some checks in those function. Like making sure them item is in the inventory, and has a sufficient quantity (for removing), for the “remove” function. For the “add” function, you’ll want to see if the item is already in the inventory, so you can increase the quantity, or if it isn’t, and you need to insert a new inventory item. This is where you need to look for “edge cases” that might cause errors in certain situations.

Leave a Reply

Your email address will not be published. Required fields are marked *