I want to perform data-binding to Room.ToNorth.ImageName
while ToNorth
may be null.
I'm trying to write my own text adventure and have images next to each of the directions a player can go (ie. open/closed door, pathway). When there isn't a room in a given direction I have the controls bound to show a 'no exit' image, this works great so long the player starting location has an exit in all 4 directions, however when one is null I get the following exception
System.ArgumentNullException: 'Value cannot be null. Parameter name: component'
This is isn't an issue on a new game but I'm making randomly generated dungeons so it can't be guaranteed on a load game. I realise I could probably fudge it by creating a safe space while the bindings are set then moving the player to where they need to be but is there a proper way to handle this?
The closest answer I've found is this question, but I'm not sure I can apply it here due to how it's bound.
private GameSession _CurrentGame;
private BindingSource _BindToPlayer = new BindingSource();
private void BtnNewGame_Click(object sender, EventArgs e)
{
_CurrentGame = new GameSession();
_BindToPlayer.DataSource = _CurrentGame.CurrentPlayer;
PicBoxNorth.DataBindings.Add("ImageLocation", _BindToPlayer,
"CurrentRoom.ToNorth.ImageName", true, DataSourceUpdateMode.OnPropertyChanged,
"Images\\Wall.png");
}
The ToNorth property just gets the object from an an array of exits, but telling it to return an empty exit if it's null (like suggested in the above link) would be problematic in that the exit wouldn't have any rooms to connect to and thus fail to initialise likely throwing an exception itself along the way. To explain better, I have my rooms set up as follows
public Class Room
{
public int ID { get; set; }
public String Name { get; set; }
public String Description { get; set; }
public String FarDescription { get; set; }
public CoOrds Co_Ords { get; set; }
public Boolean UniqueRoom { get; set; }
public Exit[] ExitArr { get; set; }
public Exit ToNorth => ExitArr[0];
public Exit ToSouth => ExitArr[1];
public Exit ToWest => ExitArr[2];
public Exit ToEast => ExitArr[3];
public Exit ToUp => ExitArr[4];
public Exit ToDown => ExitArr[5];
public Exit ToIn => ExitArr[6];
public Exit ToOut => ExitArr[7];
public Room(int id, String name, String desc, String fardesc,bool unique = false)
{
ID = id;
Name = name;
Description = desc;
FarDescription = fardesc;
Co_Ords = new CoOrds();
ExitArr = new Exit[8];
UniqueRoom = unique;
}
And my exits are set up like so
public class Exit
{
public String Description {get;}
public Room RoomA { get; set; }
public Room RoomB { get; set; }
public Boolean CanExitA { get; set; } = true;
public Boolean CanExitB { get; set; } = true;
public Room NextRoom
{
get
{
if (RoomA.PlayerHere && CanExitA)
{ return RoomB; }
else if (RoomB.PlayerHere && CanExitB)
{ return RoomA; }
else
return null;
}
}
public String ImageName
{
get
{
string imagePath = "Images\\";
if (DoorHere != null)
{
return imagePath + DoorHere.ImageName;
}
else
return imagePath + "Pathway.png";
}
}
public Door DoorHere { get; set; }
public Exit(Room roomA, int Adir, Room roomB, int Bdir, Door door = null)
{
RoomA = roomA;
RoomA.ExitArr[Adir] = this;
RoomB = roomB;
RoomB.ExitArr[Bdir] = this;
DoorHere = door;
}
Door is just an unnamed object with a few bools for IsOpen, IsLocked etc. and shouldn't be needed if you want to test this but exits are created anonymously and add themselves to the Exit array in both connecting rooms, hence creating empty ones would fail.
Any suggestions would be greatly appreciated.
As an option, you can create a property to do null-checking and get/set second level property using that property.
For example in your code, you can create ToNorthImageName
property to get/set the value of ToNorth.ImageName
in Room
class:
public string ToNorthImageName
{
get { return ToNorth?.ImageName }
//set { if (ToNorth != null) ToNorth.ImageName = value; }
}
The property setter is optional, you can remove it if you just want to read the image name.
Then setup data-binding to that property:
PicBoxNorth.DataBindings.Add("ImageLocation", _BindToPlayer, "ToNorthImageName",
true, DataSourceUpdateMode.OnPropertyChanged);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With