Documentation
Table of Contents
Shell XAML
Shell.xaml is the main entry point of the app and defines the data model and navigation.
<?xml version="1.0" encoding="utf-8" ?>
<Shell xmlns="http://schemas.snapworx.at/appshell/2016/xaml"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Sample">
<Shell.Entities>
<!--Definition of data source entities used in lists and forms-->
</Shell.Entities>
<Shell.Tiles>
<!--Optional definition of map tiles used as background or map overlay-->
</Shell.Tiles>
<Shell.Views>
<!--Definition of UI views / navigation targets-->
</Shell.Views>
</Shell>
Entities
<Shell.Entities>
<Entity Id="Table1" Key="id" SyncType="Automatic" Table="table1" RevisionField="lastupdatetime">
<Field Name="id" Type="Guid" IsRequired="True" />
<Field Name="name" Type="String" MaxLength="256" />
<Field Name="geometry" Type="Geometry" />
<Field Name="lastupdatetime" Type="DateTime" />
</Entity>
</Shell.Entities>
Key field must be of type Guid if you want to create records offline
Entity
<Entity Id="" Title="" Table="" Key="" SyncType="" RevisionField="">
Field
<Field Name="" Type="" IsRequired="" MinLength="" MaxLength="" EpsgCode=""
LazyLoading="" ForeignEntity="" DefaultValue="" IntersectionMode=""
Precision="" StorageType="" FilterOperator="" FilterField="" />
Field Types
- Guid
- String
- DateTime
- Number
- Integer
- Boolean
- Geometry
- Binary
- AutoIncrement
- UnixTimestamp
- Timestamp
AutoIncrement, Timestamp and UnixTimestamp are automatically updated on modification of an entity.
Sync Types
Value | Description |
---|---|
None | Entity is only available online |
Automatic | Entity is synced automatically on each login |
Automatic (with revision field) | Entity is synced automatically on each login, but only changes which have a higher value in the revison field since last sync (diff sync) |
Manual | Entity will only be synced once. You can sync it manually in the Synchronization view |
Intersection Modes
Intersection mode is used to define which geometry field is used for intersection. Currently only one geometry field with IntersectionMode="Intersects" is supported.
Value | Description |
---|---|
None | Geometry field is ignored |
Intersects | Geometry field is used to filter entities if an area is selected (Default) |
Applies only to geometry fields
Storage Types
Value | Description |
---|---|
Database | Binary field is stored in database (Default) |
FileSystem | Binary field is stored on the file system |
Applies only to binary fields with LazyLoading="True"
Filter Operators
Value |
---|
None |
Equal |
Contains |
GreaterThan |
GreaterEqual |
LessThan |
LessEqual |
Applies only to forms used in a filter
Validators
<Field>
<RegexValidator Message="" Pattern="" />
<MinValidator Message="" Minimum="" />
<MaxValidator Message="" Maximum="" />
</Field>
Filters
<Entity.Filters>
<Filter Id="" Sql="" IsDefault="" Title="" />
</Entity.Filters>
Triggers
<Entity.Triggers>
<Trigger Id="" Method="" Type="" />
<SqlTrigger Sql="" />
<MailTrigger From="" To="" Subject="" Body="" />
<UrlTrigger Url="" HttpMethod="" Headers="" Data="" />
<UpdateFieldTrigger Field="" Value="" />
<RemoveFieldTrigger Field="" />
</Entity.Triggers>
Id and Method attribute applies to all trigger types.
Trigger Methods
- BeforeSave
- BeforeUpdate
- BeforeDelete
- AfterSave
- AfterUpdate
- AfterDelete
- Manual
You can specify multiple methods separated with a comma
Tiles
Configuration of tile sources for map views (WMTS, WMS and TMS). Projection must be EPSG:3857.
<Shell.Tiles>
<UrlTileOverlay Id="" TileWidth="" TileHeight="" MinimumZoomLevel="" MaximumZoomLevel=""
MinimumCacheZoomLevel="" MaximumCacheZoomLevel="" Url="" CacheOnDemand="" />
</Shell.Tiles>
Views
Menu XAML
Defines a menu configuration.
<Menu xmlns="clr-namespace:AppShell;assembly=AppShell">
<MenuItem Target="TaskNavigation" Title="Tasks" Icon="Checklist" />
<MenuItem Target="NativeMapNavigation" Title="Native Map" Icon="Map" />
<MenuItem Target="SettingsNavigation" Icon="Setting" Type="Toolbar" />
<MenuItem Target="AppSelection" Icon="ChangeStatus" Type="Toolbar" />
<MenuItem Target="Logout" Icon="Logout" Type="Toolbar" />
</Menu>
Menu Items
<MenuItem Target="" Title="" Icon="" Type="" />
Target can be a view id from Shell.xaml or AppSelection/Logout
Menu Action Type
- Menu
- Toolbar
List XAML
Defines a list configuration.
Name of your XAML file is the view name in Shell.xaml
<?xml version="1.0" encoding="utf-8" ?>
<List xmlns="clr-namespace:AppShell;assembly=AppShell">
<List.ShellActions>
<!--Definition of shell actions on the top right-->
</List.ShellActions>
<List.RowActions>
<!--Definition of actions for each list row-->
</List.RowActions>
<List.Sort>
<!--Definition of default sorting-->
</List.Sort>
<!--Definition of various list cells-->
</List>
Shell Actions
<ShellAction Icon="" Type="" />
<NavigateShellAction Target="" />
<SearchShellAction Filter="" Placeholder="" />
<OpenUriShellAction Uri="" />
<FilterShellAction Target="" Filter="" IsPersisted="" />
<NavigateMapShellAction Target="" Entity="" SourceField="" GeometryField="" />
Shell Action Type
- Primary
- Secondary
Row Actions
<NavigateRowAction Icon="" Target="" />
<ScriptRowAction Icon="" />
<OpenUriRowAction Uri="" />
<OpenDocumentRowAction Field="" />
<OpenFileRowAction Field="" FileNameField="" FileName="" IsText="" />
<DownloadFileRowAction Field="" FileNameField="" FileName="" IsText="" />
Sort
<ListSort Name="" Order="" />
Sort Order
- Ascending
- Descending
Cells
<Cell Name="" Title="" ShortTitle="" Width="" DisplaySize="" WordWrap="" ScriptValue="" />
<ListCell StringFormat="" ForeignField="" />
<DistanceListCell />
<ImageListCell />
<MultiListCell>
<!--List Cells-->
</MultiListCell>
Display Size
- Small
- Medium
- Large
Word Wrap
- NoWrap
- WordWrap
- CharacterWrap
- HeadTruncation
- TailTruncation
- MiddleTruncation
Form XAML
Defines a form configuration.
Name of your XAML file is the view name in Shell.xaml
<?xml version="1.0" encoding="utf-8" ?>
<Form xmlns="clr-namespace:AppShell;assembly=AppShell">
<Form.ShellActions>
<!--Definition of shell actions on the top right-->
</Form.ShellActions>
<Form.Scripts>
<!--Definition of scripts-->
</Form.Scripts>
<!--Definition of various form fields-->
</Form>
Shell Actions
<ShellAction Icon="" Type="" />
<SaveShellAction />
<DeleteShellAction />
<ScriptShellAction />
<PrevShellAction />
<NextShellAction />
<NavigateShellAction Target="" />
<OpenUriShellAction Uri="" />
Shell Action Type
- Primary
- Secondary
Scripts
<StartupScript />
<LoadedScript />
<ChangeScript Name="" Field="" />
<SharedScript />
Fields
<Field Name="" Title="" Placeholder="" Help="" IsVisible="" IsRequired=""
IsEnabled="" DefaultValue="" />
<Entry />
<Editor />
<DatePicker />
<TimePicker />
<DateTimePicker />
<Distance />
<Picker KeyMember="" DisplayMember="" Items="" />
<Geometry />
<ImagePicker PreviewField="" SizeField="" MimeTypeField="" />
<FilePicker FileNameField="" SizeField="" MimeTypeField="" />
<AutoComplete Entity="" DisplayField="" />
<OptionsGroup MultiSelect="" Columns="">
<Option Value="" Title="" />
<Option Field="" Title="" />
</OptionsGroup>
<Switch TrueValue="" FalseValue="" />
<Info />
<Table Entity="" RelationEntity="" Target="" RowCount="">
<Table.RowActions>
</Table.RowActions>
<Table.Actions>
</Table.Actions>
<Table.Sort>
</Table.Sort>
<TableCell Name="" Title="" />
</Table>
<Group IsExpanded="" />
<TabGroup IsExpanded="">
<FieldTab Name="" Title="">
<FieldTab.Fields>
</FieldTab.Fields>
</FieldTab>
</TabGroup>
Sort
<TableSort Name="" Order="" />
Field Actions
<FieldAction Icon="" AutoSave="" />
<NavigateFieldAction Target="" />
<ScriptFieldAction />
<MessageFieldAction Message="" Cancel="" />
<DateTimeNowFieldAction />
<GeometryFieldAction Target="" Edit="" GeometryType="" />
<DownloadImageFieldAction />
<PickImageFieldAction Resize="" />
<TakeImageFieldAction Resize="" />
<PickFileFieldAction IsText="" />
<DownloadFileFieldAction FileName="" IsText="" />
<OpenFileFieldAction FileName="" IsText="" />
<ExecuteTriggerFieldAction Trigger="" />
<OpenUriFieldAction Uri="" />
<OpenDocumentFieldAction />
Map XAML
Defines a map configuration.
Name of your XAML file is the view name in Shell.xaml
<?xml version="1.0" encoding="utf-8" ?>
<NativeMap xmlns="clr-namespace:AppShell;assembly=AppShell">
<NativeMap.ShellActions>
<!--Definition of shell actions on the top right-->
</NativeMap.ShellActions>
<NativeMap.Layers>
<!--Definition of layers-->
</NativeMap.Layers>
</NativeMap>
Shell Actions
<ShellAction Icon="" Type="" />
<CurrentLocationAction />
<ToggleLayerAction />
<CaptureMarkerAction Target="" />
<NavigateSelectionAction />
<NavigateCarSelectionAction />
<CaptureDistanceAction />
<OpenUriShellAction Uri="" />
<CaptureCarDestinationAction />
<AutoCenterMapAction MarkerIcon="" />
Shell Action Type
- Primary
- Secondary
Layers
<Layer Name="" Title="" IsActive="" AllowActivate="" />
<NativeLayer Type="" />
<TileLayer TileRef="" />
<VectorLayer Entity="" MinimumZoomLevel="" MaximumZoomLevel="" ZIndex="" Filter="" AllowSelection="">
<FeatureInfo Title="" Detail="" Preview="">
<!--Shell Actions-->
</FeatureInfo>
</VectorLayer>
<MarkerVectorLayer Icon="" SelectionIcon="" IconSize="" AnchorPoint="" Label="" LabelSize="" />
<LineVectorLayer Color="" StrokeWidth="" SelectionColor="" IsDashed="" SelectionBuffer="" />
<PolygonVectorLayer Color="" FillColor="" StrokeWidth="" SelectionColor="" SelectionFillColor="" IsDashed="" />
<CircleVectorLayer Color="" FillColor="" StrokeWidth="" SelectionColor="" SelectionFillColor="" IsDashed="" Radius="" />
Native Layer Type
- Roads
- Satellite
- Hybrid
JavaScript API
General
message(message: string): void;
alert(message: string, accept: string, cancel: string, resultCallback: (result: boolean) => void): void;
getUserName(): string;
getUserId(): string;
getActiveAreaId(): string;
getSessionKey(key: string): any;
setSessionKey(key: string, value: any): void;
removeSessionKey(key: string): void;
hasSessionKey(key: string): boolean;
getClipboardText(resultCallback: (text: string) => void): void;
setClipboardText(text: string): void;
syncEntity(name: string, resultCallback: () => void): void;
/*
Supported formats:
AZTEC,CODABAR,CODE_39,CODE_93,CODE_128,DATA_MATRIX,EAN_8,EAN_13,ITF,MAXICODE,PDF_417,
QR_CODE,RSS_14,RSS_EXPANDED,UPC_A,UPC_E,UPC_EAN_EXTENSION,MSI,PLESSEY,IMB
If no format is passed, QR_CODE is assumed.
You can specify multiple formats separated by a comma.
*/
scanCode(resultCallback: (code: string) => void, formats?: string): void;
httpRequest(url: string, method: string, headers: {}, data: string, resultCallback: (result: string) => void): void;
navigate(target: string, parameters: {}): void;
setVisible(name: string, visible: boolean): void;
isVisible(name: string): boolean;
show(name: string): void;
hide(name: string): void;
setEnabled(name: string, enabled: boolean): void;
isEnabled(name: string): boolean;
enable(name: string): void;
disable(name: string): void;
getEntities(entity: string, filter: string, filterParameters: {}, resultCallback: (entities: {}[]) => void);
getEntity(entity: string, id: string, resultCallback: (entity: {}) => void);
getEntityByLocation(entity: string, geometry: Geometry, resultCallback: (entity: {}) => void);
getEntityCount(entity: string, filter: string, filterParameters: {}): number;
getEntityFieldById(entity: string, field: string, id: string, resultCallback: (value: any) => void);
getEntityField(entity: string, field: string, filter: string, filterParameters: {}, resultCallback: (value: any) => void);
saveEntity(entity: string, values: {}, resultCallback: (id: string) => void);
updateEntity(entity: string, id: string, values: {}, resultCallback: () => void);
deleteEntity(entity: string, id: string, resultCallback: () => void);
List
getValue(fieldName: string): any;
setValue(fieldName: string, value: any): void;
Form
getValue(fieldName: string): any;
setValue(fieldName: string, value: any): void;
copyValue(sourceFieldName: string, targetFieldName: string): void;
//Returns distance from current GPS position to geometry center in meters
getDistance(fieldName: string): number;
setDateNow(fieldName: string): void;
setGpsPosition(fieldName: string, accuracyFieldName?: string, altiudeFieldName?: string): void;
collapse(groupName: string): void;
expand(groupName: string): void;
setRequired(fieldName: string, required: boolean): void;
isRequired(fieldName: string): boolean;
isInsert(): boolean;
setValid(valid: boolean): void;
isValid(): boolean;
refresh(fieldName: string): void;
Scripts can be used in multiple ways
<!--As row action in a list-->
<List.RowActions>
<ScriptRowAction>
<ScriptRowAction.Script>
</ScriptRowAction.Script>
</ScriptRowAction>
</List.RowActions>
<!--After a selection in a list-->
<List.SelectionScript>
</List.SelectionScript>
<!--Before or after any action-->
<DeleteShellAction>
<DeleteShellAction.BeforeScript>
</DeleteShellAction.BeforeScript>
<DeleteShellAction.AfterScript>
</DeleteShellAction.AfterScript>
</DeleteShellAction>
<!--As field action in a form-->
<Entry Name="entry" Title="Entry">
<ScriptFieldAction>
</ScriptFieldAction>
</Entry>
<!--After loading a form-->
<Form.Scripts>
<StartupScript>
</StartupScript>
</Form.Scripts>
<!--After changing a field in a form-->
<Form.Scripts>
<ChangeScript Field="FieldName" Name="OnFieldNameChanged">
</ChangeScript>
</Form.Scripts>
<!--After a selection in a map-->
<NativeMap.SelectionScript>
</NativeMap.SelectionScript>
<!--After a selection in a map for a specific vector layer-->
<MarkerVectorLayer.SelectionScript>
</MarkerVectorLayer.SelectionScript>
Graphics
Icons
Icon | Name | Icon | Name | Icon | Name | Icon | Name | Icon | Name |
---|---|---|---|---|---|---|---|---|---|
AppSelect | AreaList | Back | Bell | Chat | |||||
Checklist | Compass | DataSource | Delete | DeviceList | |||||
Distance | Down | Download | Filter | Flag | |||||
Gps | Hamburger | Help | Home | Info | |||||
Left | LineList | List | Logging | Logout | |||||
Map | Message | More | New | Password | |||||
PinList | QRCode | Request | Right | RightList | |||||
SatelliteMap | Save | Setting | Start | Stop | |||||
StreetMap | Summary | Synchronize | Text | TopoMap | |||||
Up | Url | User | UserList | Walk | |||||
Work | World | X |
Actions
Icon | Name | Icon | Name | Icon | Name | Icon | Name | Icon | Name |
---|---|---|---|---|---|---|---|---|---|
Alert | Attachment | Bicycle | Bin | Camera | |||||
Car | Check | Click | Clock | Delete | |||||
Edit | EditArea | EditLine | EditPin | Expand | |||||
Gps | Helicopter | Info | Layer | Map | |||||
Micro | Minus | More | NewArea | NewLine | |||||
NewPin | Pause | Phone | Plus | ||||||
Prev | Question | Refresh | Save | Search | |||||
Signature | Start | Stop | View | Walk | |||||
World |
Map
Icon | Name | Icon | Name | Icon | Name | Icon | Name | Icon | Name |
---|---|---|---|---|---|---|---|---|---|
Area | Arrow | Bicycle | Car | Delete | |||||
Edit | End | Helicopter | Line | Pin | |||||
Plus | Start | Walk |
Server Side Customization
You need Visual Studio to create custom triggers and providers
Create a C# class library and reference the following assemblies from the Mobile/bin directory:
AppShell.Core.dll AppShell.Services.Core.dll
Compile the class library and copy it into the Mobile/bin directory.
Custom Triggers
The following trigger will simply add the values of the two form fields Field1 and Field2 and store the result in the SumField.
using AppShell.Core;
using AppShell.Services.Core;
using System;
using System.Threading.Tasks;
namespace SampleTriggers
{
[Trigger(nameof(AddTrigger))]
public class AddTrigger : ITrigger
{
public Task ExecuteAsync(TriggerContext context)
{
context.Values["SumField"] = Convert.ToInt32(context.Values["Field1"]) + Convert.ToInt32(context.Values["Field2"]);
return Task.FromResult(0);
}
}
}
You can use the custom trigger in the Shell.xaml like that:
<Entity.Triggers>
<Trigger Type="AddTrigger" Method="BeforeSave,BeforeUpdate" />
</Entity.Triggers>
Custom Providers
IUserSessionProvider
The user session provider is called when an app is selected in the app selection screen.
using AppShell.Services.Core;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace SampleProviders
{
public class MyUserSessionProvider : IUserSessionProvider, IAutoRegister<IUserSessionProvider, MyUserSessionProvider>
{
protected readonly IDatabaseProvider databaseProvider;
public MyUserSessionProvider(IDatabaseProvider databaseProvider)
{
this.databaseProvider = databaseProvider;
}
public async Task<IDictionary<string, object>> GetUserSessionAsync(string appName, string userId)
{
if (appName != "MyApp")
return new Dictionary<string, object>();
using (IDatabase database = await databaseProvider.GetAppConnectionAsync(appName))
{
string value = await database.ExecuteScalarAsync<string>("SELECT MyValue FROM MyTable WHERE Id = @Id", new { Id = 1 });
return new Dictionary<string, object>() { { "MyValue", value } };
}
}
}
}
IUserHandler
The user handler is called after a login, after an app has been selected in the app selection screen and after the user actually logged into the selected app.
using AppShell.Services.Core;
namespace SampleProviders
{
public class MyUserHandler : IUserHandler, IAutoRegister<IUserHandler, MyUserHandler>
{
public void AfterLogin(string userId)
{
}
public void AfterAppSelection(string appName, string userId)
{
}
public void AfterShellSelection(string shellName, string userId)
{
}
public void AfterActivity(string userId)
{
}
}
}
Samples
Shell
Apply a default filter to an entity
<Entity.Filters>
<Filter Id="OpenTasks" Sql="endtime IS NULL" IsDefault="True" />
</Entity.Filters>
Filter an entity by user id
<Entity.Filters>
<Filter Id="UserTasks" Sql="userid = @{System.UserId}" IsDefault="True" />
</Entity.Filters>
Add a regex validator to a field
<Field Name="name" Type="String" IsRequired="True">
<RegexValidator Pattern="^[a-zA-Z0-9]+$" />
</Field>
Add a trigger to an entity which is executed before an insert or update and sets the current user id
<Entity.Triggers>
<UpdateFieldTrigger Method="BeforeSave,BeforeUpdate" Field="userid" Value="@{System.UserId}" />
</Entity.Triggers>
Using a TMS tile source
<Shell.Tiles>
<UrlTileOverlay Id="tms" TileWidth="256" TileHeight="256" MinimumZoomLevel="0" MaximumZoomLevel="20"
Url="https://<tileserver>/{z}/{x}/{y}.png" />
</Shell.Tiles>
Using a restful WMTS tile source
<Shell.Tiles>
<UrlTileOverlay Id="wmts" TileWidth="512" TileHeight="512" MinimumZoomLevel="0" MaximumZoomLevel="20"
Url="https://maps.wien.gv.at/basemap/bmaphidpi/normal/google3857/{z}/{y}/{x}.jpeg" />
</Shell.Tiles>
Using a WMS tile source
<Shell.Tiles>
<UrlTileOverlay Id="wms" TileWidth="512" TileHeight="512" MinimumZoomLevel="10" MaximumZoomLevel="20"
Url="https://data.wien.gv.at/daten/geo?version=1.3.0&service=WMS&request=GetMap&crs=EPSG:4326&bbox={bbox}&width={width}&height={height}&layers=ogdwien:SPIELPLATZOGD&styles=&format=image/png&transparent=true" />
</Shell.Tiles>
List
Show a field in a list
<List xmlns="clr-namespace:AppShell;assembly=AppShell">
<ListCell Name="name" Title="Name" />
</List>
Show distance from current GPS position to geometry center
<List xmlns="clr-namespace:AppShell;assembly=AppShell">
<DistanceListCell Name="geometry" Title="Distance" />
</List>
Show an image in a list depending on a field
<List xmlns="clr-namespace:AppShell;assembly=AppShell">
<ImageListCell Name="status" Title="Status" Width="48" StringFormat="{}Icons.Status{0}.png" />
</List>
If the value of status would be 2, the icon would resolve to Icons/Status2.png in the shell folder
Show an image in a list depending on a field with a mapping
<List xmlns="clr-namespace:AppShell;assembly=AppShell">
<ImageListCell Name="status" Title="Status" Width="48" StringFormat="{}Icons.{0}.png" Fallback="Red">
<Mapping Key="0" Value="Red" />
<Mapping Key="1" Value="Yellow" />
<Mapping Key="2" Value="Green" />
</ImageListCell>
</List>
If the value of status would be 2, the icon would resolve to Icons/Green.png in the shell folder If the value is not found in the mapping it will fallback to Icons/Red.png
Show an image in a list depending on a script value
<List xmlns="clr-namespace:AppShell;assembly=AppShell">
<ImageListCell Name="begintime" Title="Status" Width="48" StringFormat="{}Icons.{0}.png">
<ImageListCell.ScriptValue>
var dateNow = new Date();
Context.getValue('begintime') < dateNow ? 'Red' : 'Green';
</ImageListCell.ScriptValue>
</ImageListCell>
</List>
If begintime is in the past it will show Icons/Red.png, otherwise it will show Icons/Green.png
Show multiple fields in one cell
<MultiListCell Name="NameDescription" Title="Name / Description">
<ListCell Name="name" />
<ListCell Name="description" />
</MultiListCell>
Show date value with a specific format
<List xmlns="clr-namespace:AppShell;assembly=AppShell">
<ListCell Name="begindate" Title="Begin Date" StringFormat="d" />
</List>
Format | Description | en-US | de-DE |
---|---|---|---|
d | Short date pattern. | 6/15/2009 | 15.06.2009 |
D | Long date pattern. | Monday, June 15, 2009 | Montag, 15. Juni 2009 |
f | Full date/time pattern (short time). | Monday, June 15, 2009 1:45 PM | Montag, 15. Juni 2009 13:45 |
F | Full date/time pattern (long time). | Monday, June 15, 2009 1:45:30 PM | Montag, 15. Juni 2009 13:45:30 |
g | General date/time pattern (short time). | 6/15/2009 1:45 PM | 15.06.2009 13:45 |
G | General date/time pattern (long time). | 6/15/2009 1:45:30 PM | 15.06.2009 13:45:30 |
M | Month/day pattern. | June 15 | 15. Juni |
s | Sortable date/time pattern. | 2009-06-15T13:45:30 | 2009-06-15T13:45:30 |
t | Short time pattern. | 1:45 PM | 13:45 |
T | Long time pattern. | 1:45:30 PM | 13:45:30 |
u | Universal sortable date/time pattern. | 2009-06-15 13:45:30Z | 2009-06-15 13:45:30Z |
U | Universal full date/time pattern. | Monday, June 15, 2009 11:45:30 AM | Montag, 15. Juni 2009 11:45:30 |
Y | Year month pattern. | June 2009 | Juni 2009 |
Standard Date and Time Format Strings
Sort a list
<List xmlns="clr-namespace:AppShell;assembly=AppShell">
<List.Sort>
<ListSort Name="geometry" Order="Descending" />
</List.Sort>
<DistanceListCell Name="geometry" Title="Distance" />
</List>
Add a row action which navigates to a map view and centers the map to geometry center
<List xmlns="clr-namespace:AppShell;assembly=AppShell">
<List.RowActions>
<NavigateRowAction Icon="View" Target="NativeMapNavigation">
<Parameter Name="Center" Value="@{geometry}" />
<Parameter Name="ZoomLevel" Value="15" />
<Parameter Name="SelectionId" Value="@{id}" />
</NavigateRowAction>
</List.RowActions>
</List>
Map value of a field to a display value in a list cell
<ListCell Name="DeviceType" Title="Device Type">
<Mapping Key="0" Value="iOS" />
<Mapping Key="1" Value="Android" />
<Mapping Key="2" Value="Windows" />
</ListCell>
Show value of a foreign entity in a list cell
<ListCell Name="DataSource_Id" Title="DataSource" ForeignField="Name" />
<!--Make sure to define ForeignEntity in your Shell.xaml-->
<Field Name="DataSource_Id" Type="Guid" IsRequired="True" ForeignEntity="DataSource" />
Enable search in a list
<List.ShellActions>
<SearchShellAction Filter="NameSearch" Placeholder="Your search hint" />
</List.ShellActions>
<!--Shell.xaml-->
<Entity.Filters>
<Filter Id="NameSearch" Sql="name LIKE @{NameSearch}" />
</Entity.Filters>
Enable search in a list on a foreign field
<List.ShellActions>
<SearchShellAction Filter="DataSourceSearch" Placeholder="Your search hint" />
</List.ShellActions>
<ListCell Name="DataSource_Id" Title="DataSource" ForeignField="Name" />
<!--Shell.xaml-->
<Entity.Filters>
<Filter Id="DataSourceSearch" Sql="DataSource_Id__Name LIKE @{DataSourceSearch}" />
</Entity.Filters>
<!--Make sure to define ForeignEntity in your Shell.xaml-->
<Field Name="DataSource_Id" Type="Guid" IsRequired="True" ForeignEntity="DataSource" />
Enable filtering in a list
<List.ShellActions>
<FilterShellAction Target="TasksFilter" />
</List.ShellActions>
<!--TasksFilter.xaml-->
<?xml version="1.0" encoding="utf-8" ?>
<Form xmlns="clr-namespace:AppShell;assembly=AppShell">
<Entry Name="Name" Title="Name" FilterOperator="Contains" />
<DateTimePicker Name="From" Title="From" FilterOperator="GreaterEqual" FilterField="begintime" />
<DateTimePicker Name="To" Title="To" FilterOperator="LessEqual" FilterField="begintime" />
</Form>
<!--Shell.xaml-->
<Navigation Id="MasterDetailNavigation">
<Form Id="TasksFilter" Title="Filter" View="TasksFilter" Entity="{x:Reference Tasks}"/>
</Navigation>
Form
Picker with static values
<Form xmlns="clr-namespace:AppShell;assembly=AppShell">
<Picker Name="color" Title="Color" KeyMember="Key" DisplayMember="Value"
Items="{KeyValueList Red/Green/Blue}" />
</Form>
Picker with static keys and values
<Form xmlns="clr-namespace:AppShell;assembly=AppShell">
<Picker Name="country" Title="Country" KeyMember="Key" DisplayMember="Value"
Items="{KeyValueList at-Austria/de-Germany/us-United States}" />
</Form>
Picker with values from an entity
<Form xmlns="clr-namespace:AppShell;assembly=AppShell">
<Picker Name="task_id" Title="Task" KeyMember="id" DisplayMember="name"
Items="{Entity Tasks}" />
</Form>
Picker with values from an entity sorted by a field
<Form xmlns="clr-namespace:AppShell;assembly=AppShell">
<Picker Name="task_id" Title="Task" KeyMember="id" DisplayMember="name"
Items="{Entity Tasks, Sort=name}" />
</Form>
Picker with values from an entity and a filter applied
<Entity Id="Tasks" Table="tasks" Key="id" SyncType="Automatic">
<Entity.Filters>
<Filter Id="OpenTasks" Sql="enddate IS NULL" />
</Entity.Filters>
...
</Entity>
<Form xmlns="clr-namespace:AppShell;assembly=AppShell">
<Picker Name="task_id" Title="Task" KeyMember="id" DisplayMember="name"
Items="{Entity Tasks, Filter=OpenTasks}" />
</Form>
Picker with values filtered based on another picker
<Entity Id="Countries" Table="countries" Key="id" SyncType="Automatic">
<Field Name="id" Type="Guid" IsRequired="True" />
<Field Name="name" Type="String" IsRequired="True" />
</Entity>
<Entity Id="Cities" Table="cities" Key="id" SyncType="Automatic">
<Entity.Filters>
<Filter Id="CountryFilter" Sql="country_id = @{country_id}" />
</Entity.Filters>
<Field Name="id" Type="Guid" IsRequired="True" />
<Field Name="country_id" Type="Guid" IsRequired="True" />
<Field Name="name" Type="String" IsRequired="True" />
</Entity>
<Form xmlns="clr-namespace:AppShell;assembly=AppShell">
<Picker Name="country_id" Title="Country" KeyMember="id" DisplayMember="name"
Items="{Entity Countries}" />
<Picker Name="city_id" Title="City" KeyMember="id" DisplayMember="name"
Items="{Entity Cities, Filter=CountryFilter}" />
</Form>
DateTimePicker with a field action to set current date and time
<Form xmlns="clr-namespace:AppShell;assembly=AppShell">
<DateTimePicker Name="begin" Title="Begin">
<DateTimeNowFieldAction />
</DateTimePicker>
</Form>
Using a script field action to set a field value
<Form xmlns="clr-namespace:AppShell;assembly=AppShell">
<Entry Name="scriptfield" Title="Script Field">
<ScriptFieldAction Icon="Alert">
Context.setValue('scriptfield', 'Test');
</ScriptFieldAction>
</Entry>
</Form>
Validate if a user is near an object before saving it
<Form xmlns="clr-namespace:AppShell;assembly=AppShell">
<Form.ShellActions>
<SaveShellAction>
<SaveShellAction.BeforeScript>
var distance = Context.getDistance('geometry');
if (!distance || distance > 100) {
Context.setError('geometry', 'Distance must be < 100m to the venue');
Context.setValid(false);
}
</SaveShellAction.BeforeScript>
</SaveShellAction>
</Form.ShellActions>
</Form>
Add an image picker to your form
<ImagePicker Name="image" Title="Image" PreviewField="previewimage" SizeField="imagesize" MimeTypeField="imagemimetype">
<DownloadImageFieldAction />
<PickImageFieldAction />
<TakeImageFieldAction />
</ImagePicker>
PreviewField (optional field to store a thumbnail)
SizeField (optional field to store size of captured image)
MimeTypeField (optional field to store mime type of captured image)
Add support for paging to your form
<Form xmlns="clr-namespace:AppShell;assembly=AppShell">
<Form.ShellActions>
<PrevShellAction />
<NextShellAction />
</Form.ShellActions>
</Form>
Add an options group with a single selection
<OptionsGroup Name="Color" Title="Choose a color">
<Option Value="red" Title="Red" />
<Option Value="green" Title="Green" />
<Option Value="blue" Title="Blue" />
</OptionsGroup>
Add an options group with multiple selections allowed separated by a comma
<OptionsGroup Name="Color" Title="Choose colors" MultiSelect="True">
<Option Value="red" Title="Red" />
<Option Value="green" Title="Green" />
<Option Value="blue" Title="Blue" />
</OptionsGroup>
Add an options group with multiple selections allowed saved into multiple boolean fields
<OptionsGroup Title="Choose colors">
<Option Field="red" Title="Red" />
<Option Field="green" Title="Green" />
<Option Field="blue" Title="Blue" />
</OptionsGroup>
Group fields in a form
<Group Name="History" Title="History">
<Entry Name="CreatedBy" Title="Created By" IsEnabled="False" />
<DateTimePicker Name="CreationTime" Title="Creation Time" IsEnabled="False" />
<Entry Name="UpdatedBy" Title="Update By" IsEnabled="False" />
<DateTimePicker Name="LastUpdateTime" Title="Update Time" IsEnabled="False" />
</Group>
Show fields in different tab groups
<TabGroup Name="Tabs" Title="Tabs" IsExpanded="True">
<FieldTab Name="Tab1" Title="Tab 1">
<FieldTab.Fields>
<Entry Name="Entry1" Title="Entry 1" />
</FieldTab.Fields>
</FieldTab>
<FieldTab Name="Tab2" Title="Tab 2">
<FieldTab.Fields>
<Entry Name="Entry2" Title="Entry 2" />
</FieldTab.Fields>
</FieldTab>
<FieldTab Name="Tab3" Title="Tab 3">
<FieldTab.Fields>
<Entry Name="Entry3" Title="Entry 3" />
</FieldTab.Fields>
</FieldTab>
</TabGroup>
Capture a point geometry
<Geometry Name="geometry" Title="Geometry">
<GeometryFieldAction Icon="EditPin" Target="NativeMap" Edit="True" />
</Geometry>
Capture a line geometry
<Geometry Name="geometry" Title="Geometry">
<GeometryFieldAction Icon="EditLine" GeometryType="LineString" Target="NativeMap" Edit="True" />
</Geometry>
Capture a polygon geometry
<Geometry Name="geometry" Title="Geometry">
<GeometryFieldAction Icon="EditArea" GeometryType="Polygon" Target="NativeMap" Edit="True" />
</Geometry>
Populate an entry from a web service
<Form xmlns="clr-namespace:AppShell;assembly=AppShell">
<Form.Scripts>
<StartupScript>
Context.httpRequest('https://jsonplaceholder.typicode.com/todos/1', 'GET', {}, null, function (result) {
Context.setValue('scriptfield', JSON.parse(result).title);
});
</StartupScript>
</Form.Scripts>
<Entry Name="scriptfield" Title="Script Field" />
</Form>
Call a web service before saving
<Form xmlns="clr-namespace:AppShell;assembly=AppShell">
<Form.ShellActions>
<SaveShellAction>
<SaveShellAction.BeforeScript>
Context.httpRequest('<apiurl>', 'POST', {}, JSON.stringify({ data: Context.getValue('scriptfield') }), function (result) {
});
</SaveShellAction.BeforeScript>
</SaveShellAction>
</Form.ShellActions>
<Entry Name="scriptfield" Title="Script Field" />
</Form>
Map
Map with native roads and satellite layer
<NativeMap xmlns="clr-namespace:AppShell;assembly=AppShell">
<NativeMap.Layers>
<NativeLayer Type="Roads" />
<NativeLayer Type="Satellite" />
</NativeMap.Layers>
</NativeMap>
Reference a tile layer from Shell.xaml
<NativeMap xmlns="clr-namespace:AppShell;assembly=AppShell">
<NativeMap.Layers>
<TileLayer TileRef="basemap" />
</NativeMap.Layers>
</NativeMap>
Add a marker vector layer with one of the embedded map icons
<NativeMap xmlns="clr-namespace:AppShell;assembly=AppShell">
<NativeMap.Layers>
<MarkerVectorLayer Entity="Wifis" MinimumZoomLevel="5" MaximumZoomLevel="20" Icon="Map.Pin.png" />
</NativeMap.Layers>
</NativeMap>
Add a marker vector layer with an icon you deliver within the shell folder In this example a folder Icons with a file MyIcon.png inside is expected in the shell folder. You must also include MyIcon@2x.png, MyIcon@3x.png, MyIcon@4x.png for high DPI devices.
<NativeMap xmlns="clr-namespace:AppShell;assembly=AppShell">
<NativeMap.Layers>
<MarkerVectorLayer Entity="Wifis" MinimumZoomLevel="5" MaximumZoomLevel="20" Icon="Icons.MyIcon.png" />
</NativeMap.Layers>
</NativeMap>
Add a marker vector layer with an icon depending on a field
<NativeMap xmlns="clr-namespace:AppShell;assembly=AppShell">
<NativeMap.Layers>
<MarkerVectorLayer Entity="Wifis" MinimumZoomLevel="5" MaximumZoomLevel="20" Icon="wifitype" />
</NativeMap.Layers>
</NativeMap>
Add a marker vector layer with a filter applied
<Entity.Filters>
<Filter Id="FreeWifiFilter" Sql="isfree = 1" />
</Entity.Filters>
<NativeMap xmlns="clr-namespace:AppShell;assembly=AppShell">
<NativeMap.Layers>
<MarkerVectorLayer Entity="Wifis" MinimumZoomLevel="5" MaximumZoomLevel="20" Icon="Map.Pin.png" Filter="FreeWifiFilter" />
</NativeMap.Layers>
</NativeMap>
Show feature info on selection of a marker
<NativeMap xmlns="clr-namespace:AppShell;assembly=AppShell">
<NativeMap.Layers>
<MarkerVectorLayer Entity="Wifis" MinimumZoomLevel="5" MaximumZoomLevel="20" Icon="Map.Pin.png">
<FeatureInfo Title="@{id}" Detail="Address: @{address}">
<NavigateShellAction Icon="Edit" Target="TaskForm">
<Parameter Name="Id" Value="@{id}" />
</NavigateShellAction>
</FeatureInfo>
</MarkerVectorLayer>
</NativeMap.Layers>
</NativeMap>
Add a line vector layer
<NativeMap xmlns="clr-namespace:AppShell;assembly=AppShell">
<NativeMap.Layers>
<LineVectorLayer Entity="Street" Color="#FF0000" SelectionColor="#00FF00" StrokeWidth="5" />
</NativeMap.Layers>
</NativeMap>
Add a polygon vector layer
<NativeMap xmlns="clr-namespace:AppShell;assembly=AppShell">
<NativeMap.Layers>
<PolygonVectorLayer Entity="Boundary" Color="#FF0000" FillColor="#88FF0000"
SelectionColor="#00FF00" SelectionFillColor="#8800FF00" />
</NativeMap.Layers>
</NativeMap>
Capture a point geometry
<NativeMap xmlns="clr-namespace:AppShell;assembly=AppShell">
<NativeMap.ShellActions>
<GeometryShellAction Entity="PointEntity" Target="PointForm" />
</NativeMap.ShellActions>
</NativeMap>
Capture a line geometry
<NativeMap xmlns="clr-namespace:AppShell;assembly=AppShell">
<NativeMap.ShellActions>
<GeometryShellAction Entity="LineEntity" GeometryType="LineString" Target="LineForm" />
</NativeMap.ShellActions>
</NativeMap>
Capture a polygon geometry
<NativeMap xmlns="clr-namespace:AppShell;assembly=AppShell">
<NativeMap.ShellActions>
<GeometryShellAction Entity="PolygonEntity" GeometryType="Polygon" Target="PolygonForm" />
</NativeMap.ShellActions>
</NativeMap>