00:01Welcome to the Advanced Development for the ArcGIS API for Silverlight.
00:05Nice and early morning just to get started with some good details, some dive in deep into the API.
00:10My name is Rex Hansen, product lead for Microsoft clients at Esri.
00:15I'm joined by Morten Nielsen, lead dev. for Silverlight, and Jennifer Nery, rock star developer for Silverlight as well.
00:23So hopefully, we're going to be taking you through a variety of demos, diving deep into some code...
00:27...and some different functionality patterns and practices that you can derive some information from that you can then use...
00:34...take with you and then put into your Silverlight applications and make them shine, make them work really well.
00:41So we've got an agenda here of a couple of demos that we're going to walk through.
00:45We're going to start with graphics data sources and take a look at some of the new functionality that's in...
00:49...that was initially in 2.4, and we have it in 3.0 as well, and how you can leverage that in your applications.
00:55We're going to dive into printing. Jennifer's going to discuss printing.
00:58And then we're going to deep dive into the image service plenary demo...
01:01...so the demo that we saw during the plenary that I demonstrated, Morten Nielsen wrote...
01:06...and so he's going to walk through some of the techniques that he used to make things work in that application...
01:12...and really show some of the benefits of using Silverlight.
01:15And then, last, we're going to wrap up with a feature service editor tracking demo and talk about...
01:19...some of the new functionality in 10.1 and how you can leverage that in the API more effectively.
01:24So let's go ahead and get started. I'm going to push it over to Morten, and he's going to talk about graphics data sources.
01:31Thanks, Rex. Alright, I need my feed here. Let's do that. No? Come on. There we go. Yes.
01:45So I'm going to talk a little about how you can work with data you have either from...
01:51...it comes from some of the data you build from a custom service or from a local file and so on...
01:56...how you get that easily in to [unintelligible] on your map.
02:00And today, often the way you do that is if you have a bunch of graphics, you go through each of them...
02:05...and then you just add them to the layer one by one. And it's a kind of tedious line of code.
02:10You could now with our GraphicsSource and the new properties added in 2.3, you can simply just do this.
02:18So that's a little simpler, very short way, and now you actually get the myGraphics...
02:23...the graphics layer's just pulling data straight from this object.
02:27This object can be any type of collection of graphics, so it can be an array, it can be an observable collection...
02:33...it could be a list or any custom implementation of IEnumerable.
02:38In addition to that, if it implements the interface called INotifyCollectionChanged, which you add or remove graphics to it...
02:45...the graphics layer automatically detects that, so if you use observable collections, for instance...
02:48...that automatically is handled for you.
02:52The thing that's very important to note, that when you use GraphicsSource...
02:55...you cannot edit the graphics collection directly on the graphics layer; it's a read-only collection.
02:59This is very similar to, if anyone's done, for instance, a combo box in Silverlight...
03:04...you have an Items property you can add items to, or you can set the ItemsSource.
03:07The moment you set the ItemsSource, you can't change the items anymore; you modify your source data instead.
03:13This ties really well into, for instance, MVVM style programming where you get your data...
03:17...your binding in from somewhere else and you modify it. Your view model modifies that data directly.
03:24So let's try and just quickly do this, get started with this.
03:27So I have a little app here...let me zoom in a little bit.
03:35So basically I have an observable collection in this case of graphics...
03:39...and when my app starts up, I'm just going to create a bunch of new graphics, and I have this little helper method...
03:43...just creates a hundred random graphics.
03:46These could be coming from some service you downloaded or some of the data you load from a local file or something like that.
03:53And then, set the GraphicsSource here.
03:57Also have a little button I can click, and when I click it, I'll just - for each of those graphics...
04:00...I'll just add it to the graphics collection.
04:02So I don't have to touch the layer at all at this point.
04:04The moment the graphics source is hooked up to my layer, adding and removing graphics to my original source...
04:10...automatically populates the graphics layer too.
04:15So hopefully if it starts up here, I'll have about a hundred random points.
04:20If I click my button, I get a hundred more and keep adding like that.
04:23So the graphics layer automatically checks that original source the data is coming from...
04:26...has been modified and automatically adds these.
04:29It's kind of trivial. I could just have added these to the graphics layer instead, of course.
04:33So why is this actually really useful?
04:35Well, I come back to the whole if you implement an IEnumerable of graphic custom class...
04:40...you can actually do a little more fancy stuff.
04:43And so go to a little more real-world scenario, what if you have something like this?
04:52You also sometimes have some kind of class; it might have some kind of spatial component to it.
04:57It could be an address that you can geocode on the fly or something like this.
05:01In this case, just a longitude-latitude.
05:03And I want to add this data to my map.
05:06So the way you probably will do this today is you will just go through each of these data objects...
05:12...and you'll create a new graphic and then assign the map point and then add them to the graphics layer.
05:17But there's actually a lot easier way. You don't have to write any code to do this.
05:23So let's try and do that. I'm just going to grab a little snippet here.
05:31And so I have a little model here, my PointItem, and this is just a simple little object that has, in this case, just an integer ID...
05:39...it could be a name or something like that...but I also have a longitude and a latitude column.
05:45So this is a typical model you often see.
05:48Similar, I also have a view model from our main page, and here I have...
05:56...most importantly, I have a set of items on here that is a collection of point items.
06:03And I have two commands that add some random points to it...
06:06...and I have a command that moves or updates some of them on the fly.
06:11And I have tied this in to my map, so I had defined in my map over here, I defined my view model as a resource.
06:18So it's defined up here. And I have my DataContext set as well on my entire page.
06:24So the DataContext is the view model of this page.
06:30So let's try and get this into my layer.
06:32So I'm going to add a new layer here, and I'm defining a graphic source right here instead of doing it in code behind.
06:40And out of the box, we come with this data source called a PointDataSource.
06:45And in this case, I'm telling it where can I get my longitude and where can I get my latitude from?
06:51So I basically just tell it, hey, the x-coordinate binding, just do a binding to the longitude column...
06:56...and the y-coordinate go to the latitude.
06:59And by default, the PointDataSource assumes that your data is in longitude-latitude, WGS84 and...
07:06...well, if you, for instance, have a replicator map, it'll autoproject with that...
07:10...because we have autoprojection in for some of the standard projections like this.
07:14And lastly, I'm setting that the ItemsSource, in this case are more items...
07:18...so I'm grabbing my view model and the Items property on this.
07:24I also had a couple of commands in my view model.
07:29I had a command that adds random items, so I just add this command.
07:31How many is familiar with doing commands and buttons? A few.
07:36So this is, instead of having, like, do a click handle and go into code behind, you can actually have like a method to execute.
07:44And you can also say if this method actually can be executed.
07:48So a nice thing about the button, if the method can be executed, the button automatically disables.
07:53So for instance, you'll notice when I run this that when I don't have any points in there, the Move command disables.
07:58So the button, I can't move any features 'cause there's nothing to move.
08:01The moment I add features, it enables.
08:03So I don't have to write any code behind to actually hook these buttons up to my view model.
08:10Let's try and run this little sample.
08:16So here's my two new buttons. You see the Move points is disabled; the moment I click Add random...
08:20...you see some random points change. Click again, I can move some of them, and again, it automatically takes...
08:26All the Move button does is change the longitude and latitude columns.
08:29The PointItem is basing...raising PropertyChanged events on them, so the PointDataSource...
08:35...automatically takes this and updates the graphics that are being rendered in the graphics layer.
08:40And this is without writing any code. It's all binding into my view models.
08:49Alright. You could also take this data and maybe put it in a data grid.
08:57So I'm just going to throw a little data grid in here.
08:59And again, I'm just grabbing the items in my data grid and putting my data grid at the bottom.
09:07Run the sample again, and now we should hopefully see...when I add buttons, I see all my points down here.
09:15And if I actually go here in the data grid and start entering...let's say this is, let's just put this to Redlands...
09:21...you'll see the little point there actually moves instantly. Okay? And I didn't write any extra code.
09:25The data grid just updates the model; the PointDataSource detects that the model changed and updates the graphics.
09:34There's a really neat little way to work with data when you don't necessarily work with Esri graphics...
09:40...but have other data coming from elsewhere.
09:42For instance, you go on the OData marketplace, there you can download a class...
09:48..that automatically downloads and fetches data for you and then gives you a model like this...
09:53...and you can just straight bind that into your geomap.
10:00Alright. So I mentioned we have this PointDataSource that implements our new envelope graphics...
10:06...but you can also build your own.
10:08And I happen to have this little file out here on my desktop, little CSV file - you've probably seen these quite a lot of time before.
10:16So it's just some IDs and some coordinates for some points.
10:19So how would I take this and put it on my map?
10:25Well, I could of course parse this file and create all these point items and then use the PointDataSource for this...
10:33...but I could also make a data source that just directly works with CSV files.
10:43So I did that. I have a little data source here.
10:51So you notice I implement IEnumerable of Graphic, so this is required to be able to set a GraphicsSource.
10:57I also implement the INotifyCollectionChanged, so if I add or remove graphics, I can let the graphics layer know that...
11:05...hey, I've got more graphics or I removed some graphics or I reordered them or something like that.
11:13So what does it really do?
11:14Like I have a little parse method that takes a stream; in this case, it's usually a file stream to my CSV file.
11:19It really just...first, reads the first line, grabs all the header names.
11:25I had a little utility method here that basically just reads the separator and gives me an array back of string values...
11:32...and then creates a graphic based on that, based on all the attributes that get added.
11:36And I have a little AssignGeometry...let's go to this one...that checks...
11:41...hey, if I have a longitudeColumn and a latitudeColumn, read these and assign a geometry.
11:46So the DataSource kind of just knows how to handle CSV files.
11:51And when I'm done, I'm just raising a CollectionChanged, hey, this whole collection changed; you need to update.
11:59Alright. So let's try and put this into our little page here.
12:08So I have my original graphics layer. I'm just going to add a data source.
12:13GraphicsSource, local[colon]CsvDataSource. This quickly should go away when I build.
12:20And all I have to do, code. Let's get rid of the original one so I don't overwrite this thing.
12:29And lastly, I need to open my CSV file.
12:31In Silverlight, you can't just open a file on the person's hard drive; you actually have to prompt the user.
12:39Imagine going to a website and people start reading all your files.
12:42So I had a little button here for opening up a button - or opening up a file dialog for the user to browse to a file.
12:49So let's look at when I click this, uncomment this.
12:59So I've created an Open File dialog, and if the user actually picked a value, or picked a file...
13:06...I'll grab my layer, and the GraphicsSource on that layer and just parse in the file stream for it.
13:22So let's load CSV, pick my sample data, and boom, I've got the points on here. Cool.
13:34Has anyone worked with Google Fusion tables? A couple.
13:40Google Fusion, actually it's really just a query you do in your URL for, like - kind of like a SQL query...
13:45...and you get back a CSV file, which is kind of what I just built.
13:50So I figured why not just extend this a little bit.
13:55So all I did to do that, I inherited from my original CSV data source, because it already has the code for reading CSV...
14:05...and I added a new query property, like what does the query actually want to do for getting data from a service?
14:12And when that query changes, I'll call refresh, which basically just says a new web client...
14:18...and when it gets downloads of data, it just calls the parse method with the stream that I get from the web request.
14:23So instead of loading a local file, I'm doing a web request, getting that data.
14:31And the only thing I did, the geometry in Google Fusion is slightly different...
14:37...so it actually has a geometry field that's kind of XML formatted, KML-like format.
14:42And I just did a quick little dirty implementation here...
14:44...like, hey, if it starts with this, it's probably a point, and it just kind of crudely graphs this.
14:49This could, of course, be extended a lot more to support more of the KML features.
14:57So let me just grab such an example.
15:04And add that here. Again, it's just a graphics layer - oh - and we have a GraphicsSource...
15:14...and in this case, I just put in the Google Fusion data source, and here's my query - "select everything from this table."
15:21So all the tables have, like, these funky numbers. And I could add a WHERE clause to this, of course, too.
15:27And again, in this case, I just assign a simple renderer to it.
15:33So let's see if that works. Wait a little bit, and there we go.
15:44So instantly, a little data source that knows how to work with Google Fusion tables.
15:48And you can imagine how you can extend this with other types of data sources, like an OData data source...
15:52...or your own web service, WCS service or something like that, that pulls in data and then just assign it straight to the DataSource.
16:00That way you don't have to do all the code on the client side to do all these conversions.
16:05It just happens straight through that DataSource.
16:07You get a nice, really, abstraction of your logic.
16:13Alright. So just really quickly to reiterate, the PointDataSource is out of the box, it'll automatically convert...
16:22...data with a longitude and latitude into graphics, and this is basically it.
16:27There's also a Selected binding that you can add, so if you set the...
16:34...if you have like...you select something on your data grid, you can actually have that be the Selected property...
16:40...then that makes it highlight on your map, and then you can also bind that in.
16:43So the graphic state will move to selected the moment you select something through your view model from the individual items.
16:52I already did that. And that's what a DataSource is.
16:57I think it's an awesome little thing to do to quickly...to do some MVVM style programming.
17:04And now actually when I come back a little later...
17:06...I'll show some other stuff where I actually use DataSource that's under the covers too.
17:10So alright. Printing. Jennifer.
17:16Thanks, Morten. Hopefully, we got you excited with the new print task.
17:23So here I will show you an example of a map that we can interact with.
17:28We can change the map's time extent to show more features...
17:33...and we can also select to highlight some features from our feature layer.
17:39And we can also add some notes using our graphics layer to add features, and now we are ready to print.
17:49So let's select our desired template - we have a choice list - and let's also select format...
17:56...and maybe update our title to be this and hit Export Map.
18:02That will send a request to the server.
18:05And as you can see, you have an output file that has the same state as your client map.
18:13What you have here is some title, the map that we were printing at a particular extent...
18:19...and we also have some legend here that shows service renderer legend and some scale bar.
18:28Now if we wanted to update the legend to...let's move this here.
18:36If we replaced the renderer with our class breaks renderer on the client side...
18:41...as you can see, the class breaks is based on population in 2007, and we have some symbols and labels in our legend control.
18:51So we should expect the same legend to be printed.
18:56So let's fire off another request for print.
19:01And as you can see here, the legend control updated the symbols and labels which we had on the client.
19:09So how do you create such an application? It's supposed to be easy.
19:14The Silverlight API made that easy for you.
19:17So you create a Silverlight 5 application.
19:20At minimum, you will add reference to two assemblies, ArcGIS.Client and ArcGIS.Client.Printing.
19:34So let's add a XAML name space reference to esri attribute, and let's also add in our map.
19:48In this map, we have a base layer, which points to a street map...
19:53...and we also have a feature layer that points to San Francisco 311 data.
20:01Now let's add a button, which will be placed at the top center of our application, and let's have a click event and implement that.
20:16In our click event, we will call the basic print by first resolving this error.
20:25Print task comes from a new name space, so we'll resolve by adding a using statement.
20:31And as far as the URL, we will go to the REST end point.
20:36In the services directory, you will find Utilities folder.
20:40Under this folder, if you have enabled printing tools, you will find a GP server here.
20:47And we'll just copy the task URL and plug that into our code.
20:55We'll have an ExecuteCompleted event, which will fire when we execute the print task...
21:00...so let's implement that ExecuteCompleted event.
21:05And in this event handler, we want to navigate to a new HTML page...
21:16...and the URL that we use for that will be coming from e.PrintResult.url.
21:27Now this event won't trigger until we call ExecuteAsync.
21:31And over here, we will be sending just the default parameters, newPrintParameters...
21:38...and this parameter takes in either a map or a layer collection with some extent.
21:47In this case, we want to pass in MyMap.
21:52And let's run that application.
22:07Now you see here that our map is at a specific extent, and we are showing some features.
22:13By the click of a button, we can get an output file that will be the same state as our map.
22:20By default, it is a map-only template in PNG format. These are the service defaults.
22:28So if you go back to the REST end point, you will see here that Format and Layout_Template have predefined choice lists.
22:36So how do we put that in our application?
22:40Let's go back to our XAML and replace our button with more user controls like combo boxes and text box.
22:51So let me delete that - oh, we're still running.
22:58So I'll delete the button that we had earlier and replace that with a print panel.
23:05In this print panel, we have some combo boxes that will show our layout templates and formats...
23:12...and we'll also have a text box for map title.
23:17But to get information on layout templates, we will set the ItemsSource to a binding statement...
23:24...that will be pointing to LayoutTemplates.
23:28Our formats - similarly, our Formats combo box will have an ItemsSource, and we'll just set that ItemsSource to Formats.
23:38And this click event for print will use the same click event that we have in our code, so I'll just put Button_Click.
23:49I've named this grid PrintPanel, so let's go back to the code and move...
23:57...let's create the instance of printTask ahead of time so that before we even click the event...
24:03...we are able to gather the choice list from the server. So I'll be moving this code right after InitializeComponent.
24:17And let's add a private print task, which will be a member of our class.
24:26And also, the next event that we will be subscribing to is GetServiceInfoCompleted event.
24:41So let's add an event handler. In this event handler, we want to set the data context of our panel.
24:50So we have named it PrintPanel; we just set DataContext to e.ServiceInfo.
24:56So if we inspect what it has, e.ServiceInfo has formats, layout templates...
25:03...and you'll also be able to know if service operation is synchronous or asynchronous.
25:10So let's just set that DataContext.
25:14Now that we have our choice list populated, we want to make use of the selected items from our combo box...
25:21...so in our click event, we'll update with some print parameters.
25:28Again, we create an instance of PrintParameters.
25:31We'll have a chance to update our layout template using LayoutTemplates.SelectedItem.
25:38Same is true with formats; we'll have a chance to update our format.
25:44Also we want to get some title information there.
25:47Since we had a Map Title text box, we'll just add some layout options to our print parameters.
25:55As you can see here, Title is pointing to MapTitle.
25:58In addition to that, we have some author text, copyright, and some scale bar options if you wanted to change that.
26:10Let's also try to pull some legend information.
26:13Over here, I left LayerId to be blank, but this should match the ID of the layer that you wanted to show.
26:21So let's go back to XAML and choose our feature layer's ID.
26:26So I'll just copy that and plug that into our code.
26:31Once we have populated this PrintParameters with our desired inputs, we will now replace this code with our PrintParameters.
26:43So I think we're ready. So we have that GetServiceInfoCompleted to get information from the server.
26:51We are setting the print panel data context, and our click event has been updated to take in these new parameters.
26:59So let's start that application.
27:05And now we have this choice list, we can select our desired layout template and our desired output...
27:13...and we can even update our title and send another request to the server to generate the output file.
27:21And there you go. You have the same map with some legend information, some scale bar information, and some title.
27:31Now let's go to the slide.
27:36So from what I've shown you earlier, just to reiterate the code that we have...
27:41...we have a new name space called EsriArcGIS.Client.Printing.
27:48In this assembly, we have a print task where we pass in a task URL.
27:53There is also a property URL that you can change outside the constructor.
28:00You will also have an event called ExecuteCompleted wherein you navigate to a new page and have it point to the printResult URL.
28:11To trigger this event, you call ExecuteAsync.
28:15You can also pass in a newPrintParameters wherein you have your map control pass in in that constructor.
28:24By default, this will generate map options for you, such as the scale of the map, the time extent of the map...
28:32...or rotation of the map if you have provided that.
28:39Or if you have changed your GP server to an asynchronous type of operation on the server, you will have two events to listen for.
28:49Instead of ExecuteCompleted, you will have StatusUpdated or JobCompleted events.
28:55And to trigger these events, you have SubmitJob.
29:01Earlier we have also seen that if we have a series of combo boxes, like couple of combo boxes...
29:08...we can update their ItemsSource using LayoutTemplates and Formats.
29:14We can also have a Map Title field, or if you wanted to show copyright or author text.
29:22Now, since we have named our stack panel PrintPanel, we can set this DataContext to be e.ServiceInfo...
29:30...so that the binding statements will be resolved, and to trigger this event, we call GetServiceInfoAsync.
29:39To make use of the selected items, we have used PrintParameters and set the layout templates and format.
29:48You will also have a chance to update the title and some legend options.
29:54Again, as I have mentioned earlier, you have some scale bar options...
29:57...where you might want to change the label or the default kilometers and meters. You can change the units.
30:08And you are able to overwrite whatever map options you have.
30:14By default, this will take the map properties, but if you wanted to change scale or rotation or time options...
30:22...you will be able to change that.
30:24And ExportOptions is what you will use if you wanted to change output size or maybe the dpi...
30:33...and you just pass that in to your ExecuteAsync or SubmitJob.
30:38So what are the supported features in printTask?
30:42As I have mentioned earlier, you will get a chance to get a choice list from your server and even know the type...
30:50...so that you will know what events to listen for.
30:53We support both synchronous and asynchronous type, and since it's a GP server, you will be able to cancel the job...
31:01...cancel the print job.
31:04And also you will have the chance to have these options - snap and export and layout options.
31:12The 10.1 capabilities that you have probably seen shown in the plenary, where we have dynamic layers...
31:20...dynamic source, GDB version, these are all supported in printing.
31:25If you have wraparound and you have switched to a different world frame, you should be able to print this.
31:32And if you have token secured services, this is also supported.
31:38So the supported layers. From the client assembly, you have the following.
31:43You have Bing tile layer, and from DataSources, you have KML, WMS, WMTS, and OpenStreetMap layers.
31:51Also, if you have web maps that have these types of layers, you can print them.
31:57What are the known limitations for print task?
32:01In 10.1 prerelease, if you are using temporal renderer...
32:05...temporal renderer will work on other layout options other than MAP_ONLY, but in final, this will be fixed.
32:13Also if you have graphics layer or you have a web map with feature collection...
32:19...your graphics need to have at least one attribute, but this will be fixed in final.
32:26Also you have...if you have custom symbols or renderers, these are not supported unless you implement IJsonSerializable...
32:36...and downgrade your symbols to symbols that the REST API supports.
32:41Also, if you have clustering, the clustering won't be applied; only the renderer will be applied.
32:49And as far as KML layer, if you have made some folders not visible, this is not supported yet by the server.
33:00And if you have graphics layer with mixed geometries, the API would advise you to move them to different graphics layers.
33:11And if you have some selection on your features that you have seen earlier...
33:16...or say you have set the geometry property of your feature layer, we require that you include ObjectID in your out fields.
33:34There is another related session that you might be interested to attend this afternoon.
33:39It will be by Craig and Tanu. The time is at one thirty and two forty-five p.m.
33:48In this session, they will help you generate or create or customize your GP server for more printing...
33:56...maybe add layout templates, so it will be good to attend this session.
34:01So up next, I'll switch you back to Morten for some Image Editor sample.
34:07Thanks, Jennifer. So anyone can use this print service? Anyone needs print? Ever?
34:15It's funny. We never heard about that before.
34:21Alright. Yeah, so Rex probably...if you remember, he demoed this Image Editor sample in the plenary...
34:29...and I'd like to kind of dive in to some of the things that went into building that.
34:32And I'm not so much focusing on the image service part of it but more some of the techniques that he used to build that app.
34:40I'm going to just quickly show you the app in case you weren't paying attention.
34:44Of course you were, right? But...
34:49Right, right, yeah. So one of the first things you had to do, you had to upload an image.
34:54And especially with image services, these images can get quite large, hundreds and hundreds of megabytes or even gigabytes...
35:04...and during a post request for adding an image can easily time out or it can easily fail.
35:13And so what we added in 10.1 is this new Upload Item onto ArcGIS Server.
35:18And what it allows you to do is to upload data first to the server to use as input for, for instance, Image Server...
35:23...or if you use as inputs into a GP - let's say you want to upload a whole geodatabase for the GP tool to use...
35:29...it becomes very complex parameters, but you can actually upload these as files or like shapefiles, which are multiple files.
35:37So we have a new upload task for that, and I'm just going to upload an image here...
35:41...and what's actually going to happen now is, because this is a fairly large file, it's actually chunking it up in multiple parts.
35:47In this case, I set its value low, to 2 megabytes.
35:50Depending on your network and your scenario, you might want to make that, the chunks, larger.
35:57But it splits it up in multiple uploads.
36:00[Inaudible audience question]
36:05Let me just redo that.
36:13Here we go. [Inaudible comment] Yeah.
36:19You just have some vision then.
36:21Anyway, let me try that again. I'm going to click the Browse button, and I'm going to pick a fairly large TIFF file...
36:27...and I'll be uploading this file to the server.
36:30And it will be splitting up in multiple files, and you get some progress events, and if my network will work...
36:38Boom, boom, boom. I'm running on the same Wi-Fi as you are...
36:42...so if you're downloading something really big right now, this is the reason.
36:46I couldn't get the - we have, like, a network here, and it doesn't work. I don't know why.
36:51And it's almost there. So just use the upload task, splits it up in multiple smaller uploads and then, when it's done...
36:59...it actually, on the server, it does a commit under the covers that joins it back into one big file and you get an ID back.
37:06And all this happens for you. It's a really simple little file to use. You can also delete it again if you wanted to.
37:12The upload task provides that for you.
37:16So let me just quickly show what that looks like.
37:19So I have the Open File dialog here, and that's the same thing - I can't just open a file.
37:23I have to have someone to pick a file for me.
37:27And in this case, I'm passing in the URL to my image server, so this is really just a layers URL...
37:32...'cause a service can say, "I support uploads," and it's something that you can enable.
37:36In this case, because this is an editable service, I want to add this as a feature.
37:41And I create a new upload window, and this is basically just a child window, and I'll quickly show what that looks like.
37:47Like that, a little upload, it has a couple of properties for progress, for setting how, like, to update the progress on this thing.
37:57And when the window closes - if someone clicks Close on the upload window, actually on the upload task...
38:03...it will say, hey, cancel the upload. Just stop what you're doing and it'll clean up in the server afterwards.
38:10So show the window; it means I'm not doing something, and I'm just going to jump down a little bit and say...
38:16...uploadTask async, and I'm going to give it some parameters.
38:21There's really just two; there's the stream to the file and there's the file name I want to give it.
38:25The file name is technically optional, but for some of the servers, they actually require extensions.
38:29For instance, you have a TIFF file and a world file, Image Server likes to know which, from the file name, what this is.
38:35For some other scenarios, it might not be necessary.
38:40And when it completes, I'll basically just close the window.
38:43And I have this little data model where I add all the items to that I've been uploading...
38:47...and this is basically just the result I get back.
38:50You will notice that I have item and whether it was successful.
38:57On the item itself, there's some extra metadata about the actual upload.
39:04Also I have the progress event. That basically gives me how many bytes were written out of how many bytes...
39:09...so when I update this, my little upload window automatically calculates the percentage and then updates that as well.
39:15I did not know that. Okay.
39:19So that's really all there is to this one.
39:23And I believe when I click Delete button, again, create an upload task, pass in the item I just deleted, and it'll...
39:31...I remove it from my data model locally too, so it removes from my list of items.
39:36So that's really the upload task. And in this case, I could have authored multiple files.
39:42Sometimes, an image upload supports two image services - multiple files.
39:46In this case, I'm not having - I'm not [unintelligible] georeferencing information.
39:53So just quickly, reiterate, good for large files - whoops.
40:00So you get progress information, you get cancellation, you get deletion, and it's a really simple file to do file uploads for you...
40:07...so we take care of all that other complex stuff of uploading and committing them and joining them on the server.
40:15Alright. So the next thing I do when I add the raster, and really, it's just telling the server...
40:22...hey, I'm going to add a raster, and by the way, this is the item I uploaded for you.
40:28I can georeference this item.
40:31And what I can do is I can zoom in here, I can click a little button here and here, and so on, keep going.
40:39And you'll notice I can actually, when I hover on it, it becomes yellow here. Whoops.
40:45So it kind of highlights both. And it's kind of hard to see.
40:47There's little yellow outlines here that like, links these together, so it's kind of like a rubber band.
40:53I can grab them and move them, and it automatically updates.
40:56And this happens to be using the graphics data source that I just talked about, so these points are actually just part of a data source.
41:02But there's these funky lines between there that actually are not part of the map.
41:07They go across two different maps, and they update.
41:10And I'd like to talk a little about how we can do something like this...
41:13...where you basically have stuff that overlays on top of the map but is in sync with the map.
41:19But because I really like this image, let me just - I think this is really cool.
41:24I have a bunch of points that I just preconfigured here, and I'm going to do a really third-order polynomial...
41:28...which I misspelled I can see, and there we go. It really warps it into place.
41:35I think it's really cool. In a browser, no matter.
41:40So how did I do that? Alright, let's build a little sample.
41:47I have this little app here I built, and I basically have a bunch of cities here, and I took all the cities and bound to a list over here.
42:01It will be kind of cool, though, when I click this, it points to a city that I'm clicking on, right?
42:09So if I can make a line that goes from here over to the city that I'm clicking on, how would I do that?
42:16And that's similar to, like, the lines that are connected between two maps; it's just two maps instead of a list and a map.
42:25So let me see. I have my list box, and then it just binds to the layer, city layers, the graphics, and it has the city name as the text.
42:40So the first thing I want to do is I want to add a line I want to draw.
42:45So at the bottom here, I'm just inserting a line...
42:48...and here I could say the line comes from X1 equals 100, Y1 equals like where I want the line to go to and from.
42:55But I don't really know this up front, so I'm just going to leave this out for now.
43:00Second thing I do is when I select an item here, I want to update the line, what it's pointing at.
43:07Oops, that's not the right one. SelectionChanged is what I'm looking for.
43:17So let's add some code for this one. Alright.
43:27So when the selection changed, I just want to update my line here.
43:32And the first thing I do is I grab the item, I select it on my list box, and then I grab the geometry on that graphic.
43:39So this is the location of the city.
43:43And remember the first thing I want to do is I want to convert my map point on the map in longitude-latitude...
43:48...into screen coordinates.
43:51And we have a little method for doing that so it gives MapToScreen.
43:54This gives you the screen coordinate of the point relative to the upper left of the map. Not of the whole app, just of the map.
44:02So it's 0,0 in the upper left of the map.
44:05But because the line doesn't live within the map, I need to have the coordinates relative to where it lives within.
44:12And Silverlight already gives you this.
44:13You have this method called TransformToVisual, and it takes into account everything like offsets, margins, rotates...
44:21...scale transforms - everything - and converts it through all those matrices and gives you the right coordinate.
44:26So I pass in the parent of the line, because that's the coordinate system I want to be working in...
44:31...and say just transform the screen point, and now this point is relative to the line's coordinate system.
44:38And then I say the X2 and the Y2 is just those x and y's.
44:44Similar, I want to draw - I want to - where I draw the line from, I'm going to pick the selected item.
44:49And this is a little more tricky one.
44:52But there is this helper method on this [unintelligible] for the item generator...
44:54...that gives you the actual visual element that my graphic is being rendered with.
44:59So I pass in the graphic, and I gave it some kind of framework element in this case.
45:04And again, I do the same thing. I want to transform this element into this PointerLine.Parent and transform that point.
45:11In this case, I'm grabbing the width of the element, which means I want it on the right side of that...
45:17...and half the height, so I kind of centered on it.
45:19So that's the relative coordinate, and I update this.
45:26Alright. So now when I click here, I get a little line. It's kind of neat.
45:34And then when I pan the map, it doesn't really work. But I click again, it's fine again, right?
45:41But how do I do that then?
45:44Well, something is happening to the map so these coordinates now get invalidated, and that's every time the extent changes.
45:52So all I have to do is go to my map here, say ExtentChanged - actually ExtentChanging.
46:03Change doesn't happen until I'm kind of done navigating.
46:05I want to do it as I'm moving, so that go into this one and say UpdatePointer, and hopefully, that is all I need.
46:22So now when I zoom in, it keeps pointing on it.
46:26In this case, it kind of looks weird when I do like this.
46:31And if you notice in the Image Editor sample - let's try and go back and do this thing again.
46:38I actually click this little image, georeference, I click Images here. Notice how it removes the line?
46:48Hard to see? Can you guys see that?
46:52So if I add a bunch, like they will kind of show them up.
46:56So all I really do is I just check here, is the point within the extent of the current map extent...
47:00...and if it is, just collapse the line.
47:01So you can do something similar in this case.
47:08Of course, now when I do this, I'll leave you guys to fix that one.
47:13But again, it's a scroll, update the pointer.
47:18So you guys have probably already seen the info window? Anyone use the info window in the toolkit? A few.
47:25Actually that was the one I was just doing here on the map.
47:29I click here, and I get this info window up.
47:33This is just using this approach. It's nothing else.
47:35So I put an info window somewhere in my page, uses a ScreenToMap...
47:40...converts to its own coordinate system and then automatically updates.
47:43And if I go outside here, it automatically just collapses; it detects that.
47:47So there's other ways; like, there's a way to do that here too.
47:50So this is just an example of how we use that approach.
47:53By converting screen coordinates, you can get stuff to stick to the map.
47:58So ExtentChanging event, really important event for these things.
48:02Again, to reiterate, MapToScreen, ScreenToMap, back and forth between screen coordinates and map coordinates.
48:10You can convert between elements' coordinate systems by using that TransformToVisual...
48:14...that all framework elements have.
48:18And the ExtentChanging event, use that for updating; every time the extent changes, you want to update your positioning.
48:27Alright. That was...that slide got misplaced. But if you guys need some notes about the upload task, it's in the slide.
48:35Just a little... Sorry about that. Anyways...alright.
48:45I want to show a little, I want to jump over to something a little different.
48:48In 10.1, we added support for z's and m's. Anyone use z's and m's? Some hands there.
48:55Anyone want to use it in a browser? Yep. We can do that now.
49:03So let me just show you a quick little sample. There's really not much to it. It's really just two extra double values.
49:09So...that's not right. So I have this little dataset of some rivers.
49:21So what we did was we took a simple river dataset and we draped it onto, like, a surface of a hyd. model...
49:30...and we assigned all the z-values and then we assigned all the measure values.
49:35I better hurry up; I'm running out of battery.
49:45So we assigned all the m-values to be the distance from the ocean.
49:49So as the whole river system branches out, the m-value becomes bigger and bigger and bigger.
49:55And so what I did was I had this little hovering here...let me just zoom in a little bit so you can better see.
50:01I wrote a little bit of SNAP code, like grabs the vertex on an item, and you'll see the z-values and the m-values.
50:07So if I go down here to - close to the ocean, z is 0 because I'm at sea level...
50:12...and then as I move up, the m-value increases; z-value increases.
50:19If I click on a feature, what I'm going to do is I'm going to grab that whole feature and take its...
50:24...plot its m-values along the x-axis and its z-values along the y-axis.
50:30And I kind of...there's a little...well, data was not that accurate, so it goes a little bit up and down...
50:35...but generally, this river flows downhill all the way, which you would expect it to do.
50:41It's a nice little way I have that showcases that the z's and m-values are now exposed...
50:45...and I believe that this river is a lot steeper, and it goes uphill too; it's really amazing.
50:52And if you go to the last point here, we'll see that it's about three kilometers up, which seems to fit pretty well.
50:59And if it's really steep here, that's probably a really good place to go river rafting. Or die, depending on...
51:11So, yeah. That really is - there's just a new z- and m-value on MapPoint that we added, so you can just set those.
51:18When you do editing, though, the editor tools out of the box do not do z's and m's, and some of the servers require you to set these.
51:27So for those scenarios, you're required to write a little code to either set those, if you're doing editing of those...
51:32...or have defined defaults for them.
51:36For instance, you could take whatever the user just drew, pass it through some kind of GP service...
51:41...that assigns z's to them, or asks them to enter all the values, before you actually commit the save.
51:47So you can still do this in code behind and it'll be saved back to the server.
51:50The tools out of the box only do 2D editing, though, so beware of that.
51:57Alright. Think that was really what I had.
52:07Alright. So you guys just got an early preview of this before it was ready, so there we go. So, good to go.
52:14Thanks, Jennifer. Thanks, Morten.
52:17We're going to wrap up with a last discussion here on working with feature layer editing with feature services.
52:22How many of you guys - So this was introduced in 10.0.
52:25Obviously, we have functionality in our 2.x API that enables you to work with editing feature layers within a feature service.
52:33Anybody actually use this? Is this...quite a few, okay. So this is pretty common.
52:37So this, you might have already seen this here at the conference.
52:41We've enhanced feature services, as well as a few other services, to enable tracking of features within a feature service...
52:51...within a feature layer.
52:53Also dictating what type of access those different owners have to making changes to both geometry and attributes.
53:01So there's some changes that've gone into feature services at 10.1.
53:04Maybe in the past, to keep track of...what you've wanted to do is keep track of who created a feature...
53:09...when they created it, and who's last edited that feature, and maybe restrict access to specific users or roles...
53:18...or restrict different levels of access, such as a user can edit geometry but they can't edit attributes...
53:24...or they can edit attributes, not geometry, vice versa.
53:26So a variety of different combinations and workflows that are necessary to better support control or tracking...
53:33...of who's making changes to your data.
53:36So feature services have been enhanced at 10.1 to support, what we call it is editor tracking or ownership-based editing.
53:42Basically, editor tracking allows you to keep track of the person, the individual, the user that created a feature...
53:48...when they created it, the last user that edited that feature, and when they edited it; allows you to dictate...
53:54...whether or not a user who is not the initial owner of a feature can update or delete a feature. Alright?
54:03If they own it, can they update it or delete it? You can define that.
54:06And then also, if you'd like to disable geometry edits, right? So you can actually just enable attribute edits.
54:12Users are then unable to actually edit geometry.
54:15So there's a variety of different combinations that feature services support.
54:18Where do you get this? Well, ArcGIS Server 10.1 feature services have it.
54:22The hosted feature services that rolled out last week on ArcGIS Online as part of the Organizations offering have it as well.
54:30What I'm going to dive into here is just a brief demo of two different workflows.
54:34The first workflow, I've enabled editor tracking on a layer, or on a feature service...
54:39...so that layers that are within that feature service that support it and have editor tracking enabled on them...
54:44...be able to keep track of who creates a feature, when they did it, and then who last edited that feature.
54:48And I can see that information actually in a tabular format as well as in the map display.
54:56How do you do this?
54:57Well, obviously, with ArcGIS Server, either ArcGIS Online or ArcGIS Server, that includes a token service...
55:02...and so if you secure your service, the identity, the identity that's wrapped in that token that you provide to a service...
55:09...is going to identify the user that you're trying to use to make an edit to the underlying layer within that service.
55:16And so this'll be valid for both the ArcGIS Online hosted feature services as well as ArcGIS Server feature services too.
55:23So in this case what I've done is I've created an application, simple application.
55:26We have an identity manager class within our 3.0 API.
55:32We also have a sign-in dialog, which is an out-of-the-box toolkit control that plugs into the...
55:37...token-secured service capabilities of ArcGIS Server and ArcGIS for Portal or ArcGIS Online.
55:43So you can merely plug this into your app at 3.0. It'll actually work with older services too.
55:48So we covered this in the What's New session, so I'm not going to go into too much detail here...
55:52...but just know that we have this available. It's out of the box; you don't have to write the entire thing from scratch.
55:58You can use it right now, actually. It's in the 3.0 prerelease and ready to go.
56:03So I'm going to log in as a user here. I'm going to log in as user3. User3...we'll go ahead and the identity's user3.
56:09We're hitting an ArcGIS Server 10.1 prerelease server.
56:14We've got a set of points here, and we can see at least in the display, we've got three points...
56:19...and they're owned by different users, right? So we've got one point owned by user3, which is the person that I'm logged in as...
56:26...and then two different points that are actually owned by user1.
56:29Now in this case, I can actually update and delete features that I don't own.
56:35I can either change the geometry; I can also change the attributes.
56:39So we'll go ahead and take a quick look here.
56:40If I make the change, we can see the active updates happen as they occur.
56:46So in this case, if I were to grab this feature, what we can see is that the user changes.
56:53Right? If I were to grab this feature over here, as soon as I grab it, I start moving it, the user identity's now changed.
56:59The creator was user1. I'm user3; I make a change, immediately that change is then updated on the server...
57:06...and we can see the change happen in the feature data grid here in the application.
57:16I also have the ability to edit attributes as well, so if I wanted to...
57:21Let's say let's log in as a different user. I'll hit a different user here. Let's go in as user2.
57:28Get a nice little validation there.
57:33And let's go down here, and I'm going to make a change right here.
57:37What we can see is that...well, that's a little bit too close; hopefully, this is a little too far away.
57:44Let's go in, I'll make a change down here. I'm going to add in an instant command post, let's say I see a small fire.
57:51As soon as I make a change, I can see that the last_edited_user column was updated with the current user that I'm logged in as...
58:00...the one that I actually made the change with.
58:03Great. So this is a service in which editor tracking's been enabled.
58:07Ownership-based editing is wide open, so by default, other users can update or delete other users' features.
58:17We can lock that down.
58:18And so I've got another service here, and I'll log in as...let's go to user3. User3.
58:28I've got another service here, and in this service, I have a set of features...
58:35That's interesting; the old features are showing up there.
58:40I have a set of features that I've disabled the ability for other users to update or delete features that have been created by someone else.
58:51At the same time, I'm only tracking who's created a feature, right, so we're not tracking who's actually updated that feature.
58:56So I have a select few columns here.
58:58In this case, I have a creator column, when that was actually created, and I'm logged in as user3...
59:02...so I can go, make a change to individual features that I own, right?
59:07I can actually go down here and say, hey, this is a big starfish. Good times.
59:13But if I hit another feature - let's say this feature here - I can't make a change to it.
59:18I can't edit it. The interface doesn't allow me to do that.
59:22Now, how is this happening in the API? I also can't delete the feature, right?
59:26If I go back to a feature that I do own, I do have a set of commands that are included with the editor...
59:32...and the API, out of the box.
59:33And so I can actually delete this feature. I have full control over those features that I created or that I own basically.
59:40So that's something that's been configured on the service, too, to control.
59:43The key here is that the API is smart about the metadata associated with your feature service...
59:51...such that if it has edit fields info or if it has ownership-based access details, it'll read that information...
59:57...and it'll attempt to validate whether or not you can make a change, right.
1:00:02As the current logged-in user, you can make a change to that feature, right?
1:00:05You have a way of interrogating this as well within the API.
1:00:08So the API tries to essentially be smart about whether or not you should be able to make changes...
1:00:15...so that you don't send an erroneous request that's doomed to fail basically.
1:00:18So the API tries to help you along the way there and validate those edits...
1:00:23...and give you information about pending edits that you're going to make.
1:00:28So let's take a look at some of the code behind the scenes here.
1:00:31This is briefly just a quick look at Identity Manager.
1:00:35This is a way of saying, hey, I want to be able to use Identity Manager out of the box.
1:00:39I want to use a sign-in dialog and provide some additional details here.
1:00:43I happen to be tracking the number of attempts actually to log in here.
1:00:47That's gratuitous, not absolutely necessary.
1:00:51The first thing I want to highlight here is EditUserName. So a couple of properties that are important.
1:00:56How do we know, in the API, who you are, right, who's trying to make an edit on a feature layer?
1:01:03Well, we have an EditUserName property, right, and now in the API you can actually discover...
1:01:06...you can discover who you're logged in as.
1:01:08So as part of the Identity Manager or as part of an interface that you've built, you're logging in as...
1:01:12...you're identifying, your customer or your client is actually identifying themselves with a user identity.
1:01:17This is the user that's associated with your creator/editor field in your feature service.
1:01:22And so if you set the EditUserName, this is merely a string.
1:01:26Set the EditUserName, and the API has the information it needs at that point to determine whether or not that user can make an edit.
1:01:32Right? So that we can more effectively validate those changes that you want to make within the API.
1:01:38We can attempt to help you.
1:01:40Instead of making requests that are going to fail, we try to help you so that we can interrogate whether or not the change...
1:01:46...that you're about to make, the change to the graphic or the feature you're about to make, is going to work.
1:01:50Alright? And so how do we do that?
1:01:51There's a call actually on the feature layer called IsUpdateAllowed. You can pass in a graphic, pass in a feature.
1:01:58This is going to let you know, hey, can I make a change, right? Can I update this feature?
1:02:02Is this something that I should proceed with?
1:02:04And so it gives you the intelligence.
1:02:06The API has the intelligence to give you that information. You can discover that.
1:02:10So what's the take-home on a few of these? Let's go ahead and we'll bounce out to a slide here real quick.
1:02:15A couple things you need to pay attention to within the API that will respect editor tracking that you've enabled on a feature service.
1:02:23First one, obviously, is the EditUserName. I just talked about that; client-side validation is how it's used.
1:02:28And then the IsUpdateAllowed for an individual graphic. So see if a feature can be updated or changed.
1:02:34There's a variety of other properties that are available off FeatureLayerInfo that give you metadata...
1:02:38...essentially about what the service provides.
1:02:39So if you want to discover EditFieldsInfo, and this basically is essentially taking the JSON from the feature service...
1:02:49...and we're providing it essentially like a native format, classes, objects that you can then discover within the API.
1:02:57So EditFieldsInfo will give you the fields that are going to be used to log the creator, the created date...
1:03:05...creation date, the editor field, and the last edited date.
1:03:10OwnershipBasedAccessControl's going to give you access to whether or not update or delete is allowed...
1:03:15...by users other than the owner.
1:03:17And then AllowGeometryUpdates is another property. Again, goes right back to JSON that's available in the feature service.
1:03:23Can geometry be updated, right?
1:03:24And this is a way of saying, hey, I just want my users to change attributes; I don't want them to change geometry.
1:03:30So you have a way of restricting that within the feature service.
1:03:33So this is discoverable, actually, in the API...
1:03:35...so you don't have to go right to the service actually to figure out exactly if it's something that can be done.
1:03:42Okay, great. Okay, cool. So that's going to wrap it up. I think we're getting pretty close.
1:03:47Yep, so we've got about 10 minutes. We're going to go to a Q&A session here, so if you guys have some questions...
1:03:54...feel free to...we'll go ahead and ask a couple questions and then we'll break and then we can keep chatting afterwards as well.
Advanced Development with ArcGIS API for Silverlight
Morten Nielsen, Jennifer Nery, and Rex Hansen present development scenarios of Silverlight applications.
- Recorded: Mar 29th, 2012
- Runtime: 1:04:01
- Views: 1778
- Published: Apr 25th, 2012
- Night Mode (Off)Automatically dim the web site while the video is playing. A few seconds after you start watching the video and stop moving your mouse, your screen will dim. You can auto save this option if you login.
- HTML5 Video (Off) Play videos using HTML5 Video instead of flash. A modern web browser is required to view videos using HTML5.