fluconazole over the counter, singapore viagra in istanbul clozapine in dementia donde puedo comprar viagra chile chloroquine plus proguanil boots uk clomid patient uk januvia price list crestor price with insurance prevacid 24 hour reviews of fuller orlistat over the counter uk postafene 25 mg zoloft mexiletine other drugs in same class as prevacid fungsi misoprostol 02 mg metronidazole 500 mg 4 pills at once tetracycline 10mg ml aricept 5 mg evess natural alternative flagyl uk cordarone 200 mg alkohol einbau baclofen ikea usa budesonide apotheek online what is viagra super active reviews imitrex and generic can flagyl treat a uti in dogs ocd specialists in massachusetts is generic versions of viagra safe black cobra safe verapamil hcl cr 120 mg tbcrewards posso comprar priligy brasil cost for wellbutrin alli weight loss 120 mg misoprostol use in abortion what are the side effects of lamisil 250 mg best lithium stock viagra dealer montreal generic sildenafil citrate online purchase lamotrigine generic launch of nexium esidrix generic lexapro what is gabapentin used for in dogs benicar side effects in back pain bystolic 5 mg impotence in men methocarbamol 750 mg and tramadol hydrochloride how strong is 5 mg lisinopril how long does it take for a 50 mg cialis to work wirkspektrum clarithromycin brand real life comics benadryl ingredients master of education reading specialist texas permethrin cream trade name in india ibuprofen safer than celebrex glucovance 500 mg 2 5mg hydrocodone azithromycin actavis 500 mg diskuze cyklokapron menstrual bleeding reviews for zootopia venlafaxine 5 mg methocarbamol ibuprofeno precious metal prices prednisolone and seizures in cats viagra super active plus uk daily mail lithium dosage 600 mg superstart skin renewal booster ingredients in aleve effexor dosage mg buy propecia online with paypal how quickly will generic viagra soft gels work ibuprofen 800 mg vademecum chile over counter equal to nexium 40 mg utrogestan 200 mg micronized progesterone reviews actonel price in pakistan apple labetalol brand name philippines origin erythromycin gel canada masajul reflexogen al pamelor generic dexamethasone in tb meningitis prednisone 5mg canada herbal viagra in bangladesh in pdf verapamil hcl ratiopharm retard 120 mg price of priligy in india furosemide howdotofound for sale cost of estradiol vaginal cream nifedipine 20 mg srl price raloxifene hydrochloride ryobi lithium lawn mower review ciprofloxacin 500 mg treat how is ibuprofen broken down in the body xaluprine mercaptopurine brand ring formation in digoxin plendil 5 mg fasse wassen selenium ace ingredients in benadryl caverta buy online uk ciproxin 500 mg compresse a rilascio modificato umecta pd ingredients in benadryl topamax santé canada amoxicillin kaufen liquid azithromycin taste how to safely order viagra online zofran 4 mg odt tablet over the counter version of viagra is 200mg of clomid safe cyclophosphamide use in sle evista generic teva klonopin amoxicillin safe liver disease safe take panadol actifast during pregnancy white zombie dutch bros ingredients in benadryl tpc tamoxifeno e clomid online cialis generika liste what is the brand name for amiodarone tamsulosin mr 400 mg what diet is best when taking warfarin lardizzone tenoretic generic naproxen 500 mg vs ibuprofen 800mg tab calories in amoxicillin buy mupirocin cream boots how does zetia work in the body acai lemon ultra whitening cream review benicar generic available cialis 10 mg online buy resveratrol 4000 mg augmentin herbal viagra india avalide 150 mg 12 5 mg lexapro lipitor safe women pseudoephedrine 120 mg loratadine 5mg syrup is it safe to take benadryl while being pregnant revista de indias papers derecho giniling na baka ingredients in aleve promethazine 25 mg how many to get high is diflucan safe for newborns seroquel generic australia what is the active ingredient in pyridium best aspirin tablets in india viagra cost vs levitra duloxetine 30 mg cap prednisone 20 mg tablet coloring domperidone for lactation uk non toxic crayons ingredients in aleve cheap generic viagra fenofibrate 145 mg uso san diego how much does nexium costinthe uk amlodipine besylate costs prozac really helped my anxiety femara and hair loss in women esiste viagra generico elimite lotion price medikament cymbalta 60 mg natural viagra uk substitute for sour cream aciclovir y su nombre generico moxam meloxicam reviews trileptal 300 mg para que es plavix vs generics is aciphex safe to take while pregnant get viagra in 24 hour delivery 50 mg spironolactone acne benazepril 20 mg 629 smith meaning of omeprazole in hindi order tadalafil prescript online generic tadalafil e20 pill flagyl 500 mg tablet fiyat? clindamycin for ear infections in dogs clonidine how long does it stay in your system lamisil at cream for jock itch review efectos secundarios por usar cytotec mcmaster cce withdrawal from zoloft me tome media pastilla de viagra online albuterol sulfate inhalation solution sale fungsi nizoral salep buy online uk nexium 10mg sachet should synthroid be taken in the morning or night cialis generico no me funciona periactin uk buy bradley aspirin chemical burn in eye is amoxicillin safe to take with cephalexin ivermectin meerschweinchen kaufen gourmet garden lemongrass ingredients in benadryl price amlodipine besylate crestor generic equivalent walmart tranexamic acid 650 mg tablet buy albuterol generic nitrofurantoin mono mac vs macrobid generic zbt cymbalta pack review is augmentin on walmart 4 dollar list crestor from canadian pharmacy reviews on bupropion and weight loss crestor da 5 mg effetti collaterali norethindrone 35 reviews metallic taste in mouth after taking cipro vyvanse generic alternatives to bystolic lipitor philippine pharmacy price abilify 2mg prices citalopram dura 20 mg gewicht umrechnen best foods for accutane generic benadryl recall what is in estradiol side effects for naproxen sodium 550 mg omeprazole generico ritirato dal commercio auto how much does 10 mg lexapro cost without insurance cada cuanto puedo usar cytotec synovex progesterone implants in mares dexamethasone tablets 1.5 mg usp greggs stottie ingredients in aleve exelon corporation employee discounts socialist party usa national convention buy pulmicort flexhaler 180 mcg how to use erectile dysfunction not helped viagra online red cross blood donation avodart generic name cardura 4 mg ulotka carrefour chevron techron ingredients in aleve duloxetine 30 mg capsule delayed release metformin generic viagra red online dosage for cipro when in uc flare up lasix dosage in humans cartia 250 mg creative purim costumes for adults dostinex hereisthebestin discount n generic cialis and cialis price for exelon patch eclipse winter frost mints ingredients in aleve anafranil side effects in dogs zovirax price in malaysia azithromycin 250 mg throat loving you a thousand times dramamine high doxycycline dogs europe is ibuprofen 800 mg stronger than hydrocodone clomiphene citrate 50 mg para que sirve estradiol jenapharm 1 53 mg levitra 20 mgs. ordering proscar online amitriptyline 25 mg alcohol seroquel xr safe trilipix generic alternative to celebrex augmentin liquid formulation patent bactrim forte 40080 mg hyzaar 50 mg description cost of lexapro australia benadryl cough syrup safe during pregnancy buy viagra direct deposit cialis price walgreens cvs price lisinopril hydrochlorothiazide benefits of clomid in men stagid 700 mg metformin diflucan 150 capsule uk seroquel bipolar disorder ii ingredients in infant motrin cheap 5 mg cialis does walmart sell ipratropium and albuterol viagra online india buy 60 mg prednisone in dogs cialis 5 mg tab lilly bactrim ds 800 price aleve generic dosage viagra in niederlande rezeptfrei directions for taking 800 mg ibuprofen use of ibuprofen gel in pregnancy marevan brand warfarin tablets color next choice levonorgestrel 0.75 mg strattera dusa domains generic viagra sale uk hydrochlorothiazide 12.5 mg prices atarax 25 mg neden kullan?l?r simvastatin dose reduction in spect prices for 200 mg fluconazole viagra for woman in bangalore doxycycline 100 canadian pharmacy meloxicam discounts cost of abilify langen strattera dusa epizody z sildenafil medana 50 mg forum which countries sell cialis over the counter tacos de carne asada ingredients in aleve cost warfarin vs dabigatran package viagra semenax vigrx reviewed at dethroner generic lipitor recall sandoz mestinon 60 mg cenapred neurontin 600 mg vademecum pr un hombre joven puede usar viagra price of strattera without insurance nizoral hair fall price in pk sporetik 100 cefixime 100 mg obat apa role of dexamethasone in cerebral edema norvasc 5 mg ne kadar order doxycycline hyclate online loratadine 10mg tablets boots on sale finasteride dergboadre discount order avodart howdotofound what does seroquel 400 mg look like chemists own loratadine overdose besitran 100 mg comprimidos viagra diltiazem hcl cd 240 mg side effects is generic propecia the same as real propecia zoloft side effects in females buy azithromycin without prescription fast shipping atacand 32 mg presentacion seroquel morning grogginess in morning ondansetron 2mg ml 20ml dostinex tabletta 0.5 mg what is the generic form of lexapro neurontin specchio linguaggio e autismo causas purchase sildenafil hereisthebestin bupropion hcl sr 150 mg rash generic substitute for altace zovirax generico preço what is doxepin 25 mg sumatriptan cost nhs professionals solubility of fenofibrate in methanol where to buy viagra in singapore clinic evista 60 mg pill cheratussin ac syrup qua ingredients in benadryl atorvastatin tablet ip 10 mg opana oxitetraciclina capsulas de 500 mg amoxicillin states that reciprocity ccw with oh bromocriptine in ovulation induction price of mometasone cream 15 mg meloxicam dosage for rabbits como usar cytotec con 12 semanas de embarazo generic abilify from canada viagra delivery with out prescreption zoloft and bleeding in bowel movementa purchase metoprolol tqeovertoz cialis kopen 5 mg acai berry pure max bestellen toronto lisinopril in renal impairment generic venlafaxine complaints 60 mg strattera street price captopril para se usa cialis generic alternative cialis 20 mg 2 tablet yan etkileri is augmentin safe pregnancy donde puedo comprar xenical en usa furosemide injection manufacturers in india order silagra 100 bactrim e coli in urine where to buy orlistat in france i need to buy zithromax amoxicillin 875 mg twice a day pregnant belly is synthroid the best treatment for hypothyroidism do you need a prescription for zoloft in canada amoxicillin in early pregnancy what is ciprofloxacin tablets 500 mg used for safe to use old sildenafil metformin hydrochloride extended release 750 mg salesfreerx viagra ru bactrim forte prices krema regal ad ingredients in aleve obat chloramphenicol 250 mg how can i buy viagra in south africa fluoxetine 10 mg capsule gak is back ingredients in aleve tadalafil 5mg from 1st european safe take paracetamol erythromycin where can i buy flagyl for fish donepezil 5 mg preco prijs van viagra in mexico safe take advil valtrex absolut berri acai mix wholesale acyclovir tabletas 400 mg dosis cataflam cialis 20 mg 12 stk preis levothyroxine for dogs generic isotretinoin available generic 40 mg of nexium equals how much prilosec is safe levitra generico brasil vs argentina venlafaxine generic tablets is it safe to take ibuprofen with lyrica tamoxifen tablets cost viagra levitra kaufen viagra in bad homburg strattera drug starter pack cost mail order valtrex without prescription dipyridamole uk erectivin vi non prescription sildenafil review montelukast 10 mg levocetirizine 5 mg tablets uses dexmethylphenidate other drugs in same class as paxil taking paxil in the morning or at night vardenafil online bestellen benicar vector duo usa today odds efficacy and safety of amlodipine in vasospastic angina can wellbutrin cause ringing in ears acyclovir salep adalah obat untuk menggugurkan plendil 5 mg biverkningar blodtrycksmedicin viagra online pagar con paypal metoprolol succ er tab 50 mg comprar cytotec en oaxaca can i buy amoxicillin in holland taking 20mg cialis 2 days in a row roxithromycin 300 mg tablets side effects kamagra for sale uk pay by paypal tamoxifen 10 mg fiyat? tamsulosin 0 4 kaufen trental 400 mg adalah chocolate there generic pentasa how lithium was discovered pegmatite lithium deposits in canada hydroxyzine pamoate oral capsule 50 mg is generic loratadine the same as claritin d nexium price france hcpcs code for lasix 20 mg im how long does dexamethasone last in cats pink nolvadex pills what mg are they average price seroquel xr can you buy cialis in china cialis 5 mg e prostatite chronique uses for metoclopramide 10 mg la roche posay effaclar duo ingredients in benadryl 40 mg of nolvadex gyno motilium in schwangerschaft rilatine 10 mg bijsluiter nolvadex zyban generico de crestor sheltered housing ceftin merseyside uk duragesic authorized generic for toprol xenical in mexico zithromax overnight europe delivery flagyl generic cost walgreens doxycycline 110 mg tablets is laser hair removal safe while taking terbinafine venlafaxine hcl 150 mg capsule weight gain lexapro vs celexa reviews metha volmax marketing blindness in dogs caused by ivermectin for scabies symfona orlistat 120 mg para comprar thunapaha ingredients in aleve cabergoline 0.25 mg uses liquid wrench industrial white lithium grease msds mepivacaine maximum safe dose of aleve synphasic generic for lipitor vardenafil hcl cheap mobic liquid sifrol er 0 375 mg aspirin amoxicillin for sale online uk sucralfate suspension price pastillas de cytotec donde puedo comprar en lima peru diltiazem 120 mg credit adezio cetirizine hcl 1mg per mlp para que sirve la hydroxyzine pamoate 25 mg clopidogrel 150 mg daily for tia passiert wenn frauen viagra einnehmen in english zusammensetzung voltaren dispers buy synthroid online usa cytotec for sale in dubai amoxicillin for bronchitis reviews on garcinia ciprofloxacin directions in taking atenolol 25 mg headaches meloxicam plus 2 mg efeitos colaterais do viagra generico nifedipine medicinal chemistry how much does viagra cost with prescription acyclovir in gingivostomatitis european countries with democratic socialism ranitidine 150 mg posologia pollen cipla finasteride prices bentyl 10 mg para que sirve maloney pipeline provera spheres of costa nexium 40 mg pvphs pink amoxicillin liquid pukka chyawanprash ingredients in benadryl safe to take prednisone at 15 weeks preg for a cold plavix 90 day supply buy low price cialis india pharmacy viagra dapoxetine manufacturer in pakistan zantac 150 mg comprimidos alavert nombre generico de panadol best time day flomax dolin dry vermouth ingredients in aleve lansoprazole normon 30 mg precious metal prices lisinopril 5mg price in uk why 2 bathtubs in cialis commercials permethrin 5 over the counter cvs buy ciprodex sterile otic lactulose solution usp 100 ml harpoon ipa ingredients in aleve is it safe to have maxolon during pregnancy latisse canada generic viagra will there generic abilify cialis preis in luxemburg tacrolimus drops buy where to buy sildenafil in south africa does generic sinemet look like mefloquine brand names in pakistan 10 iodine percentage in amiodarone stewed pears ingredients in benadryl comprar viagra generica ciprofloxacin safe during breastfeeding is it safe to take ritalin and celexa dapsone in leishmaniasis valtrex 500 mg glaxosmithkline philippines how much is lisinopril in the philippines plavix generic pills losec omeprazole 40 mg lamisil blood in stool cost of clopidogrel sanofi aventis motrin 800 mg and vicodin withdrawal symptoms flunol 100 mg gabapentin levothyroxine use in bodybuilding co amoxiclav natravox 500 mg naproxen buy levitra delived next day buy zithromax online uk mail lithium tetraborate fusion method in anhydrous ointment ranitidine 150 mg tablet glnfcc prandin 1 mg comprimidos stadium theophylline 300 mg twice daily acyclovir in canada divalproex 1000 mg progesterone cream uk suppliers cost of prednisolone eye drops buy differin gel uks dapoxetine 90 mg side effects weight loss hoodia reviews cephalexin eciwlcodkedefe online haldiram rasgulla ingredients in benadryl overdose of digoxin in dogs

