As I mentioned in my previous entries in this series, I am currently writing an app to track participation in various activities. I am writing the app for the Windows 8 Metro UI as a means of teaching myself how to write these apps. In this article, I will discuss what I'm learning about UI development using XAML. Many (perhaps even most) of the things I'll discuss will apply to using XAML for other platforms, but that's only natural since I'm a novice in using XAML.

My first modification to the participant UI was to add three text blocks (for labels) and three text boxes to allow editing of the participant's first and last name and nickname. I did this with a combination of the designer and the XAML editor because some tasks are easier one way and some the other. I bound the controls to the appropriate properties in my participant class and my sample data showed up when running the app. The values changed when I selected different participants, as expected. The only issue was that any changes I made to the values weren't reflected in the data objects. Fortunately, I found the solution quickly. By default, the data binding is one way; however, it is easy to make it two way as follows:

Text="{Binding FirstName, Mode=TwoWay}"

By adding "Mode=TwoWay" to the Text property's binding, changes made to the data in the field are reflected in the data object when the text box loses focus.

The next step was to add a list view to show attendance objects for the selected participant. While working on this, I realized that I needed to revisit the data objects because I had no simple way to retrieve the attendance objects. I added a property to contain the current activity and another to contain that activities attendance records (picked out of all attendance records for that participant). That completed, the task of filling the list view was trivial. I bound the listview to a participant's current activity's attendance records. By adding a single line of code (telling the participant which activity was the current one) to the participants page's OnNavigated handler and to the participants list view's SelectionChanged handler, I was able to get the selected participant's attendance records for the current activity and display them via the attendance listview's data binding.

Next I needed to build a new page to allow editing of attendance entries -- dates and types of participation (such as "Present" or "Served snacks"). It seems kind of silly to build a whole page just to edit two items, but this is educational as well as practical, so I'm doing it anyway. I started by creating a new page using the "Basic Page" template, which automatically gave me a working back button and the page title. I set up navigation to the page by looking at the navigation from the activities page to the activity/participants page and using the appropriate data source (in this case, the attendance entry selected). I added text blocks to display the participant and activity names, a text box for date, and a combo box for participation type.

The most interesting part of this was setting up the combo box. Here is the line of XAML:

<ComboBox Grid.Column="1" Grid.Row="3" Margin="10,0,1,1" ItemsSource="{Binding Activity.Participation}" SelectedItem="{Binding Participation, Mode=TwoWay}"/>

The ItemsSource binding fills the combo box's list from a collection of strings in the attendance object's Activity property. Then we bind the SelectedItem property to the attendance object's Participation property, allowing updates to flow both ways. I'm continually amazed at just how easy some of this stuff is, coming from an environment where I was stuck manually setting and getting data to and from controls. I'm not thrilled with the way the new page looks when in full screen (landscape or portrait) and filled views. It's just too sparse. However, as I said earlier, it works and is a good educational experience.

Next up is to allow the user to select a custom image for a participant. I'll need the same for activities, but haven't yet constructed the activity editor. The Metro file dialog is simply beautiful to look at and simple to create in code:

FileOpenPicker p = new FileOpenPicker(); p.SuggestedStartLocation = PickerLocationId.PicturesLibrary; p.ViewMode = PickerViewMode.Thumbnail; p.FileTypeFilter.Clear(); p.FileTypeFilter.Add(".jpg"); p.FileTypeFilter.Add(".jpeg"); p.FileTypeFilter.Add(".png"); StorageFile f = await p.PickSingleFileAsync();

That bit of code gives you a gorgeous thumbnail-based view of the Pictures library root, showing only JPEG and PNG image files, and subdirectories within the library. It allows you to pick a single file. If you need multiple files, you change PickSingleFileAsync to PickMultipleFilesAsync and change StorageFile to IReadOnlyList<StorageFile>. If, after PickSingleFileAsync returns, f is not null, the user picked a file and tapped the "Open" button. In my app's case, I then verify that the user wants to replace the current picture, copy the file to a repository directory for the app, then load the image into the object's Image property. Thanks to property binding, the updated image is automatically displayed on the participant page.

