Visually Located

XAML and GIS

Creating a Custom MessageBox for Windows Phone Applications

UPDATE: See a new post to get the latest code for the custom MessageBox.


UPDATE: After posting this blog I found out about the message box within the XNA framework. This does allow for custom button text which is what I was trying to accomplish. However, the user experience is different than what you get from the message boxes within the native phone applications (eg: deleting a text). With the native message boxes, the application bar disappears, but with the XNA message box, it gets greyed out. It’s the little things that matter. Also within the XNA framework you cannot add additional components to the message box. For example, you might want to add a “Do not show me this again” option within the message box.

While using a Windows Phone you get prompted every once in awhile by a message box. Custom Applications have them, even apps native to the phone has them. When deleting a text message or a contact you get a nice prompt asking you if you want to delete it. But there is something unique about these message boxes that separates them from the one that you and I get to have. The standard message box only allows for an “OK” and a “Cancel” button. The message boxes that are native to the phone have custom text. When you delete a text, you are prompted with buttons “delete” and “cancel”. Seeing as there is not a way to do this, you need to create your own. I’ve created a very simple sample that can be used.

The CustomMessageBox sample is based on the assumption that message boxes are “binary”. What I mean is that you get binary options, Yes/No, OK/Cancel, etc. So I’ve limited what is allowed to be a valid result.

 1: public enum CustomMessageBoxResult
 2: {
 3:     Yes, 
 4:     No,
 5:     // Not using this yet, but you could wire up to the back button of the phone to be a cancel
 6:     Cancel
 7: }

I don’t have the ability to have a Show method return the CustomMessageBoxResult so I’ll need an EventArg that will be used within an event.

 1: public class MessageBoxEventArgs : EventArgs
 2: {
 3:     public CustomMessageBoxResult Result { get; set; }
 4: }

The xaml is pretty straight forward. We need to "”block” the page the CustomMessageBox is for. To do this I made the control a grid so it will fill up everything. Then give it a background with an opacity that will block all clicks.

<Grid x:Class="Visual.Controls.MessageBox"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"             
             Margin="0">
    <Grid.Background>
        <SolidColorBrush Color="{StaticResource PhoneBackgroundColor}" Opacity=".5"/>
    </Grid.Background>
    <Grid x:Name="MessagePanel" Background="{StaticResource PhoneChromeBrush}"
          VerticalAlignment="Top" HorizontalAlignment="Stretch"
          toolkit:TiltEffect.IsTiltEnabled="True">
        <StackPanel Margin="12,12,12,18">
            <TextBlock x:Name="HeaderTextBlock" TextWrapping="Wrap"
                       Style="{StaticResource PhoneTextLargeStyle}"
                       FontFamily="{StaticResource PhoneFontFamilySemiBold}"
                       HorizontalAlignment="Left"/>
            <TextBlock x:Name="MessageTextBlock" TextWrapping="Wrap"
                       Style="{StaticResource PhoneTextNormalStyle}"
                       FontSize="{StaticResource PhoneFontSizeMedium}"
                       Margin="12,24,12,24"
                       HorizontalAlignment="Left"/>
            <Grid HorizontalAlignment="Stretch" Margin="0,6,0,0">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Button x:Name="YesButton" Click="YesButton_Click"/>
                <Button x:Name="NoButton" Grid.Column="1" Click="NoButton_Click"/>
            </Grid>
        </StackPanel>
    </Grid>
</Grid>

The message box has really one basic function, to ask the user a question. To accomplish that one function, we need to do three things.

  1. The message box must be put into the application. (Show method)
  2. When the user answers the question, the message box needs to be removed from the application. (Remove method)
  3. The message box needs to tell the application what the user picked. (Closed event)
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
 
using Microsoft.Phone.Controls;
 
namespace Visual.Controls
{
    public partial class MessageBox : Grid
    {
        private PhoneApplicationPage _page;
 
        private MessageBox()
        {
            InitializeComponent();
        }
 
        public event EventHandler<MessageBoxEventArgs> Closed;
 
        protected virtual void OnClosed(MessageBoxResult result)
        {
            // need to unsubscribe from the backkeypress
            _page.BackKeyPress -= Page_BackKeyPress;
 
            var handler = this.Closed;
            if (handler != null)
            {
                handler(this, new MessageBoxEventArgs { Result = result });
            }
            Remove();
        }
 
        public static MessageBox Show(string message, string caption, string yesButtonText, string noButtonText = null)
        {
            MessageBox msgBox = new MessageBox();
            msgBox.HeaderTextBlock.Text = caption;
            msgBox.MessageTextBlock.Text = message;
            msgBox.YesButton.Content = yesButtonText;
            if (string.IsNullOrWhiteSpace(noButtonText))
            {
                msgBox.NoButton.Visibility = Visibility.Collapsed;
            }
            else
            {
                msgBox.NoButton.Content = noButtonText;
            }
            msgBox.Insert();
            return msgBox;
        }
 
        private void Insert()
        {
            // Make an assumption that this is within a phone application that is developed "normally"
            var frame = Application.Current.RootVisual as Microsoft.Phone.Controls.PhoneApplicationFrame;
            _page = frame.Content as PhoneApplicationPage;
            _page.BackKeyPress += Page_BackKeyPress;
 
            // assume the child is a Grid, span all of the rows
            var grid = System.Windows.Media.VisualTreeHelper.GetChild(_page, 0) as Grid;
            if (grid.RowDefinitions.Count > 0)
            {
                Grid.SetRowSpan(this, grid.RowDefinitions.Count);
            }
            grid.Children.Add(this);
 
            // Create a transition like the regular MessageBox
            SwivelTransition transitionIn = new SwivelTransition();
            transitionIn.Mode = SwivelTransitionMode.BackwardIn;
 
            // Transition only the MessagePanel
            ITransition transition = transitionIn.GetTransition(MessagePanel);
            transition.Completed += (s, e) => transition.Stop();
            transition.Begin();
 
            if (_page.ApplicationBar != null)
            {
                // Hide the app bar so they cannot open more message boxes
                _page.ApplicationBar.IsVisible = false;
            }
        }
 
        private void Remove()
        {
            var frame = Application.Current.RootVisual as Microsoft.Phone.Controls.PhoneApplicationFrame;
            var page = frame.Content as PhoneApplicationPage;
            var grid = System.Windows.Media.VisualTreeHelper.GetChild(page, 0) as Grid;
 
            // Create a transition like the regular MessageBox
            SwivelTransition transitionOut = new SwivelTransition();
            transitionOut.Mode = SwivelTransitionMode.BackwardOut;
 
            ITransition transition = transitionOut.GetTransition(MessagePanel);
            transition.Completed += (s, e) =>
                {
                    transition.Stop();
                    grid.Children.Remove(this);
                    if (page.ApplicationBar != null)
                    {
                        page.ApplicationBar.IsVisible = true;
                    }
                };
            transition.Begin();
        }
 
        private void Page_BackKeyPress(object sender, CancelEventArgs e)
        {
            OnClosed(MessageBoxResult.Cancel);
            e.Cancel = true;
        }
 
        private void YesButton_Click(object sender, RoutedEventArgs e)
        {
            OnClosed(MessageBoxResult.Yes);
        }
 
        private void NoButton_Click(object sender, RoutedEventArgs e)
        {
            OnClosed(MessageBoxResult.No);
        }
    }
 
}

Now you can show your message box like such:

 1: var msgBox = CustomMessageBox.Show("Do you like Windows Phone.", "Custom Prompt", "I <3 WP", "No Thanks");

And you get the following:

image

blog comments powered by Disqus