Documentation : Push notifications - Windows Phone 7

localControls.SwitchUserControlThis example shows how to send push notifications to all users or just to one specified user.

Push notifications on Windows Phone 7 devices are provided by Microsoft Push Notification Service. Basic knowledge of it's mechanisms are necessary to complete this tutorial. 

Main screen of an application contains three buttons, one for sending push notifications to all users and two for sending push notification to specified users. When application recieve notifications, toast message will be shown. There are two users in the system and there's a possibility to switch user on application life time.

Design Your App

Open Mobeelizer App Designer and reate application called PushNotifications.

Because there are no models in application we can move to push notification section. There we enable push notifications. And that is all for WP7 devices. 

When everything is done in Create mode, deploy our application to test environment, and create two users with passwords:

  • a - usera
  • b - userb

Last thing to do in App Designer is download configured template with default settings.

Use the Mobeelizer SDK

Open downloaded project in Microsoft Visual Studio (Windows Phone SDK 7.1 must be installed on your computer). There is a few files generated in our project, applicatiom.xml, app.config (read more) and 'Model/File.cs' - our model class.

Create app skeleton

In our example we will use MVVM pattern. To make it, create three folders in solution explorer - 'View', 'Model' and 'ViewModel'. Next, move 'MainPage.xaml' file to 'View' folder and change path to navigation page in 'WMAppManifet.xml' file - DefaultTask node - to 'View/MainPage.xaml'.

Prepare main screen

Now we have already created skeleton of our project, next things to do is creating View and ViewModel. As you can read before main screen contains only 3 buttons, let's create them. Open MainPage.xaml file and create grid with six rows, then create buttons and labels in them as in below code.

View/MainPage.xaml
...
<Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
        <TextBlock x:Name="ApplicationTitle" Text="MOBEELIZER TUTORIAL" Style="{StaticResource PhoneTextNormalStyle}"/>
        <TextBlock x:Name="PageTitle" Text="Push notifications" 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="100"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="70"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="70"/>
            <RowDefinition Height="70"/>
            <RowDefinition />
        </Grid.RowDefinitions>
        <Grid>
            <!-- Place to switch user control -->
        </Grid>
        <TextBlock Grid.Row="1" Text="Send to everyone"/>
        <Button Grid.Row="2" Content="Send push notification" Command="{Binding SendPushCommand}"/>
        <TextBlock Grid.Row="3" Text="Send to users"/>
        <Button Grid.Row="4" Content="Send to A" Command="{Binding SendPushCommand}" CommandParameter="A"/>
        <Button Grid.Row="5" Content="Send to B" Command="{Binding SendPushCommand}" CommandParameter="B"/>
    </Grid>
</Grid>
...

Ok, let's create ViewModel for our xaml code. In ViewModel folder we need to create MainPageViewModel class. This class will contains properties which we already bind to our View.

ViewModel/MainPageViewModel.cs
public class MainPageViewModel
{
    public ICommand SendPushCommand { get; set; }
}

To connect our View with just created ViewModel, open MainPage.xaml.cs file and implement MainPage class constructor like this:

View/MainPage.xaml.cs
...
public MainPage()
{
    this.DataContext = new MainPageViewModel();
    InitializeComponent();
}
...

Register for receiving notifications

To keep all code responsible for push notifications in one seperated place we will create Singleton class called PushNotificationService in Model folder. The following methods will be included there:

  • RegisterForRemoteNotification - in this method we will create new or find existing push notification channel and bind it to shell toast messages. 
  • UnregisterUser - this method will be invoked before switching user to unregister not logged in user from reciving push notifications. 
  • RegisterUser - this method will be invoked after switching user. 
  • DispayToast - this method will dispay toast message on application life time. 
  • PushChannel_ChannelUriUpdated - this method will be invoked by opened push notification channel when url changed. 
  • PushChannel_ErrorOccurred - this method will be invoked by opened push channel in case of error.
  • PushChannel_ShellToastNotificationReceived - this method will be invoked by push channel when notification recived.

Toast messages are not included in standard controls library provided by Widnows Phone 7 SDK, you need to include following librrary into our project. 