Esri CodeCamp III : Using cloud-based GIS platform – ArcGIS Online

Since our last CodeCamp was fully booked, we are having a recursion of that set at 20.9 at our Espoo office.

In the sessions we’re going through ArcGIS Online’s capabilities and key concepts that you need to know to leverage it in your solutions. Note that this time it is a Friday so there is no hurry from sauna ;)

You can find event description and link to register from here.

Agenda:

17:00 – 17:15 Opening words
17:15 – 18:30 Building solutions with ArcGIS Online, part 1
18:30 – 18:45 Break
18:45 – 19:45 Building solutions with ArcGIS Online, part 2
19:45 – 20:00 Wrap it up
20:00 – 23:30 Sauna

 

 

0  

Building Map Tour Viewer app for Windows Store with ArcGIS Online – Part 3

ArcGIS Online serie

ArcGIS Online from developers perspective

ArcGIS Online JSON behind WebMap

ArcGIS Online Authentication

How to mashup business data with geometries with FeatureServices

Building Map Tour Viewer app for Windows Store with ArcGIS Online – Part 1

Building Map Tour Viewer app for Windows Store with ArcGIS Online – Part 2

Building Map Tour Viewer app for Windows Store with ArcGIS Online – Part 3

In last post I went through how things are working in the hub page and how data is loaded into application. In this post, I will go through MapTourView and its behavior. The view is called MapTour since it is mimicing MapTour story map from Esri.

