In this lesson, we will add buttons to let the player move to different locations in the game world.
Step 1: Remove the old test button.
Open MainWindow.xaml. Find, and delete, this line:
<Button Grid.Row="6" Grid.Column="1" Content="Add XP" Click="ButtonBase_OnClick"></Button>
Open MainWindow.xaml.cs. Delete the function that was called for the button Click event.
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
_gameSession.CurrentPlayer.ExperiencePoints = _gameSession.CurrentPlayer.ExperiencePoints + 10;
}
Step 2: Add the buttons to MainWindow.xaml
Find the label for the Combat/Movement controls, and delete it.
<Label Grid.Row="2" Grid.Column="1" Content="Combat/Movement Controls" Background="Lavender"/>
In its place, add this grid (with an inner grid) and the movement button controls.
<Grid Grid.Row="2" Grid.Column="1"
Background="Lavender">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="255" />
</Grid.ColumnDefinitions>
<Grid Grid.Row="0" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="1" Content="North"/>
<Button Grid.Row="1" Grid.Column="0" Content="West"/>
<Button Grid.Row="1" Grid.Column="2" Content="East"/>
<Button Grid.Row="2" Grid.Column="1" Content="South"/>
</Grid>
</Grid>
To make the movement button look the same, set the Height, Width, and Margin attributes for each of them:
<Button Grid.Row="0" Grid.Column="1"
Height="25" Width="65" Margin="10"
Content="North"/>
<Button Grid.Row="1" Grid.Column="0"
Height="25" Width="65" Margin="10"
Content="West"/>
<Button Grid.Row="1" Grid.Column="2"
Height="25" Width="65" Margin="10"
Content="East"/>
<Button Grid.Row="2" Grid.Column="1"
Height="25" Width="65" Margin="10"
Content="South"/>
Step 3: Now we need to make the movement buttons work.
For each movement button, add the Click attribute, at set their value to the name of functions we will create, which will be run when the player clicks the button.
<Button Grid.Row="0" Grid.Column="1"
Height="25" Width="65" Margin="10"
Click="OnClick_MoveNorth"
Content="North"/>
<Button Grid.Row="1" Grid.Column="0"
Height="25" Width="65" Margin="10"
Click="OnClick_MoveWest"
Content="West"/>
<Button Grid.Row="1" Grid.Column="2"
Height="25" Width="65" Margin="10"
Click="OnClick_MoveEast"
Content="East"/>
<Button Grid.Row="2" Grid.Column="1"
Height="25" Width="65" Margin="10"
Click="OnClick_MoveSouth"
Content="South"/>
Next, we need to create the functions that the button Click event will call. These will be in MainWindow.xaml.cs.
They can be “private”, because they will only be called by the buttons in MainWindow.xaml. The returning datatype for these functions is “void”, because the functions will not return any values.
The Click event sends two parameters to its function, so we need to accept them. For Click events, the two parameters are the sender and the event arguments. The “sender” is the object that “sends” the event (in this case, the button in MainWindow.xaml). The event arguments are any additional information that the sending object includes. The Click event sends event arguments whose datatype is “RoutedEventArgs”.
We are not going to do anything with these event arguments, in these functions (we will with other events, in the future). So, I won’t go into detail about them now. However, we do need to include the parameters with the function, because the Click event will send them. So, the function needs to have a place to accept them.
private void OnClick_MoveNorth(object sender, RoutedEventArgs e)
{
}
private void OnClick_MoveWest(object sender, RoutedEventArgs e)
{
}
private void OnClick_MoveEast(object sender, RoutedEventArgs e)
{
}
private void OnClick_MoveSouth(object sender, RoutedEventArgs e)
{
}
If we wanted to, we could change the player’s location inside these functions. But, these functions are in the View. It’s better to put the game logic inside the ViewModel, or a Model (this makes it easier to test, or connect the game to different UIs in the future).
So, we will create new functions inside the GameSession class, which will be called by the event-handling functions we just created.
public void MoveNorth()
{
}
public void MoveEast()
{
}
public void MoveSouth()
{
}
public void MoveWest()
{
}
Now we can go back to MainWindow.xaml.cs, and make the Click event functions call the functions in GameSession.cs
private void OnClick_MoveNorth(object sender, RoutedEventArgs e)
{
_gameSession.MoveNorth();
}
private void OnClick_MoveWest(object sender, RoutedEventArgs e)
{
_gameSession.MoveWest();
}
private void OnClick_MoveEast(object sender, RoutedEventArgs e)
{
_gameSession.MoveEast();
}
private void OnClick_MoveSouth(object sender, RoutedEventArgs e)
{
_gameSession.MoveSouth();
}
Next, we’ll add the code to move the player, inside the new functions in GameSession.cs.
Each of these functions will use the CurrentLocation’s X and Y coordinates, add (or subtract) 1 to the appropriate coordinate for the movement, and get the location at the new coordinates – using the LocationAt function of CurrentWorld.
public void MoveNorth()
{
CurrentLocation = CurrentWorld.LocationAt(CurrentLocation.XCoordinate, CurrentLocation.YCoordinate + 1);
}
public void MoveEast()
{
CurrentLocation = CurrentWorld.LocationAt(CurrentLocation.XCoordinate + 1, CurrentLocation.YCoordinate);
}
public void MoveSouth()
{
CurrentLocation = CurrentWorld.LocationAt(CurrentLocation.XCoordinate, CurrentLocation.YCoordinate - 1);
}
public void MoveWest()
{
CurrentLocation = CurrentWorld.LocationAt(CurrentLocation.XCoordinate - 1, CurrentLocation.YCoordinate);
}
If we run the game now, the player’s location does not change on the screen. That’s because the UI did not receive a notification that the CurrentLocation property has changed. We need to make the GameSession class implement INotifyPropertyChanged, and raise a PropertyChanged notification when the CurrentLocation changes.
To do this, we’ll do the same thing we did for the Player class.
First, at the top of the class, add “: INotifyPropertyChanged”, to declare that this class will implement the INotifyPropertyChanged interface – which lets the WPF UI know it needs to watch for PropertyChanged events from this object.
Next, we need to add the PropertyChanged event, and the OnPropertyChanged function, to implement the interface. We can copy those from the Player class.
Finally, we need to change the CurrentLocation property to use a backing variable, and call the PropertyChanged function when it gets a new value – just like we did with the properties in the Player class.
GameSession.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Engine.Models;
using Engine.Factories;
namespace Engine.ViewModels
{
public class GameSession : INotifyPropertyChanged
{
private Location _currentLocation;
public World CurrentWorld { get; set; }
public Player CurrentPlayer { get; set; }
public Location CurrentLocation
{
get { return _currentLocation;}
set
{
_currentLocation = value;
OnPropertyChanged("CurrentLocation");
}
}
public GameSession()
{
CurrentPlayer = new Player();
CurrentPlayer.Name = "Scott";
CurrentPlayer.CharacterClass = "Fighter";
CurrentPlayer.HitPoints = 10;
CurrentPlayer.Gold = 1000000;
CurrentPlayer.ExperiencePoints = 0;
CurrentPlayer.Level = 1;
WorldFactory factory = new WorldFactory();
CurrentWorld = factory.CreateWorld();
CurrentLocation = CurrentWorld.LocationAt(0, 0);
}
public void MoveNorth()
{
CurrentLocation = CurrentWorld.LocationAt(CurrentLocation.XCoordinate, CurrentLocation.YCoordinate + 1);
}
public void MoveEast()
{
CurrentLocation = CurrentWorld.LocationAt(CurrentLocation.XCoordinate + 1, CurrentLocation.YCoordinate);
}
public void MoveSouth()
{
CurrentLocation = CurrentWorld.LocationAt(CurrentLocation.XCoordinate, CurrentLocation.YCoordinate - 1);
}
public void MoveWest()
{
CurrentLocation = CurrentWorld.LocationAt(CurrentLocation.XCoordinate - 1, CurrentLocation.YCoordinate);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Step 4: Now that we can move, we need a way to prevent the player from moving in a direction where there is no valid location. The way we’ll do that (for now) will be to hide the movement buttons when the player cannot move in a direction.
To do this, we’ll use the “Visibility” attribute on the buttons. This attribute can be set to “Collapsed”, “Hidden”, or “Visible”. “Collapsed” means the control should not be displayed, and it should not take up any space in the screen. “Hidden” means the control should not be displayed, but it will still use the same amount of space as it would if it was visible – although the space will be blank. And, we can “Visible” when we want the control displayed.
As the player moves to different locations, the hidden and visible buttons will change – depending on which directions have valid locations, from the CurrentLocation. So, we will add four new properties on the GameSession class. These will be “Boolean” properties (which hold true/false values), and will see if the World contains a location in each direction from the CurrentLocation.
If there is a location in the direction, the property for that direction will be “true”/ If there isn’t, that property will be “false”.
For these properties, we’re going to only use the “get” – no “set”. And, we will calculate the value to return for the “get”.
The calculation will look in the CurrentWorld, and use the LocationAt function to get the location in the property’s direction. If there is a Location in that direction, LocationAt will return the Location. If there is not a Location in that direction, LocationAt will return “null” (nothing).
So, we want the “HasLocation” properties to return “true”, when LocationAt returns an object (is not null). It will return “false”, when LocationAt returns “null – because there isn’t a Location in that direction. The “get” values for these properties will change as the CurrentLocation changes.
Here is the code for the four new properties:
public bool HasLocationToNorth
{
get
{
return CurrentWorld.LocationAt(CurrentLocation.XCoordinate, CurrentLocation.YCoordinate + 1) != null;
}
}
public bool HasLocationToEast
{
get
{
return CurrentWorld.LocationAt(CurrentLocation.XCoordinate + 1, CurrentLocation.YCoordinate) != null;
}
}
public bool HasLocationToSouth
{
get
{
return CurrentWorld.LocationAt(CurrentLocation.XCoordinate, CurrentLocation.YCoordinate - 1) != null;
}
}
public bool HasLocationToWest
{
get
{
return CurrentWorld.LocationAt(CurrentLocation.XCoordinate - 1, CurrentLocation.YCoordinate) != null;
}
}
Next, we need to connect these properties to the UI. But, we need a way to convert from the Boolean property values to Hidden/Visible. XAML has a built-in converter function we can use to do this.
Open MainWindow.xaml, and add this between the opening <Window> tag, and the first <Grid> control.
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibility" />
</Window.Resources>
That will let us use the built-in XAML converter that converts “true” to “Visible”, and “false” to “Hidden”.
Now, we’ll set the Visibility attribute on the buttons, binding the Boolean properties, and using the BooleanToVisibility converter to convert “true” to “Visible”, and “false” to “Hidden”.
We use Binding, just like we did with the Player properties, but we need to add the Converter, to get the Visibility values. So our buttons will look like this now:
<Button Grid.Row="0" Grid.Column="1"
Height="25" Width="65" Margin="10"
Click="OnClick_MoveNorth"
Visibility="{Binding HasLocationToNorth, Converter={StaticResource BooleanToVisibility}}"
Content="North"/>
<Button Grid.Row="1" Grid.Column="0"
Height="25" Width="65" Margin="10"
Click="OnClick_MoveWest"
Visibility="{Binding HasLocationToWest, Converter={StaticResource BooleanToVisibility}}"
Content="West"/>
<Button Grid.Row="1" Grid.Column="2"
Height="25" Width="65" Margin="10"
Click="OnClick_MoveEast"
Visibility="{Binding HasLocationToEast, Converter={StaticResource BooleanToVisibility}}"
Content="East"/>
<Button Grid.Row="2" Grid.Column="1"
Height="25" Width="65" Margin="10"
Click="OnClick_MoveSouth"
Visibility="{Binding HasLocationToSouth, Converter={StaticResource BooleanToVisibility}}"
Content="South"/>
Step 5: Notify the UI when the HasLocation properties change.
If we run the game right now, the buttons never disappear – even when there is no Location in their direction. That’s because we haven’t configured the GameSession class to raise a notification when the HasLocation properties’ values change.
We need to add the same type of PropertyChanged notification that we did for the CurrentLocation property. However, the HasLocation properties don’t have a “set”, which is where we raised the PropertyChanged notification for CurrentLocation.
Fortunately, the values for the HasLocation properties will change at the same time the CurrentLocation property changes. So, we can add the PropertyChanged notifications for the HasLocation properties inside the CurrentLocation property’s setter.
Change the CurrentLocation property’s code to this:
public Location CurrentLocation
{
get { return _currentLocation;}
set
{
_currentLocation = value;
OnPropertyChanged("CurrentLocation");
OnPropertyChanged("HasLocationToNorth");
OnPropertyChanged("HasLocationToEast");
OnPropertyChanged("HasLocationToWest");
OnPropertyChanged("HasLocationToSouth");
}
}
Now, when the CurrentLocation changes, the UI will receive notification that the HasLocation properties have changed, and will hide (or show) the direction buttons.
Step 6: Run the game, and try moving around in the worlld. You should see the buttons hide/appear, as you move. You should also see the Location image and description change.
Final Source Code
GameSession.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Engine.Models;
using Engine.Factories;
namespace Engine.ViewModels
{
public class GameSession : INotifyPropertyChanged
{
private Location _currentLocation;
public World CurrentWorld { get; set; }
public Player CurrentPlayer { get; set; }
public Location CurrentLocation
{
get { return _currentLocation;}
set
{
_currentLocation = value;
OnPropertyChanged("CurrentLocation");
OnPropertyChanged("HasLocationToNorth");
OnPropertyChanged("HasLocationToEast");
OnPropertyChanged("HasLocationToWest");
OnPropertyChanged("HasLocationToSouth");
}
}
public bool HasLocationToNorth
{
get
{
return CurrentWorld.LocationAt(CurrentLocation.XCoordinate, CurrentLocation.YCoordinate + 1) != null;
}
}
public bool HasLocationToEast
{
get
{
return CurrentWorld.LocationAt(CurrentLocation.XCoordinate + 1, CurrentLocation.YCoordinate) != null;
}
}
public bool HasLocationToSouth
{
get
{
return CurrentWorld.LocationAt(CurrentLocation.XCoordinate, CurrentLocation.YCoordinate - 1) != null;
}
}
public bool HasLocationToWest
{
get
{
return CurrentWorld.LocationAt(CurrentLocation.XCoordinate - 1, CurrentLocation.YCoordinate) != null;
}
}
public GameSession()
{
CurrentPlayer = new Player();
CurrentPlayer.Name = "Scott";
CurrentPlayer.CharacterClass = "Fighter";
CurrentPlayer.HitPoints = 10;
CurrentPlayer.Gold = 1000000;
CurrentPlayer.ExperiencePoints = 0;
CurrentPlayer.Level = 1;
WorldFactory factory = new WorldFactory();
CurrentWorld = factory.CreateWorld();
CurrentLocation = CurrentWorld.LocationAt(0, 0);
}
public void MoveNorth()
{
CurrentLocation = CurrentWorld.LocationAt(CurrentLocation.XCoordinate, CurrentLocation.YCoordinate + 1);
}
public void MoveEast()
{
CurrentLocation = CurrentWorld.LocationAt(CurrentLocation.XCoordinate + 1, CurrentLocation.YCoordinate);
}
public void MoveSouth()
{
CurrentLocation = CurrentWorld.LocationAt(CurrentLocation.XCoordinate, CurrentLocation.YCoordinate - 1);
}
public void MoveWest()
{
CurrentLocation = CurrentWorld.LocationAt(CurrentLocation.XCoordinate - 1, CurrentLocation.YCoordinate);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
MainWindow.xaml
<Window x:Class="WPFUI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFUI"
mc:Ignorable="d"
FontSize="11pt"
Title="Scott's Awesome Game" Height="768" Width="1024">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibility" />
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="225"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Content="Menu" Background="AliceBlue"/>
<Grid Grid.Row="1" Grid.Column="0" Background="Aquamarine">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Name:"/>
<Label Grid.Row="0" Grid.Column="1" Content="{Binding CurrentPlayer.Name}"/>
<Label Grid.Row="1" Grid.Column="0" Content="Class:"/>
<Label Grid.Row="1" Grid.Column="1" Content="{Binding CurrentPlayer.CharacterClass}"/>
<Label Grid.Row="2" Grid.Column="0" Content="Hit points:"/>
<Label Grid.Row="2" Grid.Column="1" Content="{Binding CurrentPlayer.HitPoints}"/>
<Label Grid.Row="3" Grid.Column="0" Content="Gold:"/>
<Label Grid.Row="3" Grid.Column="1" Content="{Binding CurrentPlayer.Gold}"/>
<Label Grid.Row="4" Grid.Column="0" Content="XP:"/>
<Label Grid.Row="4" Grid.Column="1" Content="{Binding CurrentPlayer.ExperiencePoints}"/>
<Label Grid.Row="5" Grid.Column="0" Content="Level:"/>
<Label Grid.Row="5" Grid.Column="1" Content="{Binding CurrentPlayer.Level}"/>
</Grid>
<Grid Grid.Row="1" Grid.Column="1"
Background="Beige">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<Border Grid.Row="0" Grid.Column="1"
BorderBrush="Gainsboro"
BorderThickness="1">
<Grid Margin="3">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
HorizontalAlignment="Center"
Text="{Binding CurrentLocation.Name}"/>
<Image Grid.Row="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Height="125"
Width="125"
Source="{Binding CurrentLocation.ImageName}"/>
<TextBlock Grid.Row="2"
HorizontalAlignment="Center"
Text="{Binding CurrentLocation.Description}"
TextWrapping="Wrap"/>
</Grid>
</Border>
</Grid>
<Label Grid.Row="2" Grid.Column="0" Content="Inventory/Quests" Background="BurlyWood"/>
<Grid Grid.Row="2" Grid.Column="1"
Background="Lavender">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="255" />
</Grid.ColumnDefinitions>
<Grid Grid.Row="0" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="1"
Height="25" Width="65" Margin="10"
Click="OnClick_MoveNorth"
Visibility="{Binding HasLocationToNorth, Converter={StaticResource BooleanToVisibility}}"
Content="North"/>
<Button Grid.Row="1" Grid.Column="0"
Height="25" Width="65" Margin="10"
Click="OnClick_MoveWest"
Visibility="{Binding HasLocationToWest, Converter={StaticResource BooleanToVisibility}}"
Content="West"/>
<Button Grid.Row="1" Grid.Column="2"
Height="25" Width="65" Margin="10"
Click="OnClick_MoveEast"
Visibility="{Binding HasLocationToEast, Converter={StaticResource BooleanToVisibility}}"
Content="East"/>
<Button Grid.Row="2" Grid.Column="1"
Height="25" Width="65" Margin="10"
Click="OnClick_MoveSouth"
Visibility="{Binding HasLocationToSouth, Converter={StaticResource BooleanToVisibility}}"
Content="South"/>
</Grid>
</Grid>
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Engine.ViewModels;
namespace WPFUI
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private GameSession _gameSession;
public MainWindow()
{
InitializeComponent();
_gameSession = new GameSession();
DataContext = _gameSession;
}
private void OnClick_MoveNorth(object sender, RoutedEventArgs e)
{
_gameSession.MoveNorth();
}
private void OnClick_MoveWest(object sender, RoutedEventArgs e)
{
_gameSession.MoveWest();
}
private void OnClick_MoveEast(object sender, RoutedEventArgs e)
{
_gameSession.MoveEast();
}
private void OnClick_MoveSouth(object sender, RoutedEventArgs e)
{
_gameSession.MoveSouth();
}
}
}
NEXT LESSON: Lesson 04.4: Improving the World – Inheritance and INotifyPropertyChanged
PREVIOUS LESSON: Lesson 04.2: Creating the World
Hello! In your video you say that Click events change color when handler is added. In my IDE (VS 2022) the color remains the same regardless of handler being has been added or not. Could you please tell how to fix it?
Hi Alex,
My VS Community 2022 still shows different colors, depending on whether or not the handler function exists. I do have to move the cursor out of the name of the function, for the color to change.
Do you have ReSharper, or some other editor plugin installed? Have you changed Visual Studio’s color theme? Those might be a source of the problem. There might also be solutions in this StackOverflow post: https://stackoverflow.com/questions/24254362/visual-studio-intellisense-color-coding-not-working
I dont have Reshaper, but I have Sonar installed. I use Dark theme, but tried default light theme as well. Colorcoding works with all other stuff, like turns yellow for bindings, and grey with plain text. It is just events like “Click” that remain the same color regardles of handler presense.
Well, tried thing on StackOverflow, seems just gotta be extra watchful for adding handlers then.
Same on my end, It’s only the click. I’ll have to look into it sometime and If I find a reason I’ll update here
https://stackoverflow.com/questions/25549826/resharper-wpf-error-cannot-resolve-symbol-myvariable-due-to-unknown-datacont
I think it’s a Resharper Feature from what I can see.
Thanks for sharing that StackOverflow link. I like that is shows several different solutions.
Inputting “_gameSession.MoveNorth();” results in “MoveNorth” getting the error CS1061. It says ” ‘GameSession’ does not contain a definition for ‘MoveWest’ and no accessible extension method ‘MoveWest’ accepting a first argument of type ‘GameSession’ could be found (are you missing a using directive or an assembly reference?)”.
Hi Jakob,
That message probably means one of this things is happening:
1. The WPF project does not have a reference to the Engine project.
2. The GameSession class, or MoveNorth function, is not “public”
3. There’s a typo in the MoveNorth function name (function names are case-sensitive)
Check on those and let me know if that doesn’t lead to a solution. If it doesn’t, can you upload your solution (including the directories under it, and all the files in those directories) to GitHub, Dropbox, or some other file-sharing location so I can look at it?
So I copied and pasted the code from this page and I am receiving 4 errors. I get one for each direction, here is one:
CS1061 ‘MainWindow’ does not contain a definition for ‘OnClick_MoveNorth’ and no accessible extension method ‘OnClick_MoveNorth’ accepting a first argument of type ‘MainWindow’ could be found (are you missing a using directive or an assembly reference?) WPFUI F:\Programming\SOSCSRPG\WPFUI\MainWindow.xaml
I would greatly appreciate any advice because this tutorial is fantastic!
FWIW, I am using VS 2022
Hi Jason,
Does your MainWindow.xaml.cs have the second code block from Step 3 (which are changed in the fourth code block of step 3)?
If that doesn’t solve the problem, can you upload your solution (including the directories under it, and all the files in those directories) to GitHub, Dropbox, or some other file-sharing location so I can look at it?
If you haven’t used GitHub before, here is some information (and a video) on how to upload your solution to GitHub and share it with me. https://codingwithscott.com/how-to-connect-visual-studio-community-edition-2022-to-github/
First off, thank you so much for answering so quickly, I greatly appreciate it!
My MainWindow.xaml.cs matches your Final Source Code.
I unloaded and reloaded the solution, and that seems to have resolved the issue I was having. However, now I am getting an error on GameSession.cs:
System.NullReferenceException
Engine.ViewModels.GameSession.CurrentLocation.get returned null.
Repository: https://github.com/ADKCourage/SOSCSRPG
You’re welcome. I downloaded the code from the repository, but it looks like it’s an earlier version of the code. The GameSession class doesn’t have any of the movement functions.
Can you please push the latest changes to GitHub (https://learn.microsoft.com/en-us/visualstudio/version-control/git-push-remote?view=vs-2022)
Also, if you look at the exception message, it usually has the line number where the error happened, and that might help you see where the problem is.