nasal spray for cough diseases that start with b blue pill l751 what is tl types of colon polyps pictures most expensive prescription drug types of calluses keflex antibiotic price gerd medications otc buy dexedrine spansules online t-37 somethings stuck in my throat how to break your big toe asa 81 mg acido mefenamico 500 mg diluting drug test define intravenous drugs little bruises all over legs feeling itchy all over body constipation blood pressure same supplement side effects relief for bladder infection pain coffin siris syndrome what causes a stye in eye asian ginseng extract benefits iodine side effects bandage for knee signs you need your tonsils out what are tia symptoms chest pain reflux levator anguli oris muscle diabetes and feet swelling vaginal discharge cottage cheese will viagra work frontline plus for cats dosage chart generic name for zoloft allergy medicine for diabetics upset stomach stress and anxiety obesity weight loss pills time to pass kidney stone what is urinary incontinence plaque psoriasis causes pure caffeine powder snort ammonia and bleach symptoms does tylenol help upset stomach how to unpop an ear antacid liquid brands hydrocortisone generic name effects of meth on pregnancy mass on kidney symptoms bleeding during sex iud iud cramping at night lotrisone 1-0.05 cream keratin supplements side effects compounded testosterone cream for women adenovirus type 4 over the counter breathing treatments azithromycin 1 gram best red rice yeast supplement alza 36 mg glass in eye burping after eating anything sinus congestion tooth pain consumer reports fish oil ratings sarcoma in arm natural remedy tooth pain effects of wellbutrin how to recognize bipolar disorder amoxicillin vs z pack tricompartmental degenerative changes citric acid rash penis yeast infection treatment m purple pill treatments for edema in legs how to use a tanpon pneumovax side effects friction burn blister cough and sore throat during pregnancy what is septic in medical terms lambert kay fresh and clean how to treat constipation in toddlers clear liquid draining from ear what is adderral pseudobulbar affect causes pain below belly button male lisinopril joint pain stomach polyps cancer thallium stress test definition ankle swelling with rash vancomycin resistant enterococcus pepcid dosage for dogs calcium tablets costco how to help meth addict ace knee bandage anxiety and agitation medications for bladder spasms severe asthma attack breastfeeding and beer coumadin mechanism of action antidepressants and menstrual cycle progestin hormone side effects how to treat panic attacks naturally causes for nose bleed medications for hiccups takes affect or takes effect what shape is a d20 domperidone and breastfeeding infection of the fallopian tubes preparation h totables cream depo wearing off symptoms fish tapeworm treatment hctz 25 mg tab opti free refresh tylenol pm ingredients signs of mrsa tramadol extended release is horse chestnut a nut how many ambien can kill you abuse deterrent oxycodone side effects of malaria pills baby aspirin dogs mental side effects of suboxone what is the sodium squamous cell lung cancer blood spots on arms in elderly alcoholic gastritis symptoms nitroglycerin for anal fissure becker muscular dystrophy bmd oxycodone active ingredients how to take orlistat ginger and breastfeeding treatment for heart disease gard dog storage casual smoker drug test hydrochlorothiazide 50 mg tab over the counter medication for depression common medicine side effects head spinning causes side effects allopurinol gtf chromium side effects does codeine make you sleepy acetonide cream uses adrenergic blocking agents small blood blisters on skin mirena removal symptoms best pills for losing weight paragard side effects hair loss what does testicular cancer look like saline solution for nose infection on toe pus infection videos how to tell appendicitis from gas frequent bacterial infections acorda therapeutics careers how to avoid constipation signs of lead in water bupropion hcl 75 mg weight loss cortizone injection knee how does the polio vaccine work dorzolamide/timolol cirrhosis of the liver stage 1 wrist pain bandage posh 21 cosmetics cracking in corner of mouth cyzmic cs insecticide miralax pediatric dose function of sweat glands tinea versicolor treatment cream sore throat syrup prednisolone oral solution broad ligament definition elbow gout symptoms iv pyelogram prep bronchiolitis symptoms in babies flu vaccines names gas medicine for baby prolapsed uterus and sex otc opiate withdrawal flash burn definition kidney failure and anemia prostate medicine finasteride how much alcohol liver damage causes of stys pot chloride 10meq er precum on finger pregnancy potassium in ginger what is stromectol minoxidil shampoo side effects treatment for allergic reaction clotrimazole jock itch big belly buttons weight gain ovarian cancer 4 acetic acid definition of annealed benefits from pineapple best retin a cream for wrinkles dipyridamole brand name bipolar disorder lamictal tedizolid vs linezolid aspirin chest pain chemical formula for thc mirena cramping after insertion how to cure urticaria baby blue eyes country song 115 blood sugar level fasting asherman syndrome mayo clinic what does omnicef treat flu shot and nursing non prescription doxycycline are muscle twitches normal opiate based painkillers insulin like growth hormone tramadol no prescription leading weight loss supplements slight burning when i pee color pink pictures long term pepto bismol use my panties are so wet trifamox ibl duo dark blood after period lump in throat symptoms definition of cavernous virbac c.e.t. enzymatic toothpaste lipitor and blood pressure selegiline brand name hipotiroidismo y embarazo before after puberty blood sugar 129 treatment for acute lymphocytic leukemia healing a cut fast zyprexa for migraines cyproterone acetate and ethinyl estradiol what does mittelschmerz feel like restless sleep cures intense itching on arms prescription drug finder sublingual migraine medication signs of a broken bone 25/45 saint johns wort tea posterior ethmoidal nerve beta blocker migraine prophylaxis watson laboratories inc viagra and blood pressure hair growth on breast hytrin 5 mg septiderm-v skin care bath c disc colitis natural treatment for gas natural desiccated thyroid supplement what causes whiteheads on forehead is bactrim good for sinus infection peg 8 distearate passing a kidney stone quickly 200 mg lyrica cutaneous porphyria pictures mucus poop in adults do onions give you gas abdominal and stomach pain excedrin menstrual complete bph treatment medications pepto bismol causes black stools what can cause hoarseness despues de cirugia de vesicula side effects of zantac 150 how is h pylori diagnosed clonidine dosing for opiate withdrawal how long does imodium last gel for arthritis is broncitis contageous what is humulin r stages of liver cancer extravasation of dopamine cracked rib healing time xarelto or warfarin pituitary gland and depression can you smoke percocet causes of avascular necrosis are vitamins drugs what is arterial sclerosis smoking catnip effects tapering off mirtazapine zoloft 50 milligrams pepcid ac alcohol how many vertebrae in neck levothyroxine brand names poop looks black oxazepam side effects what is nitrofurantoin mono acd a anticoagulant effects of snorting ritalin untreated strep throat can lead to nasal spray cvs treat common cold prevent thinning hair female what are poppy seeds good for one minute cure hydrogen peroxide therapy steroids and birth defects kegel exercises for men ester c vitamins definition of cleaver acid that burns skin night time enuresis burning diarrhea remedies swollen face pregnancy beta blockers withdrawal singulair side effects anxiety what is in miralax ultram pain pill signs and symptoms of hemorrhoids allergic to flaxseed azo active ingredients hctz sulfa allergy allegra while pregnant how do i enlarge my penis types of insulin onset peak duration biotene for cats antibiotic ear drops otc acid reflux vomiting bile left arm tingling how long does strep last my diarrhea is black reasons for sleeplessness what does adrenaline mean symptoms tired nausea is ritalin a narcotic neurontin for shingles nerve pain 80/25 oriental massage definition shoulder pain when moving non-opiate pain killers what is a mao inhibitor what is duche can you get high off mirtazapine repel natural insect repellent glipizide vs metformin burn healing stages methadone clinic cost chronic diarrhea and weight gain dr bennett tulsa hair loss from steroids latex glove allergy over the counter medication for diabetes maxivision eye formula arteriovenous fistula surgery types of ringworm bronchitis early symptoms my eyes have trouble focusing extremely heavy menstrual flow navel piercing infection treatment pink color pictures symptoms when you stop drinking alcohol shingles on genitals negative effects of kratom caffeine use during pregnancy treatment of ulcers in stomach twisted colon pictures anti inflammatory oils does spironolactone cause weight gain plan b weight gain depo shot calendar 2016 n s1 white pill antibiotics for gallbladder chemical formula for magnesium hydroxide facts about barium pins and needles twitch mirena and hair growth congestive heart failure pain pantoprazole side effect lipitor withdrawal mayo clinic headache pressure behind eyes bad migraine and nausea loratadine expiration date testosterone vs estradiol ritalin la vs ritalin sr can you snort percocet best medication for add does nexium make you gain weight best otc for diarrhea potassium 20 meq tablets resection medical definition what does 43 mean when exactly did i get pregnant packing a boil progesterone emotional side effects otiflox ear drops new skin ingredients eye pain pressure green tea weight loss pills is cipro a sulfa drug primary stage syphilis low concentrated sweets diet how strong is norco stitches or sutures p&s solution how many ml in mg can allergies lead to sinus infection spine out of place symptoms of stopping cymbalta side affects of crestor is mucinex dm safe during pregnancy what is diphenhydramine used for first-pass metabolism what has dxm in it one small testicle antidepressants that cause tinnitus teaspoon equals ml hikma pharmaceuticals headquarters carbon monoxide gas stove yellow pill with m and 751 sentinel® spectrum why take a diuretic pee clean in a week ah chew sneeze hemroid symptoms and signs otc reflux medicine fibula pain above ankle can a drug test detect alcohol cancer lumps on neck baby orajel teething swabs side leg pain daily jocks coupon elf acne fighting foundation plan b stomach pains medical term for npo dobutamine blood pressure viral meningitis toddler define steady state baby throwing up everything vitamin d 500 carbohydrate content of medications tylenol dosage chart for adults what is asthma getting high on dayquil allergy medicine types scabies in head scalp treatment for mononucleosis in adults colace during pregnancy side effects of pentamidine best rx online pharmacy gaviscon for nausea does gel make you bald taking abilify while pregnant liquid diet drinks anesthesia drug doses swollen inner gums dark loose stool naproxen sodium 550 mg side effects pus pockets in throat not strep best weight loss pills for women melatonin and ssri medicine for brain tumor garlic gel capsules how to apply ointment to eye why is my cum yellow first aid ointment people on pcp beta adrenergic blocking agents 5 times 4 can you smoke morphine 30 mg space adaptation syndrome high blood sugar symptoms type 2 best way to treat blisters does walmart sell poppy seeds muscle origin definition gabapentin 600mg tablets how is shingles treated hirsutism in males how to get over bronchitis fast umbilical cord odor side effects of desyrel codeine over the counter canada can beets discolor your urine advair hfa coupon std of mouth 5 day z pack treatment for head concussion facial fractures pictures meniere disease symptoms reasons for swollen feet and legs lovaza vs fish oil prilosec drug test excruciating pain in shoulder propecia fda warning treatment chronic bronchitis pristiq for hot flashes can i take pepcid with prilosec what is cosentyx what is taking an l sores on hairline nursing drug reference book continuous bleeding from anus treating athletes foot med for scabies sanofi aventis patient assistance program benzoyl peroxide allergic reaction treatment generic zoloft cost depakote side effect signs you have parasites my daughters closet

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