The code is currently looping over all the tiles twice. On a 10x10 map, it calls the code inside the loops 10,000 times. That's already a very large number, and that's just on a small map. Most of these calls will be useless, as it is also checking tiles that are far away from each other.
Store things appropriately
Your tiles will always be next to the same neighbours, so why not store them that way? By using a multidimensional array, you can use tile locations on the array to your advantage.
A tile located at nonCollisionTiles[5,5], will always have the same neigbours. So if a light is placed there, it is easy to see that nonCollisionTiles[5,4] needs to be updated.
With this information you can write a recursive function like this:
private void updateLights(int X, int Y, int lightLevel)
{
neighbourUpdate(X, Y - 1, lightLevel - 1);
neighbourUpdate(X, Y + 1, lightLevel - 1);
neighbourUpdate(X - 1, Y, lightLevel - 1);
neighbourUpdate(X + 1, Y, lightLevel - 1);
}
private void neighbourUpdate(int A, int B, int lightLevel)
{
if (lightLevel > nonCollisionTiles[A, B].light)
{
nonCollisionTiles[A, B].light = lightLevel;
updateLights(A, B, lightLevel);
}
}
This function takes as input the X- and Y-location on the array and the light level. It then updates the neighbours (if their lightLevel is lower) and calls another UpdateLights for the location and lightLevel of the updated neighbour.
This is much faster then the double loop, all by using the storing method to our advantage.
On an unrelated note, it is possible to declare fields like this:
public Rectangle rectangle {get; protected set;}
Which might cut down on the length of your Tiles Class.