Hi,
Yes, that is the recommended route. You can choose to reference the File Geodatabase from the Map Package, in which case the MPK will refer to the original File GDB location or alternatively include the File GDB within the Map Package. UNC paths and/or mapped drives are also supported which can make referencing the File GDB easier.
The new dynamic layers capability in Beta 2 also allows you to add new feature classes directly to a running LocalMapService. Unfortunately we didn't manage to include a sample for this in the new sample application but here is some code which should help you get started. This new dynamic layers functionality (also in ArcGIS for Server 10.1) operates on a per request basis - no changes are made to the underlying service and other users will not be affected.
## Default constructor ##
public MainWindow()
{
InitializeComponent();
try
{
// get path to data relative to exe
var dataFolder = System.IO.Path.GetFullPath(System.IO.Path.Combine(
System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
@"..\..\..\.."));
var mapPackagePath = System.IO.Path.Combine(dataFolder, "Europe_Population_Density.mpk");
if (!File.Exists(mapPackagePath))
{
MessageBox.Show("Map Package not found");
return;
}
_LocalMapService = new LocalMapService(System.IO.Path.Combine(dataFolder, "Europe_Population_Density.mpk"));
// Make sure dynamic layers are enabled in this service
_LocalMapService.EnableDynamicLayers = true;
// Register workspaces to be used with this service.
_LocalMapService.DynamicWorkspaces.Add(new WorkspaceInfo()
{
FactoryType = WorkspaceFactoryType.FileGDB,
Id = "Europe_Population_DensityGDB", // a string to identify this workspace when repointing layers
// Connection string must use "DATABASE=" to point to the fileGdb
// API will automatically insert "DATABASE=" if it is not found in the connection string
// API will resolve relative paths if they are used to refer to workspace
// Workspaces are File GDBs, Folders (for Shapefiles) or Enterprise Geodatabases.
ConnectionString = "DATABASE=" + System.IO.Path.Combine(dataFolder, "Europe_Population_Density.gdb"),
});
_LocalMapService.StartAsync((mapService) =>
{
var layer = new ArcGISLocalDynamicMapServiceLayer(_LocalMapService);
layer.ImageFormat = ArcGISDynamicMapServiceLayer.RestImageFormat.PNG32;
layer.InitializationFailed += (s, ex) =>
{
MessageBox.Show("Failed to init layer: " + layer.InitializationFailure.ToString());
};
layer.Initialized += (s, ex) =>
{
if (layer.InitializationFailure == null)
_layer = layer;
//UpdateMapButton_Click(null, null);
};
MapControl.Layers.Add(layer);
});
}
catch (Exception ex)
{
var msg = ex.Message;
}
}
## Button Click event ##
private void UpdateMapButton_Click(object sender, RoutedEventArgs e)
{
selectedItem = ((System.Windows.Controls.ComboBoxItem)FeatureclassComboBox.SelectedItem);
string fcName = selectedItem.Content.ToString().Split(new Char[] { ' ' })[0];
// The following code will get the dynamic layer info collection from the layer (service)
// and update the first item with a new DynamicLayerInfo object to change the data
// source of an existing feature layer within the service. Alternatively you can create a
// brand new DynamicLayerInfoCollection and begin adding new DynamicLayerInfos to this
// collection. Doing this will effectively remove the existing layers and display only the new
// feature layers defined.
var layers = _layer.CreateDynamicLayerInfosFromLayerInfos();
layers[0] = new DynamicLayerInfo()
{
ID = 0,
Source = new LayerDataSource()
{
DataSource = new TableDataSource()
{
DataSourceName = fcName,
WorkspaceID = "Europe_Population_DensityGDB"
}
}
};
_layer.DynamicLayerInfos = layers;
LayerDrawingOptions layerDrawOpt = new LayerDrawingOptions();
layerDrawOpt.LayerID = 0;
layerDrawOpt.Renderer = GetClassBreaksRenderer("POP_DENSIT");
_layer.LayerDrawingOptions = new LayerDrawingOptionsCollection() { layerDrawOpt };
_layer.Refresh();
}
## Get Class Breaks Renderer ##
The code above uses another couple of methods to create a Class Breaks Renderer which is used for displaying the data thematically:
private ClassBreaksRenderer GetClassBreaksRenderer(string attributeField)
{
ClassBreaksRenderer classBreaksRenderer = new ClassBreaksRenderer() { Attribute = attributeField };
Symbol baseSymbol = GetSimpleFillSymbol(Colors.LightGray, Colors.LightGray, 1);
GenerateDataClassesTask generateDataClassesTask = new GenerateDataClassesTask(_LocalMapService.UrlMapService + "/0");
GenerateDataClassesParameters generateDataClassesParameters = new GenerateDataClassesParameters()
{
ClassificationDefinition = new ClassBreaksDefinition()
{
BaseSymbol = baseSymbol,
ClassificationField = attributeField,
ColorRamp = new ColorRamp()
{
Algorithm = Algorithm.HSVAlgorithm,
From = _FromColor,
To = _ToColor
},
BreakCount = 6,
ClassificationMethod = ClassificationMethod.NaturalBreaks,
},
};
try
{
GenerateDataClassesResult generateDataClassesResult = generateDataClassesTask.Execute(generateDataClassesParameters);
classBreaksRenderer = generateDataClassesResult.Renderer as ClassBreaksRenderer;
}
catch (Exception exception)
{
MessageBox.Show("Error: " + exception.Message);
}
return classBreaksRenderer;
}
private SimpleFillSymbol GetSimpleFillSymbol(Color fillColor, Color borderColor, double borderThickness)
{
SimpleFillSymbol fillSymbol = new SimpleFillSymbol()
{
BorderBrush = new SolidColorBrush(borderColor) {Opacity =0.75 },
BorderThickness = borderThickness,
Fill = new SolidColorBrush(fillColor)
};
return fillSymbol;
}
In the code above _FromColor and _ToColor are just class members from the System.Windows.Media namespace and in some other code in this example are updateable via a combobox.
Color _FromColor = Colors.Yellow;
Color _ToColor = Colors.Red;
I hope that should get you started with dynamic layers.
Cheers
Mike