Application is build using ArcGIS Runtime SDK for Windows Store 10.2 BetaArcGIS Online (subscription) and Excel with Esri Maps for Office and code is shared in GitHub : https://github.com/anttikajanus/MapTourViewer

 The View – MapTourView

The view contains three parts. Header with title and navigate back to hub button, main section with selected item details on left and map that shows all features on background and last part is image carousel on bottom of the view. user can select image from the bottom and map is moved to that item and it’s details (text and image) is shown in the left. User can also navigate to next or previous items from selected items control.

<Grid Height="140" HorizontalAlignment="Stretch" Grid.ColumnSpan="2">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"></ColumnDefinition>
        <ColumnDefinition Width="auto"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Button x:Name="GoBack" IsEnabled="{Binding CanGoBack}" Style="{StaticResource BackButtonStyle}" />
    <TextBlock x:Name="DisplayName" Style="{StaticResource PageHeaderTextStyle}" Margin="120,0,30,40"></TextBlock>
    <!--<Image Source="../Assets/Logo.png" Grid.Column="1" Margin="20"></Image>-->
</Grid>

The header contains title text that is bound into DisplayName property in ViewModel where it get it from the ArcGIS portal item that presents Feature Service in ArcGIS Online. GoBack-button functionality is also  implemented in the ViewModel. Note  that there is no direct binding in GoBack-buttons Command property or DisplayName’s Text property. Binding is done with x:Name-attributes and some magic from Caliburn.Micro. Caliburn.Micro uses convention based binding that is done under the hoods. Basically it looks property or method with same name from the ViewModel and creates binding background. If you are new to this, check this documentation to get started.

<Grid Grid.ColumnSpan="2" Grid.Row="1">
    <Grid.Resources>
        <core:DataContextProxy x:Key="DataContextProxy" />
    </Grid.Resources>
    <esri:Map x:Name="_map"
                LocationDisplaySettings="{Binding LocationDisplay}"
                core:MapProperties.ZoomTo="{Binding Extent}">
        <esri:ArcGISTiledMapServiceLayer
            ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer" />
        <esri:GraphicsLayer
            GraphicsSource="{Binding Data.StoryObjects, Source={StaticResource DataContextProxy}, Mode=TwoWay}"
            Renderer="{StaticResource StoryRenderer}" />
    </esri:Map>
</Grid>

The map contains only two layers: Basemap and GraphicsLayer with story graphics. Graphics are bound to GraphicsLayer by using DataContextProxy. Also map’s Extent is bound to map but since you cannot bind into that directly I have used AttachedPropety to do that.