Model/PushNotificationService.cs
public class PushNotificationService
{
    private string channelUri;
    private static PushNotificationService instance = new PushNotificationService();
    public static PushNotificationService Instance
    {
        get
        {
            return instance;
        }
    }
    public void RegisterForRemoteNotification()
    {
        HttpNotificationChannel pushChannel;
        string channelName = "toastNotificationChanel";
        pushChannel = HttpNotificationChannel.Find(channelName);
        if (pushChannel == null)
        {
            pushChannel = new HttpNotificationChannel(channelName);
            pushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(PushChannel_ChannelUriUpdated);
            pushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(PushChannel_ErrorOccurred);
            pushChannel.ShellToastNotificationReceived += new EventHandler<NotificationEventArgs>(PushChannel_ShellToastNotificationReceived);
            pushChannel.Open();
            pushChannel.BindToShellToast();
        }
        else
        {
            pushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(PushChannel_ChannelUriUpdated);
            pushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(PushChannel_ErrorOccurred);
            pushChannel.ShellToastNotificationReceived += new EventHandler<NotificationEventArgs>(PushChannel_ShellToastNotificationReceived);
            this.channelUri = pushChannel.ChannelUri.ToString();
        }
    }
    public void UnregisterUser()
    {
        Mobeelizer.UnregisterForRemoteNotifications(error => { });
    }
    public void RegisterUser()
    {
        Mobeelizer.RegisterForRemoteNotifications(channelUri, error => { });
    }
    private void DispayToast(String title, String message)
    {
        ToastPrompt toast = new ToastPrompt();
        try
        {
            toast.Title = title;
            toast.Message = message;
        }
        catch { }
        toast.Show();
    }
    private void PushChannel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e)
    {
        channelUri = e.ChannelUri.ToString();
    }
    private void PushChannel_ErrorOccurred(object sender, NotificationChannelErrorEventArgs e)
    {
        channelUri = null;
        Mobeelizer.UnregisterForRemoteNotifications((result) => { });
    }
    private void PushChannel_ShellToastNotificationReceived(object sender, NotificationEventArgs e)
    {
        Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
        {
            DispayToast(e.Collection["Text1"], e.Collection["Text2"]);
        }));
    }
}

Create switch user control

Ok, we can receive push notifications now, let's create swithing users things. We will create separated control for that. In View folder create new Windows Phone User Control and name it SwitchUserControl. This control will contains grid with two columns, first column will present information which user is currently loged in and second will contains button to switch user.

SwitchUserControl.xaml
...
	<Grid x:Name="LayoutRoot">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="150"/>
        </Grid.ColumnDefinitions>
        <TextBlock Text="{Binding CurrentUser, StringFormat='Current user is: {0}'}" VerticalAlignment="Center" Style="{StaticResource PhoneTextLargeStyle}"/>
        <Button Grid.Column="1" Content="Switch" Command="{Binding SwitchUser}"/>
    </Grid> 
...

Code below is ViewModel definition for just created control. There are two properties, first one contains information about currently logged in user and second one is a command to switch users. Class implements INotifyPropertyChanged interface to support notification about value changes of properties. There are also two methods to restore last logged in user before application closing.

SwitchUserControlViewModel.cs
public class SwitchUserControlViewModel : INotifyPropertyChanged
{
    public static String CurrentlyLoggendInUser;

    public SwitchUserControlViewModel()
    {
      // TODO:
    }

    public String CurrentUser
    {
        get
        {
            return CurrentlyLoggendInUser;
        }
    }
    public ICommand SwitchUser { get; set; }


    public event PropertyChangedEventHandler PropertyChanged;


    private void RaisePropertyChanged(String propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }


    public static void LoadLastLoggedInUser()
    {
        if (IsolatedStorageSettings.ApplicationSettings.Contains("LastLoggedInUser"))
        {
            CurrentlyLoggendInUser = IsolatedStorageSettings.ApplicationSettings["LastLoggedInUser"].ToString();
        }
    }


    public static void SaveLoggedInUser()
    {
        if (IsolatedStorageSettings.ApplicationSettings.Contains("LastLoggedInUser"))
        {
            IsolatedStorageSettings.ApplicationSettings["LastLoggedInUser"] = CurrentlyLoggendInUser;
        }
        else
        {
            IsolatedStorageSettings.ApplicationSettings.Add("LastLoggedInUser", CurrentlyLoggendInUser);
        }
    }
}

Open App.xaml.cs file and execute method to save and load last logged in user in Application_Launching and Application_Closing methods.

