Component Reference
Did you know VertiGIS Studio Workflow allows you to create custom forms you can present to an end user?
Implementing a custom component in VertiGIS Studio Mobile gives you the highest degree of flexibility with what you can do. Components can display custom, dynamic UI, register operation implementations, store persistent data, and more. They are also one of the most complex ways of customizing your mobile app, so it might be worthwhile to review simpler options like Commands and Operations or Workflow first.
[assembly: Component(typeof(CustomComponent), "custom-component", XmlNamespace = XmlNamespaces.App1Namespace)]
namespace App1.Components
{
class CustomComponent : ComponentBase
{
protected override VisualElement Create(XNode node)
{
return new Label(){ Text = "My Custom Component" };
}
}
}
Component Registration
VertiGIS Studio Mobile uses Autofac to register, locate, and inject components, services and other classes.
Each component class is registered with the Component
assembly attribute
It's convention for the name of the component in the layout
to be lower case and kebab case, i.e. custom-component
.
[assembly: Component(typeof(CustomComponent), "custom-component", XmlNamespace = XmlNamespaces.App1Namespace)]
namespace App1.Components
{
class CustomComponent : ComponentBase
{
...
}
}
Components and Layout
Once a component has been registered, it can be used in a layout by referring it by name and namespace.
<?xml version="1.0" encoding="utf-8" ?>
<layout
xmlns="https://geocortex.com/layout/v1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://geocortex.com/layout/v1 ../../ViewerSpec/layout/layout-mobile.xsd"
xmlns:custom="https://your.org/layout/app1">
<custom:custom-component/>
</layout>
Component Anatomy
VertiGIS Studio Mobile is built on top of the Xamarin Platform. In general, XAML Views are used to define reactive component UI. Component Views in VertiGIS Studio Mobile are built with the Model-View-ViewModel (MVVM) pattern. The model for components is usually either app config or a service hosting shared application data.
Component Class
Each instance of a component class directly correlates to a component in the layout. A component class extends ComponentBase
and renders visual elements. As seen in the example below, components can provide their UI inline, but it is recommended that components render an associated XAML view instead.
[assembly: Component(typeof(CustomComponent), "custom-component", XmlNamespace = XmlNamespaces.App1Namespace)]
namespace App1.Components
{
class CustomComponent : ComponentBase
{
protected override VisualElement Create(XNode node)
{
return new Label(){ Text = "My Custom Component" };
}
}
}
Component Dependencies
Components are instantiated by dependency injection when the layout is rendered. This means that a component can also list dependencies that have been registered with autofac, such as the ILayoutModel<MapView>
in its constructor, and have them be passed at runtime. This also means that if a class associated with a component has application dependencies, such as a reference to the MapOperations
for map interactions, then the component will either need to provide that dependency somehow.
The preferred way to provide sub-dependencies to classes associated with components is to instantiate those associated classes with dependency injection also. Check out managing sub-dependencies for an example.
XAML View
XAML views and their respective "code-behind" are responsible for the presentation concerns of a component. Check out a complete example in the SDK samples.
XAML views can use any XAML Controls along with built-in VertiGIS Studio Mobile XAML Elements and styling.
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="Geocortex.Mobile.Samples.Samples.Custom.XamlComponent.XamlComponentView">
<ContentView.Content>
<StackLayout Margin="5">
<Label Text="Hello XAML Component!" />
<Label Text="This component view is created using a XAML view." />
</StackLayout>
</ContentView.Content>
</ContentView>
View Model
Component view models are responsible for populating properties with data for the view to bind to. The data for the view model is usually provided by the component class, which can consume app config or other data from the application through dependency injection. View models can use commands and operations to interact with application services and other components.
Check out this example of a component with a view model.
Configuration Models
Every component is bound to specific item type, and each item type is bound to a class registered as an AppItem
with autofac. This class instantiates itself with values from the app config in its constructor, acting as a configuration model. The component class then consumes this configuration model, and then passes the appropriate values to the view and view model.
- App Item Model
- Component
- App Config
[assembly: AppItemComponent(typeof(CustomComponent), "component-with-config", "my-app-item", XmlNamespace = XmlNamespaces.App1Namespace)]
namespace VertiGIS.Mobile.Samples.Samples.Custom.Component
{
internal class CustomComponent : AppItemComponentBase<MyAppItem>
{
private readonly IAppItem<MyAppItem> _appItemResolver;
private CustomComponentViewModel _viewModel;
private CustomComponentView _view;
public CustomComponent(IAppItem<MyAppItem> itemResolver, Func<CustomComponentViewModel, CustomComponentView> viewFactory, CustomComponentViewModel viewModel)
: base(itemResolver)
{
_appItemResolver = itemResolver;
_viewModel = viewModel;
_view = viewFactory(viewModel);
}
protected override VisualElement Create(XNode node)
{
return _view;
}
protected override async Task DoInitializeAsync()
{
var item = await _appItemResolver.ResolveAsync();
_viewModel.Text = item.ConfigText;
}
}
}
[assembly: AppItem(MyAppItem.ConfigItemtype, typeof(MyAppItem))]
namespace VertiGIS.Mobile.Samples.Samples.Custom.ComponentConfiguration
{
public class MyAppItem : VisualAppItem
{
public const string ConfigItemtype = "my-app-item";
public string ConfigText { get; private set; }
public MyAppItem()
: this(Guid.NewGuid().ToString())
{
}
public MyAppItem(string id)
: this(new Properties { ["id"] = id })
{
}
public MyAppItem(Properties properties) :
base(properties, ConfigItemtype)
{
if (properties.TryGetValue("text", out var text))
{
ConfigText = text as string ?? "Default text.";
}
}
}
}
{
"schemaVersion": "1.0",
"items": [
...
{
"$type": "my-app-item",
"id": "some-unique-id",
"title": "My Title"
}
...
]
}
Component Defaults
Most components support the config
attribute in the layout, which links a component to configuration in the app config JSON. However, many configuration models have default values they can supply for initialization instead of relying on a value to exist in the config. Any AppItem
class can provide default values through the CreateDefault
method. This method should return an instance of the AppItem
which represents the default values.
[assembly: AppItem(MyAppItem.ConfigItemtype, typeof(MyAppItem))]
namespace VertiGIS.Mobile.Samples.Samples.Custom.ComponentConfiguration
{
public class MyAppItem : VisualAppItem
{
public const string ConfigItemtype = "my-app-item";
...
public override object CreateDefault()
{
return new MyAppItem();
}
}
}
This pattern is what allows you to place a map with no config in the layout and have it render a default map.
<?xml version="1.0" encoding="utf-8" ?>
<layout
xmlns="https://geocortex.com/layout/v1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://geocortex.com/layout/v1 ../../ViewerSpec/layout/layout-mobile.xsd">
<map/> <!-- The map component is populated with values from the MapExtension's `CreateDefault` function. -->
</layout>
Initialization and Teardown
Components have an initialization method, which can be used to perform asynchronous startup logic, and a teardown method, which can be used to free resources when a component is removed from the layout.
Always call base.Dispose(disposing)
when overriding the Dispose
method. ComponentBase
already implements IDisposable
and IDisposableTracker
, so only override the Dispose
method if you have created new managed resources which need to be cleaned up.
To learn more about memory management in VertiGIS Studio Mobile, check out this article, and the relevant SDK sample.
[assembly: Component(typeof(CustomComponent), "component", XmlNamespace = XmlNamespaces.SamplesNamespace)]
namespace VertiGIS.Mobile.Samples.Samples.Custom.Component
{
internal class CustomComponent : ComponentBase
{
private bool disposed = false;
public CustomComponent()
{
}
...
protected override async Task DoInitializeAsync()
{
// Initialization code.
// ...
}
protected override void Dispose(bool disposing)
{
if (disposed)
{
return;
}
if (disposing)
{
// Clean up managed resources.
// ...
}
// Clean up unmanaged resources.
// ...
base.Dispose(disposing);
disposed = true;
}
}
}
Component Lifecycle
When a VertiGIS Studio Mobile Application boots up, the set of components which are in the layout are created. Next, any components that are initially active, depending on the layout, will be activated and initialized. Components like the Panel
will only activate their first child.
Activation and Deactivation
Custom code can listen and react to a components activation or deactivation by subscribing to the ui.activated
or ui.deactivated
event. The ui.*
events contain various events relating to the component lifecycle.
The UIOperations
class contains implements the commands ui.activate
and ui.deactivate
which can be used to examine and manipulate the activation state of components.
class CustomComponent : ComponentBase
{
public CustomComponent(UIEvents uiEvents)
{
uiEvents.ComponentActivated.Subscribe(_onComponentActivated, this);
uiEvents.ComponentDeactivated.Subscribe(_onComponentDeactivated, this);
private async void _onComponentActivated(string id)
{
// ... react to component activation.
}
private async void _onComponentDeactivated(string id)
{
// ... react to component deactivation.
}
...
}
Relevant SDK Samples
Check out the relevant VertiGIS Studio Mobile SDK Samples:
Next Steps
Learn how to use Commands and Operations with Components
Learn how to run and implement commands and operations with custom components
Learn about Component Interactions
Learn about how components and services can interact with each other
Create a Component with a Complex UI
Follow along with a more in depth component example
Create a Component that Consumes App Config
Learn more about writing components that consume configuration values.