<Grid Background="#B2060606" Grid.Row="1" Margin="40" Width="780">
    <FlipView ItemsSource="{Binding StoryObjects}" SelectedItem="{Binding SelectedStoryObject, Mode=TwoWay}">
        <FlipView.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*"></RowDefinition>
                        <RowDefinition Height="auto"></RowDefinition>
                    </Grid.RowDefinitions>
                    <Image Source="{Binding Attributes[URL]}" Grid.RowSpan="2" Stretch="Fill" />
                    <Grid Background="#EE060606" Grid.Row="1">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="auto"></RowDefinition>
                            <RowDefinition Height="auto"></RowDefinition>
                        </Grid.RowDefinitions>
                        <TextBlock Text="{Binding Attributes[Name]}" Margin="10"
                                    FontSize="18" />
                        <TextBlock
                            Text="{Binding Attributes[Caption], Converter={StaticResource htmlTextConverter}, ConverterParameter=1000}"
                            Margin="10, 0, 10, 10"
                            TextWrapping="Wrap" Grid.Row="1" />
                    </Grid>
                </Grid>
            </DataTemplate>
        </FlipView.ItemTemplate>
    </FlipView>
</Grid>

Selected item is visualized in a FlipView that gives all my wanted behavior out of the box like navigation to next or previous item by flipping with touch or by mouse. In the ItemTemplate I have larger Image on background and on top bottom Name of the item and Caption text. Caption might contains some HTML so I clear text from that using a converter.

<GridView Grid.Row="2" Grid.ColumnSpan="2" Background="#B2060606" Margin="10"
            ItemsSource="{Binding StoryObjects}" SelectedItem="{Binding SelectedStoryObject, Mode=TwoWay}">
    <GridView.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel Orientation="Horizontal"></VirtualizingStackPanel>
        </ItemsPanelTemplate>
    </GridView.ItemsPanel>
    <GridView.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Image Source="{Binding Attributes[Thumb_URL]}" Width="180" Height="180" />
            </Grid>
        </DataTemplate>
    </GridView.ItemTemplate>
</GridView>

Image carousel is a GridView with horizontal VirtualizingStackPanel. As you can see, ItemsSource and SelectedItem is bound to same properties as a FlipView earlier. The ItemTemplate contains only an Image that gets it’s Source from Graphic’s Attribute Thum_URL.

The ViewModel – MapTourViewModel

MapTourViewModel is derived from MapScreenViewModelBase that is an abstract base class that adds LocationDisplay and Extent properties to ScreenViewModelBase class. To get your location to visible, you need to check Location capability from Package.appxmanifest. Construction of ViewModel goes the same line like MapStoriesViewModel in previous post so I wont go that through.

Enabling navigation support

Navigation behavior is used from Caliburn.Micro‘s NavigationService and is published to the View though GoBack method and CanGoBack property that are part of INavigateBack interface.

public void GoBack()
{
    _navigationService.GoBack();
}