See also:

Developing for Metro

Developing for Metro, Part 2

0 views0 comments
  • Marc A. Brown

Since I posted my original article on the subject of AT&T's unwillingness to approve updates to current-generation Windows Phones, I have read some promising news on the subject.

According to this wpcentral article, AT&T is planning to approve a post-8107 update to be pushed to current-generation WP7 devices, though they aren't willing to provide a timeframe for the release. Assuming that ATT&T is being truthful, and that they don't change their corporate minds, this means that those of us who bought Samsung Focus S or Focus Flash, or HTC Titan devices when they first came out won't be left out in the cold. That's good news for us, but the news could still be better. If you bought one of the first generation devices from AT&T -- the original Samsung Focus, LG Quantum, HTC Surround, or Dell Venue Pro -- you may not get the update, though that's not a sure thing. Since those phones are still less than two years old, I believe they should still get it.

I also disagree with the idea of holding off on bugfix updates because a feature update that they want to give us is coming up. The 8107 update has been available since January, and Tango is just making its way out the door now or very soon (assuming that Tango is the update they want us to have). Because 8107 was strictly an update to fix problems in the OS and nothing that would affect the OS feature set or the way the device interacts with the cellular network, it absolutely should have been released immediately. I'm cautiously optimistic that we will get the update, and get it reasonably soon, but I am still upset at AT&T both for their stance on pushing this update and for the lack of clear communication about it. They could have prevented a lot of the wailing and gnashing of teeth by their customer base simply by saying up front that they were holding the update until Tango came along.

Thanks to wpcentral and the AT&T community forums for the heads-up.

0 views0 comments

In my previous post on Metro development, I mentioned that I planned to write more as I delved deeper into this new world.

I am currently working with an app based on Visual Studio's Split Application Metro template. As I've mentioned before, you get a working app, including sample data and images. I am using this template to create an app to track activities and participants in those activities -- their attendance and additional participation.

I was ready to replace the template's sample images with my own, but wanted to load them from my Pictures library rather than embedding them in the app. Pretty simple and straightforward, right? Just add the Pictures Library capability to the manifest and go from there, right? I figured that all I needed to do was to get a URI to the image I wanted to load from the Pictures library and substitute that for the URI of the embedded image and all would be well. Not quite. I figuratively beat my head against this for (literally) a couple of hours before I figured out the correct (or at least a working) method of displaying these images. My Bing-fu wasn't up to the task of finding someone else's solution, so I had to work it out myself.

In the following snippets, ImageSource is a member of the Windows.UI.Xaml.Media namespace, BitmapImage is a member of the Windows.UI.Xaml.Media.Imaging namespace, and IStorageFile is a member of the Windows.Storage namespace.

This is the method of creating a BitmapImage from an embedded image:

ImageSource img = new BitmapImage(new Uri("ms-appx:///Assets/MyImage.png"));

Modifying it to display an image from the Pictures library (using a file:/// URI) didn't work. This, on the other hand, does work for images in the Pictures library:

ImageSource b = new BitmapImage(); IStorageFile i = await Windows.Storage.KnownFolders.PicturesLibrary.GetFileAsync(path); ((BitmapImage)b).SetSource(await i.OpenAsync(FileAccessMode.Read));

At the time I didn't understand why it had to be done that way, but I have since had a flash of inspiration that leads me to believe I understand it now. The images embedded in the project are already in memory by the time the app tries to display them (since the app has to be loaded), so the URI method works. However, images in the Pictures library aren't in memory yet, so you have to get them there (the BitmapImage class doesn't load them and neither does the Uri class). That's where the IStorageFile.OpenAsync method comes into play. Of course, I could be completely mistaken about the reasoning here, and someone with more experience may point out that I was doing something wrong that was preventing me from using a URI to create my BitmapImage (I don't think I was -- the URI looked good to me in the debugger, it just wasn't giving me a working BitmapImage).

Now that I have a working method of showing external images, I'm ready to move on to the next step in my project, which is to create editors for activities and participants so that I'm not just displaying static information.

0 views0 comments