Last week I began work on prototyping a new application as part of the Full Stack series. In this application I would like to open a dialog box, retrieve some information from the user, and return that information to the calling page.
There is a dialog box in Windows Phone (System.Windows.MessageBox) but unfortunately it cannot retrieve data entered by the user. No problem, I’ll create a new page, put in a label and a textBox and two buttons (OK and Cancel). The only issue is how do I get the data entered on page 2 back to page 1 (the calling page)?
The answer is to use the NavigationService.Navigate method to add the data in page 2, and the NavigationContext.QueryString property to retrieve the data in page 1. Let’s create a small sample to see this at work.
To begin, open a new Windows Phone application and in MainPage.xaml add two rows. Add a Button to the first row and a TextBlock in the second row. The content for the Button is Retrieve Data From User and the TextBlock should have nothing (i.e., an empty string) in the Text property for now. Set the PageTitle to Page 1,
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> <TextBlock x:Name="ApplicationTitle" Text="Sending Messages" Style="{StaticResource PhoneTextNormalStyle}" /> <TextBlock x:Name="PageTitle" Text="Page 1" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}" /> </StackPanel> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <Grid.RowDefinitions> <RowDefinition Height="1*" /> <RowDefinition Height="1*" /> <RowDefinition Height="4*" /> </Grid.RowDefinitions> <Button Name="RetrieveData" Content="Retrieve Data From User" Width="400" Grid.Row="0" /> <TextBlock Text="" Name="DisplayText" Grid.Row ="1" /> </Grid>
Create a second Windows Page. Set its PageTitle to Page 2. Add two rows and two columns. In the first row add a TextBlock whose text is Enter Data, and in the second column, a TextBox named Entered Data. In the second row add a StackPanel and within the panel two Buttons whose content are OK and Cancel respectively.
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="124*" /> <ColumnDefinition Width="332*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="1*" /> <RowDefinition Height="1*" /> <RowDefinition Height="4*" /> </Grid.RowDefinitions> <TextBlock Height="30" HorizontalAlignment="Left" Text="Enter Data" VerticalAlignment="Bottom" /> <TextBox Name="DataEntered" HorizontalAlignment="Left" VerticalAlignment="Bottom" Width="300" Grid.Column="1" /> <StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="1" Grid.Column="1" Orientation="Horizontal"> <Button Name="OK" Content="OK" Width="150" Margin="5" /> <Button Name="Cancel" Content="Cancel" Width="150" Margin="5" /> </StackPanel> </Grid>
In MainPage.xaml.cs create the event handler for the RetrieveData button. The job of this event handler is to navigate to Page 2. (No data is passed from MainPage to Page 2).
public MainPage() { InitializeComponent(); RetrieveData.Click += ( RetrieveData_Click ); } void RetrieveData_Click( object sender, RoutedEventArgs e ) { NavigationService.Navigate( new Uri( "/Page2.xaml", UriKind.Relative ) ); }
Open Page2.xaml.cs and let’s add the logic for passing the user’s entry to MainPage.xaml.cs. To do this we want to respond to either the OK or the Cancel Button, but only if the user clicks OK will we pick up the data in the TextBox. Begin by creating a unified event handler for the two buttons,
public Page2() { InitializeComponent(); OK.Click += ButtonClick; Cancel.Click += ButtonClick; }
The implementation of the click event handler needs to differentiate which button called it, and thus must cast the sender object to an object of type Button (which is what it will really be). Once we have a button we can ask for the Name or Content property to see which button called the handler. If it is OK we can then retrieve the Text property from the TextBox and pass it to Page 1. In either case, we’ll navigate to Page 1.
void ButtonClick( object sender, RoutedEventArgs e ) { Button btn = sender as Button; string msg = string.Empty; if (btn.Name == "OK") { msg = DataEntered.Text; } NavigationService.Navigate( new Uri( "/MainPage.xaml?DataEntered=" + msg, UriKind.Relative ) ); }
The string following the question mark will be passed back to MainPage.xaml in the NavigationContext’s QueryString property.
Return to MainPage.xaml and add an override of the OnNavigatedTo method. In that method you’ll retrieve the QueryString if it exists and add the string retrieved to the TextBlock.
protected override void OnNavigatedTo( System.Windows.Navigation.NavigationEventArgs e ) { string newText = string.Empty; if (NavigationContext.QueryString.TryGetValue( "DataEntered", out newText )) { DisplayText.Text = newText; } base.OnNavigatedTo( e ); }
Note, by the way, that you could use a Border on Page 1 and animate it so that it grows into place and then shrinks away, giving you more of the Dialog Box experience. I’ll cover that approach in an upcoming posting.
6 Responses to Windows Phone–Sending Messages Between Pages