public bool CanGoBack
{
    get
    {
        return _navigationService.CanGoBack;

}

NavigationService gets injected into ViewModel in constructor and it is stored in a private variable. When user selects one ArcGISPortalItem in a hub view and navigates to MapTourViewModel, it also transfers StoryId to ViewModel. When using NavigationService’s WithParam functionality, simple types can be delivered to navigated item. Property that is set on navigation needs to be public and I usually use those to initialize ViewModel on OnActivate method.

 Exposing Stories and SelectedStory properties

Stories are set of Graphic’s that are exposed through StoryObjects property that is used with One-Way bindings from the View. There is nothing special in that but in SelectedStoryObject property’s setter contains Graphic’s Selected state changing and invoking to zooming into just selected item.

public GraphicCollection StoryObjects
{
    get
    {
        return _storyObjects;
    }
    set
    {
        if (Equals(value, _storyObjects))
        {
            return;
        }
        _storyObjects = value;
        NotifyOfPropertyChange(() => StoryObjects);
    }
}

public Graphic SelectedStoryObject
{
    get
    {
        return _selectedStoryObject;
    }
    set
    {
        if (Equals(value, _selectedStoryObject))
        {
            return;
        }

        if (_selectedStoryObject != null)
        {
            _selectedStoryObject.Selected = false;
        }

        _selectedStoryObject = value;
        _selectedStoryObject.Selected = true;

        // Zoom to extent
        SetExtent(SelectedStoryObject);

        NotifyOfPropertyChange(() => SelectedStoryObject);
    }
}

SetExtent method smells but works in this case. It creates new Extent from MapPoint and zooms into it.

private void SetExtent(Graphic storyObject)
{
    // This smells. 
    var point = storyObject.Geometry as MapPoint;
    var extent = new Envelope(point.X - 1000, point.Y - 500, point.X + 500, point.Y + 500);

    Extent = extent;
}

Loading content when page gets activated

Like in earlier post, I load content when ViewModel gets activated. First I load selected item from ArcGIS Online by items id. After selected Feature Services ArcGISPortalItem is loaded, I set header text and load all Graphics that are stored in that service I zoom map to the first graphics location.

protected override async void OnActivate()
{
    try
    {
        var item = await _mapStoryService.GetStoryItem(StoryId);

        if (item == null)
        {
            // No public item found
            // TODO handle
        }

        DisplayName = item.Title;

        var results = await _mapStoryService.GetStoryObjects(item.Url + "/0");

        if (results.Features.Count == 0)
        {
            // No items found from the FeatureService
            // TODO handle
        }

        StoryObjects.AddRange(results.Features);
        SelectedStoryObject = StoryObjects[0];

        IsLoading = false;
        SetExtent(_selectedStoryObject);
    }
    catch (Exception exception)
    {
        throw;
    }

    base.OnActivate();
}

DataAccess – MapStoryService

MapTourViewModel uses GetStoryItem and GetStoryObjects methods from MapStoryService.

Loading item by id

Loading specific item or items by ids can be based on ArcGIS Online items id values. In GetStoryItem method, SearchParameters QueryString is set to id:”<id guid>”. This returns list of results with one or zero items.

private const string IdQueryTemplate = "id:\"{0}\"";

public async Task<ArcGISPortalItem> GetStoryItem(string storyItemId)
{
    var parameters =  new SearchParameters { QueryString = string.Format(IdQueryTemplate, storyItemId) };

    var results = await _portal.SearchItemsAsync(parameters);

    if (results.Results.Count() == 1)
    {
        return results.Results.ToList()[0];
    }

    return null;
}

When SearchItemsAsync is executed, following query is sent  to <portal>/sharing/rest/search endpoint.

GET http://www.arcgis.com/sharing/rest/search?q=id%3A%224fcc494b3e654608bea9b373f3159f46%22&f=json

Response is actually pretty much same that when querying groups items in earlier post.

{
   "query":"id:\"4fcc494b3e654608bea9b373f3159f46\"",
   "total":1,
   "start":1,
   "num":10,
   "nextStart":-1,
   "results":[
      {
         "id":"4fcc494b3e654608bea9b373f3159f46",
         "owner":"kajanus_dev",
         "created":1371005929000,
         "modified":1371316795302,
         "guid":null,
         "name":null,
         "title":"Mission Bay Marsh Reserve",
         "type":"Feature Service",
         "typeKeywords":[
            "ArcGIS Server",
            "Data",
            "Feature Access",
            "Feature Service",
            "Service",
            "Hosted Service"
         ],
         "description":"<div>The reserve protects the only remnant of the salt-water marsh that covered much of the bay before Mission Bay Park was created in the 1950s.</div><div><br /></div>Friends of Mission Bay Marshes is a community-based association of concerned citizens established for the purpose of restoring and preserving the indigenous marshes of Mission Bay in San Diego, California and to promote public awareness of, education about, and involvement with those marshes and their flora, fauna, and ecology.",
         "tags":[
            "StoryMaps",
            "ConceptualDemonstration",
            "MapTourSchema"
         ],
         "snippet":"The reserve protects the only remnant of the salt-water marsh that covered much of the bay before Mission Bay Park was created in the 1950s.",
         "thumbnail":"thumbnail/marsh_creek_low_tide_thumbnail.jpg",
         "documentation":null,
         "extent":[
            [
               -117.23246320000015,
               32.7897344
            ],
            [
               -117.22345619999993,
               32.795569500000006
            ]
         ],
         "spatialReference":null,
         "accessInformation":"Roy Little (Friends of Mission Bay Marshes), Isabelle Kay (UCSD Natural Reserve System), Rupert Essinger (Esri)",
         "licenseInfo":"<p style='padding: 0px; font-size: 12px; line-height: 18px; font-family: Verdana, Helvetica, sans-serif; background-color: rgb(255, 255, 255);'>No restrictions. The content of service is collected by Friends of Mission Bay Marshes and the UCSD Natural Reserve System.</p><p style='padding: 0px; font-size: 12px; line-height: 18px; font-family: Verdana, Helvetica, sans-serif; background-color: rgb(255, 255, 255);'>The map features the fantastic photography of Roy Little of Friends of Mission Bay Marshes. The photos are all copyright (c) Roy Little.</p><p style='padding: 0px; font-size: 12px; line-height: 18px; font-family: Verdana, Helvetica, sans-serif; background-color: rgb(255, 255, 255);'>This service is only for demonstration purposes!</p>",
         "culture":"english (united states)",
         "properties":null,
         "url":"http://services.arcgis.com/1be8I8dpkSL373og/arcgis/rest/services/BayMarsh/FeatureServer",
         "access":"public",
         "size":-1,
         "appCategories":[

         ],
         "industries":[

         ],
         "languages":[

         ],
         "largeThumbnail":null,
         "banner":null,
         "screenshots":[

         ],
         "listed":false,
         "numComments":0,
         "numRatings":0,
         "avgRating":0.0,
         "numViews":45
      }
   ]
}

As you can see from the beginning there is only one item found with that Id as expected. If you want to find multiple items which id you know already you can concatenate id:”<idValue>”  parts with OR operation like this:

"id:"<id1>" OR id:"<id2> OR id:"<id3>"

See more about more advanced searching capabilities from here. From this response application is using title and url values. Title is set into header and url contains REST endpoint of the Feature Service that is queried to get story graphics.

Querying features from FeatureLayer

ArcGIS SDK’s provides Task’s that handles a lot of needed scenarios when working directly with rest endpoint. In ArcGIS Runtime SDK for Windows Store these classes are in ESRI.ArcGIS.Runtime.Tasks namespace and in WPF / SL / Windows Phone API’s they are in ESRI.ArcGIS.Client.Tasks namespace.

public async Task<FeatureSet> GetStoryObjects(string url)
{
    var task = new QueryTask(new Uri(url));
    var query = new Query { OutFields = new OutFields { "*" }, ReturnGeometry = true, Where = "1 [equalsmarkhere] 1" };

    var results = await task.ExecuteAsync(query);
    return results.FeatureSet;
}

Using other tasks from SDK’s follows same pattern with QueryTask usage. When QueryTask is initialized, it takes a url to the map service as a constructor parameter and when QueryTask is executed it takes a Query  parameter class in as a parameter. QueryTask constructs the query from the values set to the parameter class and invokes call to rest endpoint. In this case, I use couple good to know values in Query. First I set OutFields property to contain OutFields instance with only ”*” definition. When using “*” all attributes are returned from the service. To optimize your calls, you should ask only Attributes that you need. By default, query doesn’t return geometry of the features so it is set to True. Lastly in Where clause I set query to return all items from the service. Using ”1 [equalsmarkhere] 1“ in where clause is simplest way to select whole content of the layer.

When task is executed following query is sent:

GET http://services.arcgis.com/1be8I8dpkSL373og/arcgis/rest/services/BayMarsh/FeatureServer/0/query?f=json&outFields=%2A&returnGeometry=true&returnZ=false&returnM=false&spatialRel=esriSpatialRelIntersects&where=1%3D1&returnIdsOnly=false&returnCountOnly=false&returnDistinctValues=false

Response is quite long to show here so I left only one feature in it and cut others.

{
"objectIdFieldName":"FID",
   "globalIdFieldName":"",
   "geometryType":"esriGeometryPoint",
   "spatialReference":{
      "wkid":102100,
      "latestWkid":3857
   },
   "fields":[
      {
         "name":"Name",
         "type":"esriFieldTypeString",
         "alias":"Name",
         "sqlType":"sqlTypeNVarchar",
         "length":2147483647,
         "domain":null,
         "defaultValue":null
      },
      {
         "name":"Caption",
         "type":"esriFieldTypeString",
         "alias":"Caption",
         "sqlType":"sqlTypeNVarchar",
         "length":2147483647,
         "domain":null,
         "defaultValue":null
      },
      {
         "name":"Icon_color",
         "type":"esriFieldTypeString",
         "alias":"Icon_color",
         "sqlType":"sqlTypeNVarchar",
         "length":2147483647,
         "domain":null,
         "defaultValue":null
      },
      {
         "name":"Long",
         "type":"esriFieldTypeDouble",
         "alias":"Long",
         "sqlType":"sqlTypeFloat",
         "domain":null,
         "defaultValue":null
      },
      {
         "name":"Lat",
         "type":"esriFieldTypeDouble",
         "alias":"Lat",
         "sqlType":"sqlTypeFloat",
         "domain":null,
         "defaultValue":null
      },
      {
         "name":"URL",
         "type":"esriFieldTypeString",
         "alias":"URL",
         "sqlType":"sqlTypeNVarchar",
         "length":2147483647,
         "domain":null,
         "defaultValue":null
      },
      {
         "name":"Thumb_URL",
         "type":"esriFieldTypeString",
         "alias":"Thumb_URL",
         "sqlType":"sqlTypeNVarchar",
         "length":2147483647,
         "domain":null,
         "defaultValue":null
      },
      {
         "name":"FID",
         "type":"esriFieldTypeInteger",
         "alias":"FID",
         "sqlType":"sqlTypeInteger",
         "domain":null,
         "defaultValue":null
      }
   ],
   "features":[
      {
         "attributes":{
            "Name":"Welcome to the reserve",
            "Caption":"The reserve is managed jointly. The Kendall Frost Mission Bay Reserve is part of the University of California Natural Reserve System (UC NRS) and is managed by the University of California San Diego (UCSD). The adjacent Northern Wildlife Reserve is managed by the City of San Diego.",
            "Icon_color":"R",
            "Long":-117.2296755,
            "Lat":32.7920955,
            "URL":"http://downloads.esri.com/blogs/places/missionbaymarsh/marsh_intro_picture.jpg",
            "Thumb_URL":"http://downloads.esri.com/blogs/places/missionbaymarsh/marsh_intro_picture_thumbnail.jpg",
            "FID":1
         },
         "geometry":{
            "x":-13049947.7825207,
            "y":3867740.5210794583
         }
      },
<snipped>
      }
   ]
}

