here are some bits of c# code which will help the OP out.

// you won't be able to use BoundingBox<T> - that's my class - but these are the "world extents" for a OSM map

_worldExtents = new BoundingBox<Coord>(left: -20037508.34, right: 20037508.34, top: 20037508.34, bottom: -20037508.34);

// compute resolutions for each zoom level

double[] resolutions = new double[_numZoomLevels];

for (int z = 0; z < _numZoomLevels; z++)

{

resolutions[z] = (_worldExtents.Width / _tileSize) / Math.Pow(2.0, z);

}

then you need to know how big a tile is in your chosen zoom level

private const int _tileSize = 256;

double _tileSizeMetres = _resolutions[_zoomLevel] * _tileSize;

// then you can work out the range of tiles you need

// e.MapExtents is the region of interest (a rectangle in EPSG 3857)

var tile_min_x = (int)Math.Floor((e.MapExtents.Left - _worldExtents.Left) / _tileSizeMetres);

var tile_max_x = (int)Math.Floor((e.MapExtents.Right - _worldExtents.Left) / _tileSizeMetres);

var tile_min_y = (int)Math.Floor((_worldExtents.Top - e.MapExtents.Top) / _tileSizeMetres);

var tile_max_y = (int)Math.Floor((_worldExtents.Top - e.MapExtents.Bottom) / _tileSizeMetres);

// logically you can now do the following:-

for (int x = tile_min_x; x <= tile_max_x; x++)

{

for (int y = tile_min_y; y <= tile_max_y; y++)

{

// download tile x,y, _zoomLevel here

}

}

hope that helps. it's not finished code and won't compile, but if you regard it as pseudo-code it works correctly.