App.xaml.cs
...
private void Application_Launching(object sender, LaunchingEventArgs e)
{
    Mobeelizer.OnLaunching();
    SwitchUserControlViewModel.LoadLastLoggedInUser();
}
...
private void Application_Closing(object sender, ClosingEventArgs e)
{
    Mobeelizer.OnClosing();
    SwitchUserControlViewModel.SaveLoggedInUser();
}
...

And again remember to connect ViewModel and View. You need to also create our new control in MainPage grid row. 

SwitchUserControl.xaml.cs
...
        public SwitchUserControl()
        {
            this.DataContext = new SwitchUserControlViewModel();
            InitializeComponent();
        }
...
MainPage.xaml
...
<Grid Grid.Row="0">
	<localControls:SwitchUserControl />
</Grid>
...

When View and ViewModel are almost done it is time to write some buisness logic. We will start with SwitchUserCommand, this command will be responsible for switching between users and also have to notify other classes that user was switched. Create new class in Model folder and implement it like in code below. You can see that there are two events UserSwitched and CanExecuteChanged, first one notify about switching user, second will notify View that execution lock may change. There are also four methods: 'CanExecute' which returns execution lock value, 'Execute' which contains logging in code, 'RaiseCanExecuteChanged' to rise 'CanExecuteChanged' event and 'Mobeelizer_SyncStatusChanged' which is triggered when synchronization status change.

SwitchUserCommand.cs
public class SwitchUserCommand : ICommand
{
    private bool canSwitchUser = true;
    private const String USER_A_PASSWORD = "usera";
    private const String USER_B_PASSWORD = "userb";
    private const String USER_A_LOGIN = "a;
    private const String USER_B_LOGIN = "b";
    public event EventHandler CanExecuteChanged;
    public static event EventHandler UserSwitched;
    public SwitchUserCommand()
    {
        Mobeelizer.SyncStatusChanged += new MobeelizerSyncStatusChangedEventHandler(Mobeelizer_SyncStatusChanged);
    }
    public bool CanExecute(object parameter)
    {
        return canSwitchUser;
    }
    public void Execute(object parameter)
    {
        PushNotificationService.Instance.UnregisterUser();
        bool loginCurrent = false;
        if (parameter != null)
        {
            loginCurrent = (bool)parameter;
        }
        canSwitchUser = false;
        RaiseCanExecuteChanged();
        switch (SwitchUserControlViewModel.CurrentlyLoggendInUser)
        {
            case USER_A_LOGIN:
                Mobeelizer.Login( loginCurrent ? USER_A_LOGIN: USER_B_LOGIN,loginCurrent ? USER_A_PASSWORD : USER_B_PASSWORD, error =>
                {
                    if (error == null)
                    {
                        SwitchUserControlViewModel.CurrentlyLoggendInUser = loginCurrent ? USER_A_LOGIN : USER_B_LOGIN;
                    }
                    else
                    {
                        SwitchUserControlViewModel.CurrentlyLoggendInUser = String.Empty;
                    }
                    PushNotificationService.Instance.RegisterUser();
                    EventHandler handler = UserSwitched;
                    if (handler != null)
                    {
                        handler(this, EventArgs.Empty);
                    }
                    Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        canSwitchUser = true;
                        RaiseCanExecuteChanged();
                    }));
                });
                break;
            default:
            case USER_B_LOGIN:
                Mobeelizer.Login(loginCurrent ? USER_B_LOGIN : USER_A_LOGIN, loginCurrent ? USER_B_PASSWORD : USER_A_PASSWORD, error =>
                {
                    if (error == null)
                    {
                        SwitchUserControlViewModel.CurrentlyLoggendInUser = loginCurrent ? USER_B_LOGIN : USER_A_LOGIN;
                    }
                    else
                    {
                        SwitchUserControlViewModel.CurrentlyLoggendInUser = String.Empty;
                    }
                    EventHandler handler = UserSwitched;
                    PushNotificationService.Instance.RegisterUser();
                    if (handler != null)
                    {
                        handler(this, EventArgs.Empty);
                    }
                    Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        canSwitchUser = true;
                        RaiseCanExecuteChanged();
                    }));
                });
                break;
        }
    }
    public void RaiseCanExecuteChanged()
    {
        EventHandler handler = CanExecuteChanged;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
    }
    void Mobeelizer_SyncStatusChanged(MobeelizerSyncStatus status)
    {
        if (status == MobeelizerSyncStatus.FINISHED_WITH_SUCCESS || status == MobeelizerSyncStatus.FINISHED_WITH_FAILURE
            || status == MobeelizerSyncStatus.NONE)
        {
            canSwitchUser = true;
        }
        else
        {
            canSwitchUser = false;
        }
        Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
        {
            RaiseCanExecuteChanged();
        }));
    }
}