Response can be cut into three parts: general informatinfield information and features. In general information defines items spatial reference and identification fields. Field information contains list of fields that are got from the service and their description. This information is useful when you want to create dynamical behavior in your app depending what service / features are used. Alias information is also good way to provide users understandable definition of the field. If you are publishing FeatureServices using Esri Maps for Microsoft Office you cannot control aliases or domains (range or code value domains) so if you want to create more sophisticated services, currently you need to create them in ArcMap. Features collection contains Features that drops in given Where clause. Feature contains a geometry since we asked for it and attribute information.

Query results are returned as a QueryResult that contains found features in FeatureSet property. You can access fields and features returned from the service.

Summary

This is it. Now I have gone through the implementation of this application. In this post, there was couple controls using same properties from ViewModel and executed QueryTask to get all Features/Graphics from a FeatureService. This example application is no way near of polished application but I hope that going through it you got some information how you can work with ArcGIS Online, it’s content management capabilities and using that content dynamically from custom client.

0  

Building Map Tour Viewer app for Windows Store with ArcGIS Online – Part 2

ArcGIS Online serie

ArcGIS Online from developers perspective

ArcGIS Online JSON behind WebMap

ArcGIS Online Authentication

How to mashup business data with geometries with FeatureServices

Building Map Tour Viewer app for Windows Store with ArcGIS Online – Part 1

Building Map Tour Viewer app for Windows Store with ArcGIS Online – Part 2

Building Map Tour Viewer app for Windows Store with ArcGIS Online – Part 3

In last post I went through how things are working in the ArcGIS Online and Feature Service side. In this post I concentrate on application story hub page and its implementation. Communication between application and ArcGIS Online is also looked briefly.

Application is build using ArcGIS Runtime SDK for Windows Store 10.2 BetaArcGIS Online (subscription) and Excel with Esri Maps for Office and code is shared in GitHub : https://github.com/anttikajanus/MapTourViewer

The View – MapStoriesView

When application is launched, “Loading content” indicator is shown at the page. This indicator is set to visible when application is loading it’s content from the ArcGIS Online. After All data is loaded, indicator is removed from the view and user can interact with the application. The View contains two sections – Header where the title and subtitle information is shown and a content area where list of story maps are shown. Header contains application title information on the left side and there is a place for a logo on the right side. Application gets its Title and Subtitle information from the ArcGISPortalGroup that is loaded first when the application is started.

<Grid Height="140" HorizontalAlignment="Stretch" Grid.ColumnSpan="2">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"></ColumnDefinition>
        <ColumnDefinition Width="auto"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Grid Margin="120,0,30,10">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="auto" />
        </Grid.RowDefinitions>
        <TextBlock Text="{Binding GroupInfo.Title}" Style="{StaticResource PageHeaderTextStyle}"
                    Margin="0,0,0,0" />
        <TextBlock Text="{Binding GroupInfo.Snippet}" Style="{StaticResource PageSubheaderTextStyle}"
                    Grid.Row="1" Margin="0,5,0,0">
        </TextBlock>
    </Grid>
    <!--<Image Source="Assets/Logo.png" Grid.Column="1" Margin="20"></Image>-->
</Grid>

In the main content area, set of  Stories are shown in  a GridView. Each item shows Title, Thumbnail image, Description, Creator and Created date from individual Feature Service item that are loaded as a ArcGISPortalItems after the group information is loaded. All information is updated in the ArcGIS Online by editing items and changes are reflected into application on every start up.

<GridView ItemsSource="{Binding Stories}" SelectedItem="{Binding SelectedStory, Mode=TwoWay}" Grid.Row="1" Grid.ColumnSpan="2" Margin="40,10,0,10">
    <GridView.ItemTemplate>
        <DataTemplate>
            <Grid Width="597" Height="800">
                <Grid.RowDefinitions>
                    <RowDefinition Height="100" />
                    <RowDefinition Height="auto" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
                <TextBlock Text="{Binding Title}" Style="{StaticResource HeaderTextStyle}"
                            VerticalAlignment="Center" TextWrapping="NoWrap" Margin="5">
                </TextBlock>

                <Grid Grid.Row="1" HorizontalAlignment="Left" Width="597" Height="399">
                    <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}">
                        <Image Source="{Binding ThumbnailUri}" Stretch="UniformToFill" />
                    </Border>
                </Grid>
                <StackPanel Grid.Row="2"
                            Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">
                    <TextBlock
                        Text="{Binding Description, Converter={StaticResource htmlTextConverter}, ConverterParameter=2000}"
                        Foreground="{StaticResource ListViewItemOverlaySecondaryForegroundThemeBrush}"
                        Style="{StaticResource CaptionTextStyle}" TextWrapping="Wrap"
                        Margin="15,0,15,10" />
                    <TextBlock Margin="15,0,15,10" Style="{StaticResource CaptionTextStyle}">
                        <Run Text="Created by : "></Run>
                        <Run Text="{Binding Owner}" Foreground="Gold"></Run>
                        <Run Text=" at "></Run>
                        <Run Text="{Binding CreationDate}" Foreground="DodgerBlue"></Run>
                    </TextBlock>
                </StackPanel>
            </Grid>
        </DataTemplate>
    </GridView.ItemTemplate>
    <GridView.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </GridView.ItemsPanel>
</GridView>

I think that I should mention couple things about the code in here. First is that the Thumbnails in ArcGIS Online is stored as 133 x 199 pixels so I am using that information to scale the image to three times to keep ration same.  Another part is the Description that contains HTML text styling, that you can use when editing field through ArcGIS Online, but here I wanted to rip all styling away so I am using a converter to do that. That converter is some old one that I used in Windows Phone project when showing RSS-feed so it is not written for this but seems to do the job. Here you could take an advantage styling and show description as HTML.

