Currently, we can find all images on Flickr based on the locale of the device, however in
our original "low tech mockup" design, we wanted to allow the user to filter the results
by a keyword or search phrase. We'll enable that feature in this lesson.
Our game plan in this lesson ...
1. We'l modify the layout of the MainPage.xaml to include a Topic textbox that wil allow the end user to type in specific search terms to include in our search of images from Flickr.
2. We'l then take that topic and send it to Flickr's web service. That wil require that we change the code in a few places to accommodate the passing and receiving of the topic value.
3. We'l then add the concept of radius to the app allowing us to specify the distance from the latitude and longitude for Flickr to include in it's search. I'l also refactor the code to harden it, or rather, make it impervious to accidental or malicious values that are nonsensical. We'l practice "defensive programming".
1. Edit MainPage.xaml: clean up layout, add Search text box
Not depicted in this screenshot, I remove almost all of the boilerplate comments and the
comments I've added previously.
1. I change the number of RowDefinitions, as well as their heights. In line 39 I didn't specify a height, meaning I want the default value of *, or rather, star sizing ... " take the remaining available space". Line 40 sets the row height to Auto which means "distribute space evenly based on the size of the content that is within a column or row."
2. We add a StackPanel as a container for the layout of our new Search bar at the bottom of the MainPage.xaml. The StackPanel contains a TextBlock and TextBox to allow for entry. The margin looks like it is missing two values, however that's simple a shortcut for writing:
Margin="-12, 0, -12, 0"
... it simply means "repeat these values".
Now, we'll need to add this notion of "Topic" throughout the entire application. We'll
pass it along with the position to the SearchResults.xaml page, we'll pass it to the Flickr
web service call, and so on.
2. Modify the Navigation code to pass Topic to SearchResults.xaml
In the MainPage.xaml.cs, edit the SearchClick() method ...
1. We are passing data in query strings ... We talked about query strings already. In this case, I'm concerned that a user may enter characters in the SearchTopic.Text that could be interpreted incorrectly. For example, using an ampersand or question mark could harm the interpretation of the query string. The UrlEncode() method can be used to encode the query-string values or even the entire URL. If characters such as blanks and punctuation are passed in an HTTP stream without encoding, they might be misinterpreted at the receiving end. URL encoding converts characters that are not allowed in a URL into character-entity equivalents. For more information about URL Encoding, check out:
However, whenever you're working with query strings, whether in HTML or XAML, it's always a good idea to URL Encode, ESPECIALLY if what you're passing in the query string is input by the end user.
2. In the string.Format, I add the "&topic={2}" to pass the Search Topic along to the next
page, and ...
3. Add the Url Encoded topic variable to substitute for the third position in the string.
3. Modify the Navigation code to RECEIVE the search topic in the SearchResults.xaml
First I'll create a private variable to hold the topic value I'm passing to the
SearchResults.xaml page ...
Next, I'll retrieve the topic value from the query string and save it in the new private
variable ...
While I'm here, I decide to go ahead and modify my call to the
FlickrImage.GetFlickrImage() method. I'll need to pass the topic value to the
GetFlickrImages() method that ultimately calls the Flickr web api. Since I've already
made the latitude and longitude optional / defaulted input parameters to my method, the
topic value must be passed in prior to those (unless I choose to make it optional as well
... but I've chosen not to.)
Now that I've added the topic in the call, I need to modify the
FlickrImage.GetFlickrImages() method itself:
1. I modify the method signature by adding the topic input parameter, and ...
2. I pass topic to the getBaseUrl() method call. Now I'l need to modify THAT method as wel ...
1. I modify the getBaseUrl() method signature by adding the topic input parameter
2. I add the "text" parameter to the Flickr API call, per their list of parameters.
3. I modify the line of code that replaces the placeholders with the actual values, adding topic at the end to be substituted into the new baseUrl string.
Now, I'm ready to test the results ... I'll search for "observatory" to limit the pics that are
returned by the Flickr web service call to only those that have the term "observatory" in
their description ...
I get a list of photos back that (a) look different from the list of images I was getting
back, and (b) they do all look like they have something to do specifically with the
observatory as opposed to a street level view.
However, I suppose I have no easy way to validate these results other than to perform a
similar search on Flickr's own website look for similarities between the list I'm displaying in the AroundMe app and the results from their website. I'm satisfied with the results, so I'm not going to take the time to thoroughly check the results. I'll trust that it's working for now.
We've satisfied the title of this lesson by adding filtering on the results based on
keywords. However, in the time that remains I want to add two improvements to our
GetFlickrImages() method in the FlickImage.cs file ...
4. Adding radius and programming defensively
The two improvements:
First, I'll add the concept of radius ... the Flickr web api allows us to pass in the radius it
will search.
Second, I'll add some code "defensive code" ... the phrase "defensive programming" is
a thought process or approach to writing code. In this case, I'll apply that thought
process to mean that I want do some checking of the query string values for latitude,
longitude and topic that I'm passing from the MainPage to the Results, and I want to add
double-quotes around the topic I want to pass to the Flickr API so the user can add a
phrase. If you want to learn more about defensive programming from a high level, a
great place to start is Wikipedia:
Let's begin by adding the notion of "radius" to our app. I'm not going to take the time to
fully implement this in this series. Clint's original application that he gave me will adjust
the radius we sent to Flickr based on how zoomed in or zoomed out we are in the Map
control. However, I decided to leave that code out of this video series ... first, it will add
a LOT of code to the application with come complicated calculations to convert map
pixels to radius. Secondly, there's no way to simulate the pinch-in or pinch-out motion in
the Windows Phone emulator. Perhaps once I'm finished with this series, I'll come back
and add an addendum to how to tackle this scenario. So, for now, I'll merely add the
feature for radius, and I'll hard-code the radius to 5 kilometers.
I'll modify the FlickrImage.cs ... specifically, I'll modify the getBaseUrl() method's
signature to include a radius input parameter ... I default radius the same way I default
latitude and longitude: to NaN, or rather, "Not A Number":
I'll continue to modify the getBaseUrl() method by splitting out the line of code where I
build the url that will later be used in the String.Format(). I want to test the topic, latitude,
longitude and radius before adding them to the baseUrl returned from this method. In
these cases, I want to only add values to the baseUrl that are valid. Therefore:
1. I re-work this entire section, removing about half of the string I'm constructing. Now that I've removed many of the variable parts (which I'l add back into the baseUrl in #2, #3, and #4, below), I can remove the variables I'l be replacing in the String.Format statement in line 89 and following.
2. I add this gated check to ensure that the user typed something, anything into the Topic textbox on the MainPage.xaml. Assuming the user did in fact type something in, we'l surround it with double quotes (%22 is the ASCII encoding for double quotes) and add it to the baseUrl.
3. I add this gated check to ensure that latitude and longitude are indeed numbers. If they are, then we'l add them in the baseUrl.
4. I add this gated check to ensure that radius is indeed a number. If it is, I'l add it to the baseUrl.
Next, I'll modify the GetFlickrImages() method in the FlickImage.cs file:
1. I add radius and default it to NaN
2. I include radius in the call to getBaseUrl()
Now, I'll modify the code in the SearchResults.xaml page that calls into the
GetFlickrImages() method:
Similar to what I did with topic a few moments ago:
1. I create a private variable, _radius, to hold the radius value
2. I include the _radius variable in the cal to GetFlickImages()
3. When the SearchResults.xaml page loads, I wil grab the query string value "radius".
Now I need to PASS "radius" in the query string FROM MainPage.xaml TO
SearchResults.xaml ... in the MainPage.xaml:
... I merely hard-code this to 5, indicating 5 kilometers.
I test to make sure it works, and it does.
Again, I've merely hardcoded this value. Ideally, I would allow the radius to match the
visible map on the MainPage.xaml. If you want to see a better implementation, take a
look at Clint's original implementation.
Recap
To recap, the big take away from this lesson was how to grab values from XAML input
controls, how to program defensively to make sure we check the input values to ensure
they are valid, how to URL Encode whenever you pass values (especially, end user
generated input values) in query strings of any kind. Along the way, we were able to
expand the usability of our app by allowing the user to specify the type of images he or
she is looking for.
No comments:
Post a Comment