This code is pretty simple, when user click on switch user button, Execute method will be invoked, while method is executing, execution lock is set, when loging in is finished 'UserSwitched' event will be raised. User can't change while synchronization process is in progress, this functionality is implemented in 'Mobeelizer_SyncStatusChanged' method - when synchronization is in progress, lock flag is up. Before user will be switched unregister method from PushNotificationService is invoked.

Last thing to do in switching user code is implementing SwichUserControlViewModel constructor. When user is switched successfully he is registered for push notifications. 

SwitchUserControlViewModel.cs
...
public SwitchUserControlViewModel()
{
    SwitchUserCommand command = new SwitchUserCommand();
    SwitchUserCommand.UserSwitched += (object sender, EventArgs e) =>
    {
        SaveLoggedInUser();
        Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
        {
            RaisePropertyChanged("CurrentUser");
        }));
    };
    this.SwitchUser = command;
    this.SwitchUser.Execute(true);
}
...

Send push notifications

Nice, we can login to mobeelizer and switch between users. We are also registred for push notifications. It is time to send them. To do that we have to create new command - SendPushNotification in Model folder. 

Model/SendPushCommand.cs
public class SendPushCommand : ICommand
{
    public bool CanExecute(object parameter)
    {
        return Mobeelizer.IsLoggedIn;
    }
    public event EventHandler CanExecuteChanged;
    public void Execute(object parameter)
    {
        if (parameter != null)
        {
            String user = parameter.ToString();
            IDictionary<String, String> notification = new Dictionary<String, String>();
            // This values are necessary for wp7 devices. 
            notification.Add("X-NotificationClass", "2");
            notification.Add("X-WindowsPhone-Target", "toast");
            notification.Add("Text1", "Push received!");
            notification.Add("Text2", String.Format("Wp7 device greets user {0}.", user));
            notification.Add("Param", "/View/MainPage.xaml");
            // This value is necessary for iOS and Android devices.
            notification.Add("alert", String.Format("Wp7 device greets user {0}.", user));
            List<String> users = new List<string>();
            users.Add(user);
            Mobeelizer.SendRemoteNotificationToUsers(notification, users, error => { });
        }
        else
        {
            IDictionary<String, String> notification = new Dictionary<String, String>();
            // This values are necessary for wp7 devices. 
            notification.Add("X-NotificationClass", "2");
            notification.Add("X-WindowsPhone-Target", "toast");
            notification.Add("Text1", "Push received!");
            notification.Add("Text2", "Wp7 device greets all users.");
            notification.Add("Param", "/View/MainPage.xaml");
            // This value is necessary for iOS and Android devices.
            notification.Add("alert", "Wp7 device greets all users.");
            Mobeelizer.SendRemoteNotification(notification, error => { });
        }
    }
    public void RaiseCanExecuteChanged()
    {
        EventHandler handler = CanExecuteChanged;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
    }
}

Sending push notifications is available only when user is logged in. In Execute method we are checking if there is a username  parameter given and if it is we are creating notification message and senting to specify user. If it is not given then we are sending notification message to all users. We have to create object of this class in MainPageViewModel class to complete our example. 

ViewModel/MainPageViewModel.cs
...
public MainPageViewModel()
{
    PushNotificationService.Instance.RegisterForRemoteNotification();
    this.SendPushCommand = new SendPushCommand();
    SwitchUserCommand.UserSwitched += new EventHandler(SwitchUserCommand_UserSwitched);
}
void SwitchUserCommand_UserSwitched(object sender, EventArgs e)
{
    Deployment.Current.Dispatcher.BeginInvoke(new Action(()=>{
        (this.SendPushCommand as SendPushCommand).RaiseCanExecuteChanged();
    }));
}
...

Conclusion

Great, push notification example is done, we can send push notifications to all users in the system or to specified users. We can also send push notifications between other devices, implement same example on Android or iOS platform and check it by yourself.