The ViewModel – MapStoriesViewModel

I derive my ViewModels from ScreenViewModelBase that extends Caliburn.Micros Screen class. INotifyPropertyChanged is implemented by the Screen. I have added 2 new general properties for ViewModels: IsLoading and IsContentLoaded. IsLoading is used to give state information and IsContentLoaded is used to define if the content needs to be loaded.

Construction and Dependency Injection

When ViewModel gets constructed, MapStoryService and NavigationService dependencies gets injected by the Caliburn.Micros Inversion of Control functionality that also handles the instance creation. Dependency mapping is done in the app.xam.cs file that you need to implement when using Caliburn.Micro. Read more about application bootstrapping from here. Here is how classes are registered in this application.

protected override void Configure()
{
    _container = new WinRTContainer();
    _container.RegisterWinRTServices();

    // This is main page, use single instance
    _container.Singleton<MapStoriesViewModel>();

    // Create new instance for every MapTour 
    _container.PerRequest<MapTourViewModel>();

    // Create all services as a singletons
    _container.Singleton<MapStoryService>();           
}

NavigationService is Caliburn.Micro’s service so it gets hooked when calling _container.RegisterWinRTServices() method and other classes are implemented in this application. Here is the MapStoriesViewModels constructor where I get needed service instances and those references are stored into private variables for later use.

public MapStoriesViewModel(MapStoryService mapStoryService, INavigationService navigationService)
{
    _mapStoryService = mapStoryService;
    _navigationService = navigationService;
    Stories = new BindableCollection<ArcGISPortalItem>();
    IsLoading = true;
}

Exposing Models from ViewModel

MapStoriesViewModel gives content to View through GroupInfo and Stories properties. These properties get set when the data is asynchronously loaded to them.

public ArcGISPortalGroup GroupInfo
{
    get
    {
        return _groupInfo;
    }
    set
    {
        if (Equals(value, _groupInfo))
        {
            return;
        }
        _groupInfo = value;
        NotifyOfPropertyChange(() => GroupInfo);
    }
}

public BindableCollection<ArcGISPortalItem> Stories
{
    get
    {
        return _stories;
    }
    set
    {
        if (Equals(value, _stories))
        {
            return;
        }
        _stories = value;
        NotifyOfPropertyChange(() => Stories);
    }
}

As you can see, I am using ArcGISPortalItem and ArcGISPortalGroup as Models and exposing those directly from the ViewModel. I think that in this case this is fine but keep in mind that when you are exposing models directly from the ViewModel you lose an abstraction between View and Model that could be considered as violation of MVVM pattern. I could have properties for each property that is needed to being exposed but this way I can get everything to View faster and my ViewModel is not bloated with properties. Anyway, just keep thing in mind and make decision accordingly how to expose information from items to View.

Navigating to selected story

When user selects a story from the list, application moves to another page where the map story data is visualized for the user. NavigateToItem method is called when SelectedStory is changed. It uses Caliburn.Micros NavigationService to move to another page with Id of selected item. I’ll show how this parameter is handled in MapStoryViewModel in next post.

private void NavigateToItem(ArcGISPortalItem itemToNavigate)
{
    _navigationService.UriFor<MapTourViewModel>().WithParam(x => x.StoryId, itemToNavigate.Id).Navigate();
}

Loading content when page gets activated

When the page gets activated it launches OnActivated event in ViewModel. This is default behavior that comes in when using Caliburn.Micro and it’s a good place to start loading content in many cases. Since MapStoriesViewModel is used as a singleton content might be already loaded so first I check that if it needs to be loaded. If it content needs to be loaded I call LoadContent method that contains actual loading. After content is loaded ViewModel is set into loaded state.

protected async override void OnActivate()
{
    if (IsContentLoaded == false)
    {
        await LoadContent();
        IsLoading = false;
        IsContentLoaded = true;
    }
    else
    {
        SelectedStory = null;
    }

    base.OnActivate();
}

Content is loaded by using MapStoryService that abstracts data access from the ViewModel. First group information is fetched from the ArcGIS Online and that, loaded group is used to get all stories.

private async Task LoadContent()
{
    try
    {
        var group = await _mapStoryService.GetGroupInformation();
        if (group == null)
        {
            // Group for application was not found
            // TODO handle
        }

        GroupInfo = group;

        var items = await _mapStoryService.GetStories(group);
        if (items == null)
        {
            // There were no public Feature Services in this group
            // TODO handle
        }

        Stories.AddRange(items);
    }
    catch (Exception exception)
    {
        // TODO handle

        Debug.WriteLine(exception);
        throw;
    }
}

Data access – MapStoryService

MapStoryService contains methods to query ArcGIS Online and getting information from there. It uses ArcGISPortal class to do actual queries and each method creates SearchParameters for that things that are searched. MapStoriesViewModel uses two methods – GetGroupInformation and GetStories.

ArcGISPortal abstracts ArcGIS Portal REST API from the user but it is important to know how things works under the hood. You can find REST API documentation from here where search is defined here.

Searching groups

Searching is based on a query. In query you can define all kind of parameters and options but in this application, I am using simple queries. Read more about construction query from here.

ArcGISPortal class contains SearchGroupsAsync method that takes an SearchParameters instance that defines information what is searched. Here I am just creating a query based on Title and Owner information of the group.

private const string TitleGroupQueryTemplate = "title:\"{0}\" AND owner:\"kajanus_dev\"";

public async Task<ArcGISPortalGroup> GetGroupInformation()
{
    var parameters = new SearchParameters()
                            {
                                QueryString = string.Format(TitleGroupQueryTemplate, "Story Maps")
                            };

    var results = await _portal.SearchGroupsAsync(parameters);
    if (results.Results.Count() == 1)
    {
        return results.Results.ToList()[0];
    }

    return null;
}

After query is executed and results are returned, I return only first item to the application. I have here an assumption that there is only one group defined with name containing “Story Maps” and that is created by me.

When SearchGroupsAsync gets invoked, ArcGISPortal sends a GET to REST API endpoint <portal>/sharing/rest/community/groups.

GET http://www.arcgis.com/sharing/rest/community/groups?q=title%3A%22Story%20Maps%22%20AND%20owner%3A%22kajanus_dev%22&f=json

The response contains query information like used query, total amount of results, start index where results was taken from and number (num) of items that were maximally loaded. This information is used to define if there are more results that might be needed to load and nextStart contains index from where next should be started. If it is -1 then there are no more results to query. Response also contains collection of groups in results.

