Saving Data to the Web

Applies to: Windows Phone 7

Published: August 2011

Author: Nick Randolph

WROX Tech Editors for Windows Phone 7 Articles

Wrox Windows Phone 7 Books

To this point, we’ve focused only on the retrieving and presentation of data. In this section, look at some of the standard controls for capturing user input and how to submit this information to a remote service.

Start with a new page, SaveDataPage.xaml, and create a simple layout that allows the user to adjust information about a participant. However, before you create that layout, you need a ViewModel object to data bind to. In this case, it’s a relatively simple ViewModel instance, exposing a single CurrentParticipant property. This is set to a random Participant object for this example, but you can imagine that in your application the participant would be one that the user has selected from a list to edit.

public class SaveDataPageViewModel: INotifyPropertyChanged {
    private Participant currentParticipant;
    public Participant CurrentParticipant {
        get { return currentParticipant; }
        set {
            currentParticipant = value;
            this.RaisePropertyChanged("CurrentParticipant");
        }
    }

    public SaveDataPageViewModel(IRepository repository) {
        repository.CurrentParticipantsCompleted +=
                  repository_CurrentParticipantsCompleted;
        repository.CurrentParticipantsAsync();
    }

    void repository_CurrentParticipantsCompleted(object sender, 
         ParameterEventArgs<Participant[]> e) {
        var participant = e.Parameter[(new Random()).Next(e.Parameter.Length - 1)];
        if (participant.MemberSince == DateTime.MinValue) {
            participant.MemberSince = DateTime.Now;
        }
        CurrentParticipant = participant;
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void RaisePropertyChanged(string propertyName) {
        if (PropertyChanged != null) {
            PropertyChanged(this, 
                new PropertyChangedEventArgs(propertyName));
        }
    }
}

As before, you need to add your wiring logic to set this ViewModel instance as the DataContext object for the page. First you need to expose the SaveDataPageViewModel property on the ViewModelLocator object:

public class ViewModelLocator {
    … 
    public SaveDataPageViewModel SaveDataPageViewModel {
        get
        {
            return new SaveDataPageViewModel(this.Repository);
        }
    }
}

Then you need to set the DataContext in the SaveDataPage.xaml.

<phone:PhoneApplicationPage.DataContext>
    <Binding Path="SaveDataPageViewModel"
             Source="{StaticResource Locator}" />
</phone:PhoneApplicationPage.DataContext>

Now you are ready to define the Participant layout. Open the page in Expression Blend, and add two TextBlock elements, a TextBox element, and a DatePicker element to the page. Rearrange them so that they look similar to Figure 19. Notice that the DatePicker element is for the Member Since field.

Figure 19: Save Participant Layout

Referenced Image

From the Data window, expand out the SaveDataPageViewModel node and locate the Name node. Drag the Name node onto the TextBox element on the screen. In the past, when you have done this with a TextBlock element, dragging an item like this would result in a one-way binding being created. This means that any changes to the Name property of the Participant instance would propagate through to the user interface. In this case, you want the binding to be bidirectional so that any changes entered into the TextBox element can find their way back to the Participant object. Expression Blend predicts this behavior for certain controls, such as the TextBox element, resulting in the creation of a TwoWay binding.

From the Properties window for the TextBox element, locate the Text property and click the yellow square next to it. In the Create Data Binding window, expand the lower section. You can now see that the binding direction has been set to TwoWay (Figure 20), which results in updates flowing from the TextBox element to the underlying Name property on the Participant object.

Figure 20: Create TwoWay Data Binding

Referenced Image

Next you need to wire up the DatePicker element to the MemberSince property. Again, drag the MemberSince property onto the DatePicker element. This time, Expression Blend does not know how to wire up the data binding, so it prompts you to select the property and the binding direction to connect to (see Figure 21).

Figure 21: Wiring Up the DatePicker

Referenced Image

To complete this page, add an application bar that includes two icon buttons to save or cancel the current edit session. In the Objects and Timeline window, right-click the PhoneApplicationPage element and select Add ApplicationBar. Next, right-click the newly created ApplicationBar element and select Add ApplicationBarIconButton. Repeat the preceding actions so that you have two icon buttons on the ApplicationBar element. In the Properties window, adjust each of the icon buttons to have an icon and text, similar to Figure 22.

Figure 22: Page Layout with Application Bar

Referenced Image

Still in the Properties window, switch over to the events tab, and for each icon button, create an event handler for the Click event.

private void CancelClick(object sender, System.EventArgs e) {
    this.NavigationService.GoBack();
}

private void SaveClick(object sender, System.EventArgs e) {
    (this.DataContext as SaveDataPageViewModel).Save();
    this.NavigationService.GoBack();
}

The Cancel button simply goes back to the previous page, while the Save button passes off the save operation to the View Model class, SaveDataPageViewModel. This keeps all the logic of the application together and promotes testability of the view model and associated behaviors. The Save method currently does not do anything except extract the Name property of the participant.

public void Save() {
    var name = this.CurrentParticipant.Name;
    // TODO: Actually save the updated Participant
}

If you attempt to run this application, make changes to the name of a participant, and then immediately click the ApplicationBar element. Notice that the value of the “name” variable in the Save method is actually the old Name property value, not the new one. This might cause you to wonder whether you have got the data binding set up correctly. Unfortunately, this is a minor bug in the way that the platform creates and manages the application bar.

The two-way binding you created on the TextBox element kicks in only when the user leaves the TextBox area. Again, you would think that this should occur when the user clicks the ApplicationBar element. This is not the case because the ApplicationBar element is not a typical Silverlight element, and therefore you cannot data bind to it, nor does it trigger the usual unfocused behavior when a user clicks it.

The upshot is that you have to be more proactive in updating the binding information as the content of the TextBox element changes. What’s more, the code to actually do this is relatively simple, as follows:

private void TextBox_TextChanged(object sender, TextChangedEventArgs e) {
    var text= sender as TextBox;
    if (text != null) {
        var exp= text.GetBindingExpression(TextBox.TextProperty);
        if (exp!= null)
            exp.UpdateSource();
    }
}  

Now you should be able to save the updated Participant object.

Previous Article: Displaying Data with Data Binding

Continue on to the Next Article: Occasionally Connected Scenarios

Show: