Documentation

Intro

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

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

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

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>
<MenuItem Target="" Title="" Icon="" Type="" />

Target can be a view id from Shell.xaml or AppSelection/Logout

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

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

Cells

<Cell Name="" Title="" ShortTitle="" Width="" DisplaySize="" WordWrap="" ScriptValue="" />

<ListCell StringFormat="" ForeignField="" />
<DistanceListCell />
<ImageListCell />
<MultiListCell>
  <!--List Cells-->
</MultiListCell>

Display Size

Word Wrap

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

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

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

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 Pdf 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&amp;service=WMS&amp;request=GetMap&amp;crs=EPSG:4326&amp;bbox={bbox}&amp;width={width}&amp;height={height}&amp;layers=ogdwien:SPIELPLATZOGD&amp;styles=&amp;format=image/png&amp;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 &gt; 100) {
          Context.setError('geometry', 'Distance must be &lt; 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>