{
   "query":"title:\"Story Maps\" AND owner:\"kajanus_dev\"",
   "total":1,
   "start":1,
   "num":10,
   "nextStart":-1,
   "results":[
      {
         "id":"bdbbe57e937045b58e8b70e607585b00",
         "title":"Story maps",
         "isInvitationOnly":false,
         "owner":"kajanus_dev",
         "description":"Currently this group is used to share FeatureServices that follows the same schema as Map Tour Story Template. These services are dynamically loaded into the clients and the maps are constructed dynamically by the clients. <div><br /></div><div>This is conceptual demo where ArcGIS Online items, in this case FeatureServices, are shared into clients and the content of the application is changing when changes are done to Group or FeatureServices in the group.</div><div><br /></div><div>Demonstration purposes only!</div>",
         "snippet":"Collection of maps that tells a story.",
         "tags":[
            "StoryMaps",
            "Story",
            "Story Maps",
            "Developer",
            "ConseptualDemo"
         ],
         "phone":null,
         "sortField":"title",
         "sortOrder":"asc",
         "isViewOnly":false,
         "thumbnail":null,
         "created":1371113712000,
         "modified":1371315826000,
         "access":"public"
      }
   ]
}

This response gets parsed by the ArcGISPortal and ArcGISPortalGroup is constructed from it. If you look the response, you can here see HTML in description that I was talking earlier. This behavior is shared with all general fields in ArcGIS Online items. Read more about Group data from here.

Searching items that belongs in certain group

After group is loaded that contains the map stories, groups content is loaded by it’s ID. When Feature Service items where shared with the group, items got marked to belong into that group.

private const string ItemsByGroupIdQueryTemplate = "group:\"{0}\"";

public async Task<List<ArcGISPortalItem>> GetStories(ArcGISPortalGroup group, string sortField = "created")
{
    // Here we could also include type:"Feature Service" definition so filtering would be done in the AGOL
    var itemsParameters = new SearchParameters
    {
        QueryString =
            string.Format(
                ItemsByGroupIdQueryTemplate, group.Id),
        SortField = sortField
    };

    var results = await _portal.SearchItemsAsync(itemsParameters);

    // Filter returned items to contain only FeatureServices. Could be filtered on query too.
    var featureServices = results.Results.Where(x => x.Type == ItemType.FeatureService);
    return featureServices.ToList();
}

In this query, I want to sort results by their creation time that is called “created” items. Actual search is done by ArcGISPortals SearchItemsAsync method that returns a list of ArcGISPortalItems. This application only works with Feature Services so I take only ArcGISPortalItems that are type of FeatureService. 

When SearchItemsAsync gets invoked, search query is sent to <portal>/sharing/rest/search endpoint.

GET http://www.arcgis.com/sharing/rest/search?q=group%3A%22bdbbe57e937045b58e8b70e607585b00%22&sortField=created&sortOrder=asc&f=json

The response is quite long so I only include one item of results. Response is constructed the same as in previous one. It is just returned different object (Item) as a result. Read more about items data and fields from here.

{
   "query":"group:\"bdbbe57e937045b58e8b70e607585b00\"",
   "total":4,
   "start":1,
   "num":10,
   "nextStart":-1,
   "results":[
      {
         "id":"4fcc494b3e654608bea9b373f3159f46",
         "owner":"kajanus_dev",
         "created":1371005929000,
         "modified":1371316795302,
         "guid":null,
         "name":null,
         "title":"Mission Bay Marsh Reserve",
         "type":"Feature Service",
         "typeKeywords":[
            "ArcGIS Server",
            "Data",
            "Feature Access",
            "Feature Service",
            "Service",
            "Hosted Service"
         ],
         "description":"<div>The reserve protects the only remnant of the salt-water marsh that covered much of the bay before Mission Bay Park was created in the 1950s.</div><div><br /></div>Friends of Mission Bay Marshes is a community-based association of concerned citizens established for the purpose of restoring and preserving the indigenous marshes of Mission Bay in San Diego, California and to promote public awareness of, education about, and involvement with those marshes and their flora, fauna, and ecology.",
         "tags":[
            "StoryMaps",
            "ConceptualDemonstration",
            "MapTourSchema"
         ],
         "snippet":"The reserve protects the only remnant of the salt-water marsh that covered much of the bay before Mission Bay Park was created in the 1950s.",
         "thumbnail":"thumbnail/marsh_creek_low_tide_thumbnail.jpg",
         "documentation":null,
         "extent":[
            [
               -117.23246320000015,
               32.7897344
            ],
            [
               -117.22345619999993,
               32.795569500000006
            ]
         ],
         "spatialReference":null,
         "accessInformation":"Roy Little (Friends of Mission Bay Marshes), Isabelle Kay (UCSD Natural Reserve System), Rupert Essinger (Esri)",
         "licenseInfo":"<p style='padding: 0px; font-size: 12px; line-height: 18px; font-family: Verdana, Helvetica, sans-serif; background-color: rgb(255, 255, 255);'>No restrictions. The content of service is collected by Friends of Mission Bay Marshes and the UCSD Natural Reserve System.</p><p style='padding: 0px; font-size: 12px; line-height: 18px; font-family: Verdana, Helvetica, sans-serif; background-color: rgb(255, 255, 255);'>The map features the fantastic photography of Roy Little of Friends of Mission Bay Marshes. The photos are all copyright (c) Roy Little.</p><p style='padding: 0px; font-size: 12px; line-height: 18px; font-family: Verdana, Helvetica, sans-serif; background-color: rgb(255, 255, 255);'>This service is only for demonstration purposes!</p>",
         "culture":"english (united states)",
         "properties":null,
         "url":"http://services.arcgis.com/1be8I8dpkSL373og/arcgis/rest/services/BayMarsh/FeatureServer",
         "access":"public",
         "size":-1,
         "appCategories":[

         ],
         "industries":[

         ],
         "languages":[

         ],
         "largeThumbnail":null,
         "banner":null,
         "screenshots":[

         ],
         "listed":false,
         "numComments":0,
         "numRatings":0,
         "avgRating":0.0,
         "numViews":45
      },
   ]
}

I think that most of the stuff is selfexplaning but lets check how the thumbnail information is used since it is not so clear. Thumbnail information is relative path to the actual image from items uri. For example when image is shown in the View, the image is fetched from http://www.arcgis.com/sharing/rest/content/items/4fcc494b3e654608bea9b373f3159f46/info/thumbnail/marsh_creek_low_tide_thumbnail.jpg. Thumbnail uri is constructed <portal>/sharing/rest/content/items/<id>/<textFromJSON>. 

It seems that there are some new properties in the response that are not used in the SDK at the moment like largerThumbnail that would be interesting from this applications point of view.

Summary

In this post we digged a bit into how searching is done with the ArcGIS Online and how results information can be used to get more related information. Also I went through how the hub page is implemented. In next post I will go into how MapStory part is working and how selected FeatureService gets loaded into the View.

 

2