Hey Dominique, thank your for the tips. I see where the problem is. Actually I don't have 'PreparePages' function...so the scale doesn't get any value and it doesn't work I guess. So I was thinking to add this function to MapPrinter loaded event. Please see the red words. But for some reasons the printExtent is always null. I put a breakpoint in this line: Envelope printExtent = mapPrinterWithDialog.PrintExtent....but it seems like there is no map in 'mapPrinterWithDialog' even I bind MyMap to its 'Map'. I am really confused...why the map is still empty after we bind its map property to MyMap, even in its loaded event?
controls:MapPrinterDialog x:Name="MapPrinterDialog" Background="White" Width="350" Height="400" Style="{StaticResource MyMapPrinterDialogStyle}" Visibility="Collapsed" >
<controls:MapPrinter x:Name="mapPrinterWithDialog" Map="{Binding ElementName=MyMap}" Style="{StaticResource WithLegend}"
Title="WIRT" Loaded="mapPrinterWithDialog_Loaded"/>
<!--IsScaleFixed="True" Scale="2000000"-->
<!--IsActive="{Binding ElementName=PrintBtn }"-->
</controls:MapPrinterDialog>
<controls:MapPrinterIndicator MapPrinter="{Binding ElementName=mapPrinter}" />
private void mapPrinterWithDialog_Loaded(object sender, RoutedEventArgs e)
{
MapPrinter mapPrinterWithDialog = sender as MapPrinter;
double mapHeight = MyMap.ActualHeight;
double mapWidth = MyMap.ActualWidth;
Envelope printExtent = mapPrinterWithDialog.PrintExtent;
var mapSize = new Size(mapPrinterWithDialog.RotateMap ? mapHeight : mapWidth, mapPrinterWithDialog.RotateMap ? mapWidth : mapHeight);
var mapUnit = mapPrinterWithDialog.MapUnits;
bool isWebMercator = (mapPrinterWithDialog.Map != null && mapPrinterWithDialog.Map.SpatialReference != null &&
(mapPrinterWithDialog.Map.SpatialReference.WKID == 102100 || mapPrinterWithDialog.Map.SpatialReference.WKID == 102113 || mapPrinterWithDialog.Map.SpatialReference.WKID == 3857));
double ratioScaleResolution = RatioScaleResolution(mapUnit, printExtent.GetCenter().Y, isWebMercator);
double scale = mapPrinterWithDialog.Scale;
double printResolution;
printResolution = Math.Max(printExtent.Width / mapSize.Width, printExtent.Height / mapSize.Height);
scale = ratioScaleResolution * printResolution;
if (scale != mapPrinterWithDialog.Scale)
mapPrinterWithDialog.Scale = scale;
}
private static double RatioScaleResolution(MapUnit mapUnit, double yCenter, bool isWebMercator)
{
double ratio;
int dpi = 96;
double toRadians = 0.017453292519943295769236907684886;
double earthRadius = 6378137; //Earth radius in meters (defaults to WGS84 / GRS80)
double degreeDist = earthRadius * toRadians;// distance of 1 degree at equator in meters
if (isWebMercator)
{
// Transform yCenter from web mercator to decimal degree
yCenter = Math.Min(Math.Max(yCenter, -20037508.3427892), 20037508.3427892);
var point = new MapPoint(0, yCenter);
yCenter = point.WebMercatorToGeographic().Y;
ratio = Math.Cos(yCenter * toRadians) * dpi * 39.37; // 39.37 = MapUnit.Meters/MapUnit.Inches
}
else if (mapUnit == MapUnit.DecimalDegrees || mapUnit == MapUnit.Undefined)
{
if (Math.Abs(yCenter) > 90)
ratio = 0.0;
else
ratio = Math.Cos(yCenter * toRadians) * degreeDist * dpi * 39.37;
}
else
{
ratio = (double)dpi * (int)mapUnit / (int)MapUnit.Inches;
}
return ratio;
}