Archive

Simple helper method to detect the last page of API data (C#)

When you are working with APIs from web services, you probably ran already into the same problem that I did recently: how to detect if we are on the last page of possible API results.

Some APIs (like WordPress) use tokens to be sent as parameter  with your request, and if the token is null or empty you know that you have reached the last page. However, not all APIs are working that way (for example UserVoice).

As I am rewriting Voices Admin to be a Universal app, I came up with a simple but effective helper method that allows me to easily detect if I am on the last page. Here is what I did:

	public static bool IsLastPage(int total, int countperpage, int current)
        {
            bool value = false;

            if (current < Convert.ToInt32(Math.Ceiling(Convert.ToDouble(total)/countperpage)))
            {
                value = false;
            }

            if (current == Convert.ToInt32(Math.Ceiling(Convert.ToDouble(total)/countperpage)))
                value = true;

            return value;
        }

As you can see, I need the number of total records that can be fetched (which is returned by the API) and the property for the number per page (which is one of the optional parameters of the API). On top, I need the current page number to calculate where I am (which is also an optional parameter of the API and returned by the API result).

Now I simply need to divide the total records by the result count per page to get how many pages are used. Using the Math.Ceiling() method, I always get the correct number of pages back. What does the Math.Ceiling() method do? It just jumps up to the next absolute number, also known as “rounding toward positive infinity”.

Example: if you have 51 total records and a per page count of 10, the division will return 5.1 (which means there is only one result on the 6th page). However, we need an absolute number. Rounding the result would return 5 pages, which is wrong in this case. The Math.Ceiling() method however returns the correct value of 6.

Setting the method up as a static Boolean makes it easy to change the CanExecute property of a button for example, which will be automatically disabled if we just have loaded the last page (page 6 in my case).

As always, I hope this is helpful for some of you.

Happy coding, everyone!

Posted by msicc in Archive, 2 comments

How to use WordPress to display remote notifications in your Windows Phone app

Sometimes, we need to display information to our users on demand. The easiest way is to do this in our app via a remote notification service.

If you have a WordPress blog, my solution may also be helpful for you.

I am using a page that is not linked anywhere in my blog to display the message. To add a new page, go to your WordPress Dashboard and hover over “Pages” and click on “Add New”.

image

Fill in the title and your notification and publish the page. Before closing your browser, save/remember the id of the page, we will need it later.

image

The next step is to download my WordPress Universal library, which can be downloaded right here from my Github. You can add the project directly to your solution or build it and then reference the library you will find in the bin folder of the WordPress Universal project folder. If you want to learn more about the library, visit http://bit.ly/WordPressUniversal.

Now that we have everything in place, let’s add the code that does the magic for us:

        public async void ShowNotification()
        {
            //initialize the client and load the list of pages from your blog
            wpClient = new WordPressClient();
            var pages = await wpClient.GetPostList("msicc.net", WordPressUniversal.Models.PostType.page, WordPressUniversal.Models.PostStatus.publish, 20, 0);

            //select the notification page
            var notificationContentPage = from p in pages.posts_list where p.id == 4248 select p;

            //check if has content
            if (!String.IsNullOrEmpty(notificationContentPage.FirstOrDefault().content))
            {
                //convert parapgraphs into NewLines
                //you might have more HTML content in there which needs to be converted
                string content = notificationContentPage.FirstOrDefault().content.Replace("

", string.Empty).Replace("

", "\n\n"); //App.SettingsStore = ApplicationData.Current.LocalSettings //change this to your appropriate storage like IsolatedStorage etc. //this displays the message only once to our users, but keeps the door open for an easy update mechanism if (App.SettingsStore.LastNotificationContent != content) { MessageBoxResult result = MessageBox.Show(content, notificationContentPage.FirstOrDefault().title, MessageBoxButton.OK); switch (result) { //the button click saves the actual message case MessageBoxResult.OK: App.SettingsStore.LastNotificationContent = content; break; //BackButtonPress does this as well case MessageBoxResult.None: App.SettingsStore.LastNotificationContent = content; break; } } } }

What does this code do? First, it fetches all pages from our WordPress blog. Then, we are selecting the page we created via its id. If your WordPress blog does not show you the id in the url of the page, set a BreakPoint at the “var notificationContentPage = …” line. you will then easily be able to get the id:

image

Naturally, the returned content is HTML formatted. To remove the paragraph tags and but respect their function, we are using a simple String.Replace pattern. You may have more HTML tags in your message that needs to be removed or converted.

To generate an easy way to display the message only once but keep it open for updates, we are saving the converted message locally. In this case, I used the LocalSettings of my Windows Phone 8.1 app. I am using the MessageBoxResult to make the method saving the message either at the point of the OK click as well as on BackButtonPress.

This is how the above generated WordPress Page looks as a Notification:

wp_ss_20141127_0001

As my WordPress Universal library works cross platform for C# apps, you should be able to adapt this for your Windows 8.1 or  Xamarin apps as well.

As always, I hope this is helpful for some of you.

Happy coding!

Posted by msicc in Archive, 1 comment

How to capture a photo in your Windows Phone 8.1 Runtime app – Part III: capturing and saving the photo

This is the third and last post of this series. In the first two posts I showed you how to start the preview of MediaCapture and some modifications we can apply to it. In this post, we are finally capturing and saving the photo – including the modifications we made before.

The easiest way – capture as is:

The easiest way to capture the photo is to use MediaCapture’s CapturePhotoToStorageFileAsync() method. This method shows you how to do it:

            //declare image format
            ImageEncodingProperties format = ImageEncodingProperties.CreateJpeg();

            //generate file in local folder:
            StorageFile capturefile = await ApplicationData.Current.LocalFolder.CreateFileAsync("photo_" + DateTime.Now.Ticks.ToString(), CreationCollisionOption.ReplaceExisting);

            ////take & save photo
            await captureManager.CapturePhotoToStorageFileAsync(format, capturefile);

            //show captured photo
            BitmapImage img = new BitmapImage(new Uri(capturefile.Path));
            takenImage.Source = img;
            takenImage.Visibility = Visibility.Visible;

This way however does not respect any modifications we made to the preview. The only thing that gets respected is the camera device we are using.

Respecting rotation in the captured photo:

In our ongoing sample, we are using a 90 degree rotation to display the preview element in portrait mode. Naturally, we want to port over this orientation in our captured image.

There are two ways to achieve this. We could capture the photo to a WriteableBitmap and manipulate it, or we could manipulate the image stream directly with the BitmapDecoder and  BitmapEncoder classes. We will do the latter one.

First, we need to open an InMemoryRandomAccessStream for our the captured photo. We are capturing the photo to the stream with MediaCapture’s CapturePhotoToStreamAsync() method, specifing the stream name and the image format.

The next step is to decode the stream with our BitmapDecoder. If we are performing only rotation, we can directly re-encode the InMemoryRandomAccessStream we are using. Rotating the captured photo is very simple with just setting the BitmapTransform.Rotation property to be rotated by 90 degrees, pretty much as easy as rotating the preview.

The last steps are generating a file in the storage, followed by copying the transcoded image stream into the file stream. Here is the complete code that does all this:

            //declare string for filename
            string captureFileName = string.Empty;
            //declare image format
            ImageEncodingProperties format = ImageEncodingProperties.CreateJpeg();

            //rotate and save the image
            using (var imageStream = new InMemoryRandomAccessStream())
            {
                //generate stream from MediaCapture
                await captureManager.CapturePhotoToStreamAsync(format, imageStream);

                //create decoder and encoder
                BitmapDecoder dec = await BitmapDecoder.CreateAsync(imageStream);
                BitmapEncoder enc = await BitmapEncoder.CreateForTranscodingAsync(imageStream, dec);

                //roate the image
                enc.BitmapTransform.Rotation = BitmapRotation.Clockwise90Degrees;

                //write changes to the image stream
                await enc.FlushAsync();

                //save the image
                StorageFolder folder = KnownFolders.SavedPictures;
                StorageFile capturefile = await folder.CreateFileAsync("photo_" + DateTime.Now.Ticks.ToString() + ".jpg", CreationCollisionOption.ReplaceExisting);
                captureFileName = capturefile.Name;

                //store stream in file
                using (var fileStream = await capturefile.OpenStreamForWriteAsync())
                {
                    try
                    {
                        //because of using statement stream will be closed automatically after copying finished
                        await RandomAccessStream.CopyAsync(imageStream, fileStream.AsOutputStream());
                    }
                    catch 
                    {

                    }
                }
            }

Of course, we need to stop the preview after we captured the photo. It also makes all sense to load the saved image and display it to the user. This is the code to stop the preview:

        private async void CleanCapture()
        {

            if (captureManager != null)
            {
                if (isPreviewing == true)
                {
                    await captureManager.StopPreviewAsync();
                    isPreviewing = false;
                }
                captureManager.Dispose();

                previewElement.Source = null;
                previewElement.Visibility = Visibility.Collapsed;
                takenImage.Source = null;
                takenImage.Visibility = Visibility.Collapsed;
                captureButton.Content = "capture";
            }

        }

The result of above mentioned code (screenshot of preview left, captured photo right):

16by9Photo

Cropping the captured photo

Not all Windows Phone devices have an aspect ratio of 16:9. In fact, most devices in the market have an aspect ratio of 15:9, due to the fact that they are WVGA or WXGA devices (I talked a bit about this already in my second post). If we are just capturing the photo with the method above, we will have the same black bands in our image as we have in our preview. To get around this and capture a photo that has a true 15:9 resolution (makes sense for photos that get reused in apps, but less for real life photos), additional code is needed.

As with getting the right camera solution, I generated an Enumeration that holds all possible values as well as a helper method to detect which aspect ratio the currently used device has:

        public enum DisplayAspectRatio
        {
            Unknown = -1,

            FifteenByNine = 0,

            SixteenByNine = 1
        }

        private DisplayAspectRatio GetDisplayAspectRatio()
        {
            DisplayAspectRatio result = DisplayAspectRatio.Unknown;

            //WP8.1 uses logical pixel dimensions, we need to convert this to raw pixel dimensions
            double logicalPixelWidth = Windows.UI.Xaml.Window.Current.Bounds.Width;
            double logicalPixelHeight = Windows.UI.Xaml.Window.Current.Bounds.Height;

            double rawPerViewPixels = DisplayInformation.GetForCurrentView().RawPixelsPerViewPixel;
            double rawPixelHeight = logicalPixelHeight * rawPerViewPixels;
            double rawPixelWidth = logicalPixelWidth * rawPerViewPixels;

            //calculate and return screen format
            double relation = Math.Max(rawPixelWidth, rawPixelHeight) / Math.Min(rawPixelWidth, rawPixelHeight);
            if (Math.Abs(relation - (15.0 / 9.0)) < 0.01)
            {
                result = DisplayAspectRatio.FifteenByNine;
            }
            else if (Math.Abs(relation - (16.0 / 9.0)) < 0.01)
            {
                result = DisplayAspectRatio.SixteenByNine;
            }

            return result;
        }

In Windows Phone 8.1, all Elements use logical pixel size. To get the values that most of us are used to, we need to calculate the raw pixels from the logical pixels. After that, we use the same math operations I used already for detecting the ratio of the camera resolution (see post 2). I tried to calculate the values with the logical pixels as well, but this ended up in some strange rounding behavior and not the results I wanted. That’s why I use the raw pixel sizes.

Before we continue with capturing the photo, we are going to add a border that is displayed and shows the area which is captured to the user in XAML:

            

When we are cropping our photo, we need to treaten the BitmapEncoder and the BitmapDecoder separately. To crop an image, we  need to set the Bounds and the new Width and Height of the photo via the BitmapTransform.Bounds property. We also need to read the PixelData via the GetPixelDataAsync() method, apply the changed Bounds to it and pass them to BitmapEncoder via the SetPixelData() method.

At the end, we are flushing the changed stream data directly into the file stream of our StorageFile. Here is how:

            //declare string for filename
            string captureFileName = string.Empty;
            //declare image format
            ImageEncodingProperties format = ImageEncodingProperties.CreateJpeg();

            using (var imageStream = new InMemoryRandomAccessStream())
            {
                //generate stream from MediaCapture
                await captureManager.CapturePhotoToStreamAsync(format, imageStream);

                //create decoder and transform
                BitmapDecoder dec = await BitmapDecoder.CreateAsync(imageStream);
                BitmapTransform transform = new BitmapTransform();

                //roate the image
                transform.Rotation = BitmapRotation.Clockwise90Degrees;
                transform.Bounds = GetFifteenByNineBounds();

                //get the conversion data that we need to save the cropped and rotated image
                BitmapPixelFormat pixelFormat = dec.BitmapPixelFormat;
                BitmapAlphaMode alpha = dec.BitmapAlphaMode;

                //read the PixelData
                PixelDataProvider pixelProvider = await dec.GetPixelDataAsync(
                    pixelFormat,
                    alpha,
                    transform,
                    ExifOrientationMode.RespectExifOrientation,
                    ColorManagementMode.ColorManageToSRgb
                    );
                byte[] pixels = pixelProvider.DetachPixelData();

                //generate the file
                StorageFolder folder = KnownFolders.SavedPictures;
                StorageFile capturefile = await folder.CreateFileAsync("photo_" + DateTime.Now.Ticks.ToString() + ".jpg", CreationCollisionOption.ReplaceExisting);
                captureFileName = capturefile.Name;

                //writing directly into the file stream
                using (IRandomAccessStream convertedImageStream = await capturefile.OpenAsync(FileAccessMode.ReadWrite))
                {
                    //write changes to the BitmapEncoder
                    BitmapEncoder enc = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, convertedImageStream);
                    enc.SetPixelData(
                        pixelFormat,
                        alpha,
                        transform.Bounds.Width,
                        transform.Bounds.Height,
                        dec.DpiX,
                        dec.DpiY,
                        pixels
                        );

                    await enc.FlushAsync();
                }
            }

You may have notice the GetFifteenByNineBounds() method in the above code. As we need to calculate some values for cropping the image, I decided to separate them. They are not only providing values for the image to be cropped, but also size values for our earlier added Border that is used in my sample (download link at the end of the project) to show the size that the photo will have after our cropping (which is an automatic process in our case,). Here is the code:

        private BitmapBounds GetFifteenByNineBounds()
        {
            BitmapBounds bounds = new BitmapBounds();

            //image size is raw pixels, so we need also here raw pixels
            double logicalPixelWidth = Windows.UI.Xaml.Window.Current.Bounds.Width;
            double logicalPixelHeight = Windows.UI.Xaml.Window.Current.Bounds.Height;

            double rawPerViewPixels = DisplayInformation.GetForCurrentView().RawPixelsPerViewPixel;
            double rawPixelHeight = logicalPixelHeight * rawPerViewPixels;
            double rawPixelWidth = logicalPixelWidth * rawPerViewPixels;

            //calculate scale factor of UniformToFill Height (remember, we rotated the preview)
            double scaleFactorVisualHeight = maxResolution().Width / rawPixelHeight;

            //calculate the visual Width
            //(because UniFormToFill scaled the previewElement Width down to match the previewElement Height)
            double visualWidth = maxResolution().Height / scaleFactorVisualHeight;
            
            //calculate cropping area for 15:9
            uint scaledBoundsWidth = maxResolution().Height;
            uint scaledBoundsHeight = (scaledBoundsWidth / 9) * 15;

            //we are starting at the top of the image
            bounds.Y = 0;
            //cropping the image width
            bounds.X = 0;
            bounds.Height = scaledBoundsHeight;
            bounds.Width = scaledBoundsWidth;

            //set finalPhotoAreaBorder values that shows the user the area that is captured
            finalPhotoAreaBorder.Width = (scaledBoundsWidth / scaleFactorVisualHeight) / rawPerViewPixels;
            finalPhotoAreaBorder.Height = (scaledBoundsHeight / scaleFactorVisualHeight) / rawPerViewPixels;
            finalPhotoAreaBorder.Margin = new Thickness(
                                            Math.Floor(((rawPixelWidth - visualWidth) / 2) / rawPerViewPixels), 
                                            0,
                                            Math.Floor(((rawPixelWidth - visualWidth) / 2) / rawPerViewPixels), 
                                            0);
            finalPhotoAreaBorder.Visibility = Visibility.Visible;

            return bounds;
        }

Again, we need to apply raw pixels to achieve the best results here (I just pasted those lines in for this sample). To calculate the correct values for our Border, we need the scale factor between the screen and the preview resolution we used (which is the scaleFactorVisualHeight double).  Before we’re calculating the border values, we are setting the Width to resolution’s Height (we rotated, remember?) and calculate the matching 15:9 Height.

The Border values are based on the Width and Height of the cropped image, but scaled down by scaleFactorVisualHeight’s value and converted in raw pixel. The Margin positions the border accordingly on top of the preview element.

This is the result of above mentioned code (screenshot of preview left, captured photo right):

15by9Photo

That’s all you need to know to get started with basic photo capturing from within your Windows Phone 8.1 Runtime app. Of course, there are also other modifications that you can apply, and I mentioned already most of the classes that lead you to the matching methods and properties (click on the links to get to the documentation)

By the way, most of the code can be adapted in a Windows 8.1 app as well (with some differences, of course).

Sample project

As promised, you can download the sample here. It contains all code snippets I showed you and is able to run as you build and deploy it.

As always, feedback is welcome and I hope this post is helpful for some of  you.

Until the next time, happy coding!

Posted by msicc in Archive, 21 comments

How to capture a photo in your Windows Phone 8.1 Runtime app-Part II: some common modifications

Like promised in my first post about photo capturing, I will provide some common modification scenarios when using the MediaCapture API. This is what this post is about.

Choosing a camera

If you read my first post, you probably remember that the MediaCapture API automatically selected the front camera of my Lumia 1020. Like often, we have to write some additional code to switch between the cameras.

The cameras are listed in the Panels in the Windows.Devices.Enumeration Namespace. This namespace contains all “devices” that are connected to the phone and has different properties to detect the correct panel. We are going to use the DeviceClass to detect all video capture devices (which are normally also the photo capture devices on Windows Phone, but can be different on a PC/Tablet). As we want to switch between Front and Back, we are also detecting the EnclosureLocation. Here is how I implemented it:

        private static async Task<DeviceInformation> GetCameraID(Windows.Devices.Enumeration.Panel camera)
        {
            DeviceInformation deviceID = (await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture))
                .FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == camera);

            return deviceID;
        }

To make this Task actually useful, we are also updating the InitializePreview() method from the first part:

        private async void InitializePreview()
        {
            captureManager = new MediaCapture();

            var cameraID = await GetCameraID(Windows.Devices.Enumeration.Panel.Back);

            await captureManager.InitializeAsync(new MediaCaptureInitializationSettings
            {
                StreamingCaptureMode = StreamingCaptureMode.Video,
                PhotoCaptureSource = PhotoCaptureSource.Photo,
                AudioDeviceId = string.Empty,
                VideoDeviceId = cameraID.Id,
            });

            StartPreview();
        }

In this case, we  selected the back camera. To make the MediaCapture API actually use this device, we need to generate a new instance of MediaCaptureInitializationSettings, where we select the cameras Id as VideDeviceId. If you now start capturing, this is an exemplary result:

wp_ss_20141115_0001

Rotating the preview

However, this not quite satisfying, because the preview automatically uses the landscape orientation. Luckily, this can be changed with just one single line of code (that needs to be added before actually starting the preview):

captureManager.SetPreviewRotation(VideoRotation.Clockwise90Degrees);

Now the result looks like this:

wp_ss_20141115_0002

Note: the black bands on both sides may happen due to the fact that most devices have a 15:9 ratio (WXGA, WVGA). On Devices like the Lumia 830 or 930, which have a 16:9 ratio, the preview will use the full screen in portrait mode. I tried a lot of things to get rid of those bands already, sadly without success. Once I found a proper solution, I will write another blog post and link it here on how to do it (any tips are welcome).

Limiting resolution

Sometimes, we need to limit resolutions (for example resolution limits on other parts in our app). This is possible by detecting the supported solutions and matching them to the screen ratio. As we are using the whole screen for previewing, of course we want to get our captured photo to use the same space, too.

My way to do this is to calculate the screen ratio, and return an enumeration value. This is the easiest way, and can be easily used in the further code to limit the resolution. The enumeration looks like this:

public enum CameraResolutionFormat
{
    Unknown = -1,

    FourByThree = 0,

    SixteenByNine = 1
}

And this is my helper to match the screen format (which is always wide screen on Windows Phone):

        private CameraResolutionFormat MatchScreenFormat(Size resolution)
        {
            CameraResolutionFormat result = CameraResolutionFormat.Unknown;

            double relation = Math.Max(resolution.Width, resolution.Height) / Math.Min(resolution.Width, resolution.Height);
            if (Math.Abs(relation - (4.0 / 3.0)) < 0.01)
            {
                result = CameraResolutionFormat.FourByThree;
            }
            else if (Math.Abs(relation - (16.0 / 9.0)) < 0.01)
            {
                result = CameraResolutionFormat.SixteenByNine;
            }

            return result;
        }

We could easily extend the calculation to 15:9, too. However, as the most camera resolutions are 4:3 or 16:9, this makes no sense in our use case (as 15:9 is still a widescreen format). The next thing we need to add is another helper to get the highest possible resolution for our photo and the preview. We are achieving this by generating a new object of type VideoEncodingProperties:

        private VideoEncodingProperties maxResolution()
        {
            VideoEncodingProperties resolutionMax = null;

            //get all photo properties
            var resolutions = captureManager.VideoDeviceController.GetAvailableMediaStreamProperties(MediaStreamType.Photo);

            //generate new list to work with
            List<VideoEncodingProperties> vidProps = new List<VideoEncodingProperties>();

            //add only those properties that are 16:9 to our own list
            for (var i = 0; i < resolutions.Count; i++)
            {
                VideoEncodingProperties res = (VideoEncodingProperties)resolutions[i];

                if (MatchScreenFormat(new Size(res.Width, res.Height)) != CameraResolutionFormat.FourByThree)
                {
                    vidProps.Add(res);
                }
            }

            //order the list, and select the highest resolution that fits our limit
            if (vidProps.Count != 0)
            {
                vidProps = vidProps.OrderByDescending(r => r.Width).ToList();

                resolutionMax = vidProps.Where(r => r.Width < 2600).First();                
            }

            return resolutionMax;
        }

What I am doing here: I read all available VideoEncodingProperties for the MediaStreamType Photo. As I mentioned before, we need only wide screen resolution for Windows Phone, that’s why I add only those that have not a 4:3 ratio to my list. Then I am using LINQ to order the list and select the highest resolution from that list.

Using this helper is also very easy, done with one line of code before starting the preview and best also before rotating the preview:

await captureManager.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.Photo, maxResolution());

This way, we are able to respect any resolution limits that we might face while developing our app, while keeping the photo quality as high as possible.

        private CameraResolutionFormat MatchScreenFormat(Size resolution)
        {
            CameraResolutionFormat result = CameraResolutionFormat.Unknown;

            double relation = Math.Max(resolution.Width, resolution.Height) / Math.Min(resolution.Width, resolution.Height);
            if (Math.Abs(relation - (4.0 / 3.0)) < 0.01)
            {
                result = CameraResolutionFormat.FourByThree;
            }
            else if (Math.Abs(relation - (16.0 / 9.0)) < 0.01)
            {
                result = CameraResolutionFormat.SixteenByNine;
            }

            return result;
        }

Focus

Focusing on objects in your photo is quite important. Sadly, it seems that currently we are not able to have a one solution fits all devices solution for using AutoFocus. I experimented a lot with it, and finally I got aware of known issues with Nokia drivers and the new MediaCapture API’s, as described here. Microsoft is working with Nokia (or their devices department) to fix this problem.

The only solution I got working for an Runtime app is to use manual focus. All other attempts gave me one Exception after the other, be it on cancelling the preview or be it on while previewing itself.  I’ll write another post on how to use the AutoFocus as soon as it is working like it should. In the meantime, here is my solution for manual focusing.

First, add a Slider control in your XAML page:

<Slider x:Name="FocusValueSlider" Maximum="1000" Minimum="0" Grid.Row="0" Margin="12,0,15,0" Header="adjust focus:" ValueChanged="FocusValueSlider_ValueChanged" Value="500" SmallChange="25" LargeChange="100" ></Slider>

Notice that as with any slider, you need to follow the order: Set Maximum first, then Minimum. If you do not, you will likely get an unusable Slider in return. If the VideoDeviceController.Focus property would work (seems like it is also affected by the above mentioned driver problems), we could read and set the Slider values from its MediaDeviceControl.Capabilities property. I tried to read them at any stage of previewing, but their values are always 0.0, null and false. The range up to 1000 fits in very well on all devices I tested (Lumia 920, 930 and 1020).

Ok, enough of whining. Let’s have a look at my solution. First, we need to generate a small helper that allows us to adjust the focus based on the slider values:

        private async void SetFocus(uint? focusValue = null)
        {
            //try catch used to avoid app crash at startup when no CaptureElement is active
            try
            {
                //setting default value
                if (!focusValue.HasValue)
                {
                    focusValue = 500;
                }

                //check if the devices camera supports focus control
                if (captureManager.VideoDeviceController.FocusControl.Supported)
                {
                    //disable flash assist for focus control
                    captureManager.VideoDeviceController.FlashControl.AssistantLightEnabled = false;

                    //configure the FocusControl to manual mode
                    captureManager.VideoDeviceController.FocusControl.Configure(new FocusSettings() { Mode = FocusMode.Manual, Value = focusValue, DisableDriverFallback = true });
                    //update the focus on our MediaCapture
                    await captureManager.VideoDeviceController.FocusControl.FocusAsync();
                }
            }
            catch { }
        }

This methods checks if the current camera supports Focus, and sets its value according to the slider. The AssistantLight is disabled in this case. Its default is enabled (true).

To add the possibility to adjust the focus, we need to configure our own FocusSettings that tell the camera that we are focusing manually based on the slider’s value. Finally, we need to perform the focusing action by calling the FocusControl’s FocusAsync method.

The next step is to hook up to changes in the slider values within the FocusValueSlider_ValueChanged event:

        private void FocusValueSlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
        {
            try
            {
                //convert double e.NewValue to uint and call SetFocus()
                uint focus = Convert.ToUInt32(e.NewValue);
                SetFocus(focus);
            }
            catch 
            {
                
            }
        }

Now every move of the slider will change the focus of the preview and of course also of the captured photo (which we will learn more about in the third post of this series).  To initialize our Focus correctly with the value of 500 we set in XAML, just call SetFocus(); before you start the preview. Here is the result:

focus screenshot

 

Disclaimer: I do not know if this follows best practices, but it works. If you have feedback for the above mentioned code snippets, feel free to leave a comment below.

In the third and last post I’ll show you how to save the images (also in different folders or only within the app).

Until then, happy coding!

Posted by msicc in Archive, 9 comments

How to capture a photo in your Windows Phone 8.1 Runtime app–Part I: the preview of the photo to capture

With the recent release of the public beta of RandR, I also learned a lot about taking photos from within an Windows Phone 8.1 app. There are several differences to Windows Phone 8, so I decided to start this three part series on how to capture a photo in your app (it would be too much for one single post).

The series will contain following topics:

The series concentrates on basic features to enable you to get started. I am adding relevant links to those posts, and at the end of the series, I will also attach a sample project.

Let’s start

Before we can use MediaCapture, please make sure that you enable Webcam and Microphone in your app’s Package.appxmanifest file. Then, we need is an Element that shows us the preview of the content we want to capture. In a Runtime app, we are using a CaptureElement for this. We also need to buttons, one to start/cancel the preview operation, and one to save the photo. Of course we want to show the photo we have taken, so we need also an image element.

Add this code to your XAML page:

<Grid>
    <CaptureElement x:Name="previewElement" Stretch="UniformToFill" />
    <Image x:Name="takenImage" Stretch="UniformToFill" Visibility="Collapsed"></Image>
</Grid>
<Grid VerticalAlignment="Bottom">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
<Button Grid.Row="0" x:Name="captureButton" Content="capture" Click="captureButton_Click" HorizontalAlignment="Stretch" Margin="12,0"/>
<Button Grid.Row="1" x:Name="saveButton" Content="save" Click="saveButton_Click" HorizontalAlignment="Stretch" Margin="12,0"/>
</Grid>

Asign the click handlers to the code behind file, where we will also continue to work now.

Before we’ll have a look at the preview code, we need to enable our app to obtain the whole screen. This makes all sense, as we want to capture a photo, and of course we want to see as much as possible in the preview. Add these two lines to the constructor of the page:

var appView = Windows.UI.ViewManagement.ApplicationView.GetForCurrentView();
appView.SetDesiredBoundsMode(ApplicationViewBoundsMode.UseCoreWindow);

The ApplicationViewBoundsMode enumeration has two values (UseVisible and UseCoreWindow). The later one uses the whole screen (even behind the SystemTray and also behind the BottomAppBar) and suits our needs. Only one thing to remember for your app: You need to set the Margins in this case to get your UI  right.

The preview code

Windows Runtime apps use the MediaCapture class for all photo and video capturing.

To enable your app to preview the things you want to capture, we first need to initialize the MediaCapture. We are doing this by a helper method, as we will need it in the next post to create some options for our MediaCapture. After declaring a page wide variable for the MediaCapture, add the following code to your code behind file:

       private async void InitializePreview()
       {
           captureManager = new MediaCapture();

           await captureManager.InitializeAsync();
           StartPreview();
       }

To make the initialized MediaCapture actually doing something, we also need to start the preview:

private async void StartPreview()
{

    previewElement.Source = captureManager;
    await captureManager.StartPreviewAsync();
              
    isPreviewing = true;
}

What we are doing is to set the Source of our previewElement that we declared in XAML to our captureManager and asynchronously start the preview. The isPreviewing Boolean is used to detect if we are actually previewing. We’ll need it in our method to stop the preview. This is very important. If you do not stop the preview, chances are high that you will freeze your phone or make the camera unusable for other apps, too!

To stop the preview, add this code:

private async void CleanCapture()
{
    if (captureManager != null)
    {
        if (isPreviewing == true)
        {
            await captureManager.StopPreviewAsync();
            isPreviewing = false;
        }
        previewElement.Source = null;
        captureButton.Content = "capture";
        captureManager.Dispose();
    }
}

 

We need to do a double check here: First, we need to see if we have a captureManager instance. Then, if we are previewing, we are going to stop it. If we are no longer previewing, we are setting the CaptureElement Source to null, rename our button and free all resources our captureManager used with the Dispose() method.

Now that we have everything for the preview in place, we are able to connect it to our captureButton:

private void captureButton_Click(object sender, RoutedEventArgs e)
{
    if (isPreviewing == false)
    {
        InitializePreview();
        captureButton.Content = "cancel";
    }
    else if (isPreviewing == true)
    {
        CleanCapture();
    }
}

Now we are already able to start previewing (without any options) on our phone:

wp_ss_20141114_0002

You might get similar  strange results if you start capturing. For example, the preview on my Lumia 1020 is flipped upside down and the front camera is used.

How we are going to change this, is topic of the second part.

Until then, happy coding!

Posted by msicc in Archive, 1 comment

How to generate a round image button for your Windows Phone 8.1 app (to use everywhere)

Recently, I experimented a bit because I wanted a round button that contains an image that can be used everywhere where I can add a standard button (and not just in the AppBar). I managed to get a simple style out of these experiments (sample at the end of this post).

First, you should check if you have already installed Syncfusion’s free Metro Studio (we will need it later). It is a powerful helper if you need icons, so if you do not have it, go straight ahead and download it here: http://www.syncfusion.com/downloads/metrostudio

Still here/back? Great! Ok, let’s start. In our project, generate a new button:

<Button Width="72" Height="72"></Button>

If you want your round button to have a smaller size, feel free to adjust the 72 pixels mine has to your preferred value.

The next step is to generate a new Style. Right click on the Button, and select ‘Edit Template’, followed by ‘Edit a Copy’.

Screenshot (407)

 

Set the name of your style in the next window, and save define it as an app-wide Style or on your page:

Screenshot (408)

This should open your App.xaml file and display the button as well as the newly generated style.

We are starting with our custom style modifications right at the top:

image

Set both Doubles to 0 and the Thickness to 0,0.

Next, scroll down to find the Border Element of the Button Template (closing ‘VisualStateManager.VisualStateGroups’ helps a lot).

Click on the Border element and add/adjust the ‘CornerRadius’ property. At a size of 72, the minimum value is 38 for the radius. This should be fine for most cases, but it may be higher/smaller if you are using another size. Don’t worry if your button looks like this at them moment:

image

We are going to fix it right now by setting the Height and Width properties of our Border element:

Height="{Binding Path=Height, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Width="{Binding Path=Width, RelativeSource={RelativeSource Mode=TemplatedParent}}"

This binds the Width and Height properties of our Button to the Style. Now we just need to define the Height and the Width of our Button to make it actually look really round. Setting both to 72 will result in a nice round button.

Like you can imagine, displaying text does not make a lot of sense in this case. Round Buttons should contain an image. You could add one through adding a background, but this will result in a strange looking button when it gets pressed. Also, it does not reflect changes like a color change. To solve this, we are going to add code that is able to draw a shape for us. This is achieved with the Path Class  in XAML. The Path class draws lines into a FrameworkElement like a Canvas or a Border.

To enable our Style to work with Path Data, we need to add some code before the ‘Template’ property Setter in our Style:

<Setter Property="ContentTemplate">
    <Setter.Value>
        <DataTemplate>
            <Path Stretch="Uniform"
                  RenderTransformOrigin="0.5,0.5"
                  Margin="2,6,2,2"
                  Fill="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                  Data="{Binding Path=Content, RelativeSource={RelativeSource Mode=TemplatedParent}}"></Path>
        </DataTemplate>
    </Setter.Value>
</Setter>

What does this code do? The ContentTemplate allows us to add rich content to our UIElement, the Button. To make it resuable, we are setting it up in our custom button style. The RenderTransforOrigin property value of 0.5,0.5 centers our Path drawn shape within the border. However, I found out that some shapes do not look good with that alone. That’s why I adjusted the Margin property together with it. This should fit most icon shapes, but you might adjust this for your own needs.

The most important aspects are the Fill property as well as the Data property. Binding the Fill Brush to the Foreground Brush property is necessary to reflect changes like theme changes as well as changes in the VisualState. Only this way it behaves like a native Button. Binding the Data property allows us to enter the Path string into the Content property of a button that uses our Style without any conversion. This makes it very simple to generate a button with our desired icon.

And this is where Syncfusion’s MetroStudio comes in handy. It allows you not only to generate icons as png, but also as shape in XAML. To get the relevant Data, open MetroStudio, search for your icon. Below the icon, there is an Edit Button. Tap it to open the icon settings page. On that settings page, you set up your button. Play around a little bit to get used to it (it’s pretty easy).

Once you have your desired icon on the screen, click on the </>XAML Button. Copy the highlighted part of the XAML code:

image

Back in Visual Studio, add this copied code to the Content property of our Button:

Content="F1M181.003,-1898.78L207.077,-1902.33 207.089,-1877.18 181.027,-1877.03 181.003,-1898.78z M207.065,-1874.28L207.085,-1849.1 181.023,-1852.69 181.022,-1874.45 207.065,-1874.28z M210.226,-1902.79L244.798,-1907.84 244.798,-1877.5 210.226,-1877.22 210.226,-1902.79z M244.807,-1874.04L244.798,-1843.84 210.226,-1848.72 210.177,-1874.1 244.807,-1874.04z" 
Height="72" 
Width="72"
Style="{StaticResource RoundButtonStyle}" 
VerticalAlignment="Center" 
HorizontalAlignment="Center"/>

Which will result in this nice looking round button with a Windows logo on it:

image

If you run the sample project, you can see that the Button behaves like a native Button with text. Download the sample project here.

I am pretty sure this can be improved. I will continue to play around with this, and if I have found enough optimizations, I will write another post about them. Until then, this should help you to get started with your own round button – and the best thing: you can use it like any standard button wherever you want in your Windows (Phone) 8.1 app!

Happy coding, everyone!

Posted by msicc in Archive, 1 comment

How to create a folder in Windows Phone 8.1 Pictures Library (and save/read files into/from it)

Some of you might have noticed that UniShare has its own folder in your devices picture library. Also some other apps like WhatsApp or Tweetium have it. The advantages of your app’s own folder are clear:

  • easier to get images into your app
  • user can always reflect which pictures come from your app
  • another presence of your app within the OS
  • higher remember rate for your app at the user site (which leads to more frequent usage of your app)

This post will show you how easy it is to generate a folder into the Pictures Library as well as save and read files into/from this folder.

Preparation

First, you need to add this using statements to your app:

using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;

Next, add the Picture Library capabilities to your app’s Package.appmanifest.

image

If you have a 8.1 Silverlight app, you need to add it to both the Package.appmanifest as well as the WMAppManifest.xml:

image

Then we are already able to generate our folder with this single line of code (counts for both Silverlight and Runtime apps):

StorageFolder appFolder= await KnownFolders.PicturesLibrary.CreateFolderAsync("myCustomAppFolder", CreationCollisionOption.OpenIfExists);

You should always use the CreateFolderAsync method together with the CollisionOption ‘OpenIfExists’. This way, your app will open it every time you are going to save a file, but creates the folder if it does not exist yet. If you now go to your pictures library, you will not see your folder yet, although it is there (use a File Manager app to check it if you want). Folders do only get populated when they have content. This is what the next step is about.

Save an image file

Saving an image is also pretty straight forward. First we are generating a StorageFile within our folder:

StorageFile myfile= await appFolder.CreateFileAsync("myfile.jpg", CreationCollisionOption.ReplaceExisting);

This generates a File Container that we can write our image to. To save the image we are going to asynchronously write the Stream of our image into it:

//asuming we have an Image control, replace this with your local code
var img = myImage.Source as WriteableBitmap;
//get fresh drawn image 
img.Invalidate();

using (Stream stream = await myfile.OpenStreamForWriteAsync())
{
   img.SaveJpeg(stream, img.PixelWidth, img.PixelHeight, 0, 100);
}

This code works for both a Windows Phone 8.1 Silverlight and Runtime apps. If you now go to your Pictures library, you will see your app’s folder as well as your saved image. Pretty easy, right?

Read images from our app’s folder

Reading an image file is pretty easy as well. Here is the code:

//open the picture library
StorageFolder libfolder = KnownFolders.PicturesLibrary;
//get all folders first
IReadOnlyList<StorageFolder> folderList = await libfolder.GetFoldersAsync();
//select our app's folder
var appfolder = folderList.FirstOrDefault(f => f.Name.Contains("myCustomAppFolder"));
//get the desired file (assuming you know the file name)
StorageFile picfile = await appPicturesFolder.GetFileAsync("myfile.jpg");
//generate a stream from the StorageFile
var stream = await picfile.OpenAsync(FileAccessMode.Read);
//generate a new image and set the source to our stream
BitmapImage img = new BitmapImage();
img.SetSource(stream);

//todo: work with the image

To get our generated folder, we need to fetch a list of folders in the library using the StorageFolder.GetFoldersAsync() method. We then query this list for our app’s folder. If you want to get a list of all pictures in your folder, you can use the StorageFile.GetFilesAsync() method. What I have done above is to load our saved single file. Finally, I opened a stream from this file and assigned it to a new BitmapImage, which can be used in our app.

There are also a lot of other options one can do with these folders and files, this is a very common scenario.

As always, I hope this post is helpful for some of you.

Posted by msicc in Archive, 0 comments

How to shorten an url with Bitly asynchronously on Windows Phone

bitly_logo

It was only yesterday when I decided to shorten shared links in UniShare. The reason is not Twitter as suggested by some of my users, but other networks like LinkedIn, that have text length limits as well.

After digging into the Bitly API, I created a little helper that returns the a shorten Bitly-url. In case this is not possible for whatever reason, it returns the long url that was tried to be shortened.

Before we can start to write some code, we need to get our generic access token for the Bitly API. Log in to your Bitly account, and click on ‘Settings’, and choose the ‘Advanced’ tab. If you already verified your mail address, you are nearly done. Enter your password and click on the ‘Generate Token’ Button:

Screenshot (388)

This is one of the constants we need soon. In your project, generate a new class called BitlyHelper. Declare the following constant strings:

private const string bitlyGenericAccessToken = "your_generic_access_token";
private const string base_url = "https://api-ssl.bitly.com/v3/shorten?access_token={0}&longUrl={1}&format=txt";

The base_url string contains the url we are calling, setting our generic access token as well as the long url we want to share. As we are only interested in getting the shortened url, we need to add the ‘format=txt’ part at the end.

The next step is to create an async Task that returns the HttpResponseMessage:

        /// <summary>
        /// Task that starts the async request for the HttpResponseMessage
        /// </summary>
        /// <param name="longUrl">the url to shorten</param>
        /// <returns>the HttpResponseMessage that contains the shortened url</returns>
        private async Task<HttpResponseMessage> getShortUrl(string longUrl)
        {
            //do not forget to UrlEncode the longUrl!
            string request_url = string.Format(base_url, bitlyGenericAccessToken, System.Web.HttpUtility.UrlEncode(longUrl));

            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.IfModifiedSince = DateTime.Now;

            //get the response from the Bitly API
            return await client.GetAsync(new Uri(request_url));
        }

The only important thing we think of here is to UrlEncode our long url, using the System.Web.HttpUtility.UrlEncode() method. If we would not do that, we would get an error on some links from the Bitly API. The rest is pretty straight forward to any other HttpClient usage.

To get our BitlyHelper to be helpful, we are creating another Task that detects the HttpStatusCode of our HttpResponseMessage and returns the shortened url:

        /// <summary>
        /// gets the shortened url out of the HttpResponseMessage
        /// </summary>
        /// <param name="longUrl">the url to shorten</param>
        /// <returns>the shortened url as string</returns>
        public async Task<string> GetShortenedUrl(string longUrl)
        {
            string short_url = string.Empty;

            //using try/catch to avoid Exceptions
            try
            {
                var response = await getShortUrl(longUrl);

                if (response.StatusCode == HttpStatusCode.Ok)
                {
                    short_url = await response.Content.ReadAsStringAsync();
                }
                //on error StatusCodes, just return the longUrl
                else
                {
                    short_url = longUrl;
                }
            }
            catch
            {
                short_url = longUrl;
            }

            return short_url;            
        }

In case the HttpStatusCode is not OK (200), we are simply returning the long url. To avoid any Exceptions, we are doing the same in case there is one. This way, we are keeping it as simple as possible while keeping our desired functionality.

The usage is very simple:

BitlyHelper bitly = new BitlyHelper();
var shorturl = await bitly.GetShortenedUrl("https://yourlongurl.com");

If you want more advanced features, you can perform the whole oAuth dance with your users and get some more features into your app (read more in the API docs). If you just need to shorten the url, this BitlyHelper is all you need.

As always, I hope this is helpful for some of you.

Happy coding!

Posted by msicc in Archive, 0 comments

Helper class to handle In-App-Products (IAP) licenses on Windows Phone (SL)

Like a lot of other apps, also UniShare got hit by an outage in the licensing system of the Windows Phone Store recently.

There was a workaround to get the licenses back from the store, but even with that, users have left negative votes (even after I posted the workaround and also wpcentral wrote about it a few days later).

The problem with those negative reviews: they tend to remain, even after responding to them (if possible) or having conversation with the users via mail. I totally understand users that are annoyed by such facts – I got hit by it as well with other apps I am using regularly. So I was thinking about a better solution as the recommended way by Microsoft, which says you should check it on every app start.

Rob Irving posted about his solution at the same day wpcentral wrote about it, which is one possible solution. His motive was the same as my solution – improving the user experience with the IAP’s.

However, I am preferring to check the licenses against the Store from time to time to make sure that the licenses are still correct.

Here is my solution (for durable IAP):

First, let’s we need to declare an object for the ListingInformation, which will hold the information that the store returns for our IAP:

ListingInformation IAPListing;

Then, we  need to create these two classes:

        public class IAP
        {
            public string Key { get; set; }

            public string Name { get; set; }

            public string Price { get; set; }

            public ProductType Type { get; set; }

            public string Description { get; set; }

            public string Image { get; set; }

            public bool IsLicenseActive { get; set; }
        }

        public class IAPToSave
        {
            public List<IAP> IAPListToSave { get; set; }

            public DateTime date { get; set; }
        }

The class IAP is the class/model that holds a single IAP item information. The second class is needed for saving the fetched IAP information (we’ll see later how I did it).

Now we have prepared these, we can finally go to the store and fetch the IAP list. I created an async Task that returns a List<IAP> for it:

        public async Task<List<IAP>> GetAllIAP()
        {
            var list = new List<IAP>();

            IAPListing = await CurrentApp.LoadListingInformationAsync();

            foreach (var product in IAPListing.ProductListings)
            {
                list.Add(new IAP()
                {
                    Key = product.Key,
                    Name = product.Value.Name,
                    Description = product.Value.Description,
                    Price = product.Value.FormattedPrice,
                    Type = product.Value.ProductType,
                    Image = product.Value.ImageUri.ToString(),
                    IsLicenseActive = isPackageUnlocked(product.Key)
                });
            }
            return list;
        }

To immediately check if our user has already purchased the item, we are getting a Boolean for it. While we are getting the data from the store, we are using this to fill our IAP class with the desired value (see IsLicenseActive property in the IAP item above).

        public bool isPackageUnlocked(string productKey)
        {
            var licenseInformation = CurrentApp.LicenseInformation;

            if (licenseInformation.ProductLicenses[productKey].IsActive)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

Now we have already all data that we need to display all IAP in our app. The usage is fairly simple:

var iapHelper = new IAPHelper();
var iapList = await iapHelper.GetAllIAP();

You can now bind the iapList to a ListBox (or your proper control/view). Next thing we are creating is our helper that performs the purchase action and returns a result string to display in a message to the user in our IAPHelper class:

        public async Task<string> unlockPackage(string productKey, string productName)
        {
            var licenseInformation = CurrentApp.LicenseInformation;

            string response = string.Empty;

            if (!licenseInformation.ProductLicenses[productKey].IsActive)
            {
                try
                {
                    //opening the store to display the purchase page
                    await CurrentApp.RequestProductPurchaseAsync(productKey);

                    //getting the result after returning into app
                    var isUnlocked = isPackageUnlocked(productKey);

                    if (isUnlocked == true)
                    {
                        response = string.Format("You succesfully unlocked {0}.", productName);  
                    }
                    else
                    {
                        response = string.Format("There was an error while trying to unlock {0}. Please try again.", productName);
                    }
                }
                catch (Exception)
                {
                    response = string.Format("There was an error while trying to unlock {0}. Please try again.", productName);
                }
            }
            else
            {
                response = string.Format( "You already unlocked {0}", productName);
            }

            return response;
        }

You may of course vary the messages that are displayed to the user to your favor.

The usage of this Task is also pretty straight forward:

var iapHelper = new IAPHelper();
string message = await iapHelper.unlockPackage(((IAPHelper.IAP)IAPListBox.SelectedItem).Key, ((IAPHelper.IAP)IAPListBox.SelectedItem).Name);

After that, we need to refresh the LicenseInformation by using GetAllIAP() again to refresh the iapList and of course our ListBox.

My goal was to save the LicenseInformation of my IAP for a limited time so the user is protected for future outages (or situations where no network connection is available). That’s why we need to add another Task to our IAPHelper class:

        public async Task<string> SerializedCurrentIAPList(List<IAP> iaplist, DateTime lastchecked)
        {
            string json = string.Empty;

            IAPToSave listToSave = new IAPToSave() { IAPListToSave = iaplist, date = lastchecked };

            if (iaplist.Count != 0)
            {
                json = await Task.Factory.StartNew(() => JsonConvert.SerializeObject(listToSave));
            }
            return json;
        }

As you can see, now is the point where we need the second class I mentioned in the beginning. It has one property for the List<IAP> and a DateTime property that we are saving. I am serializing the whole class to a JSON string. This way, we are able to save it as a string in our application’s storage.

The usage of this Task is as simple as the former ones:

var savedIAPList = await iapHelper.SerializedCurrentIAPList(iapList, DateTime.Now);

The last thing we need to create is an object that helps us indicating if a refresh of the list is needed or not. Like I said, I want to do this action time based, so here is my way to get this value:

        public bool isReloadNeeded(DateTime lastchecked, TimeSpan desiredtimespan)
        {
            bool reloadNeeded = false;

            var now = DateTime.Now;

            TimeSpan ts_lastchecked = now - lastchecked;

            if (ts_lastchecked > desiredtimespan)
            {
                reloadNeeded = true;
            }

            return reloadNeeded;
        }

This method just checks if the desired TimeSpan has passed already and returns the matching Boolean value. The usage of this is likewise pretty simple:

var savedlist = await Task.Factory.StartNew(() => JsonConvert.DeserializeObject<IAPHelper.IAPToSave>(App.SettingsStore.savedIAPList));

if (iapHelper.isReloadNeeded(savedlist.date, new TimeSpan(96, 0, 0)))
{
   //reload the list and perform your actions
}
else
{
   //use savedlist.IAPListToSave and perform your actions 
}

This way, we are able to make sure that all IAPs are available for a minimum of time and protect our users against store outages.

For your convenience, you can download the whole class right here. Just replace NAMESPACE with yours and you are good to go.

Note: I know that this approach does not follow the recommended way of Microsoft. It is up to us to deal with bad reviews if something on the store part is not working. This is my approach to avoid negative reviews because of store outages (at least for a limited time). However, like always, I hope this post is helpful for some of you.

Happy coding!

Posted by msicc in Archive, 0 comments

Prevent accidentally exit of your Windows Phone SL app (with Telerik RadMessageBox or Toolkit CustomMessageBox)

preventExit

After finally being able to use my dev center account again after three long weeks, I am back into UniShare development. One of the most requested fixes was to not exit the app when users are not at the compose pivot.

Of course I am listening and I found a solution that should fit nearly all possible scenarios. Here is what I did:

        //handle back key press to prevent accidentally exit of the app
        protected async override void OnBackKeyPress(CancelEventArgs e)
        {
            //get the base handler
            base.OnBackKeyPress(e);

            //go back to the first pivot on all other pivots
            if (MainPivot.SelectedIndex != 0)
            {
                MainPivot.SelectedIndex = 0;
                e.Cancel = true;
            }
            //handle app exit
            else if (MainPivot.SelectedIndex == 0)
            {
                //cancel the back button press
                e.Cancel = true;

                //check if bool isExitQuestionCheckBoxChecked is false and the message needs to be displayed
                if (isExitQuestionCheckBoxChecked == false)
                {
                    //show the message box
                    MessageBoxClosedEventArgs args = await RadMessageBox.ShowAsync("Do you really want to exit the app?", MessageBoxButtons.YesNo, null, "don't ask me again, just exit next time", false, true);
                    if (args.ClickedButton == null)
                    {
                        //save check box value (use IsolatedStorage on earlier versions of Windows Phone)
                        App.SettingsStore.isExitQuestionCheckBoxChecked = isExitQuestionCheckBoxChecked;
                        //go back to the app
                        return;
                        
                    }
                    if (args.ButtonIndex == 0)
                    {
                        //set the check box value
                        isExitQuestionCheckBoxChecked = args.IsCheckBoxChecked;
                        //save check box value (use IsolatedStorage on earlier versions of Windows Phone)
                        App.SettingsStore.isExitQuestionCheckBoxChecked = isExitQuestionCheckBoxChecked;
                        //exit the app
                        Application.Current.Terminate();
                        
                    }
                    if (args.ButtonIndex == 1)
                    {
                        //set the check box value
                        isExitQuestionCheckBoxChecked = args.IsCheckBoxChecked;
                        //save check box value (use IsolatedStorage on earlier versions of Windows Phone)
                        App.SettingsStore.isExitQuestionCheckBoxChecked = isExitQuestionCheckBoxChecked;
                        //go back to the app
                        return;
                    }
                }
                //check if bool isExitQuestionCheckBoxChecked is false and the app should be exited
                else if (isExitQuestionCheckBoxChecked == true)
                {
                    Application.Current.Terminate();
                }
            }
        }

 

Let me explain. The first thing I am checking is if the current PivotItem is the one I want to display the message. If not, I am moving the Pivot to it.

The next step is to show the MessageBox and handle the buttons and the CheckBox. If no button is pressed, the codes saves the value false and goes back to the app.

If the Yes-button is pressed, the code saved the value of the CheckBox and exits. Same happens for the No-button.

If the user presses the back button the next time, the isExitQuestionCheckBoxChecked boolean gets checked – if the user does not want the message and checked it, the app exits as expected.

The above snippet uses the RadMessageBox.

When we use Toolkit’s CustomMessageBox, we need a slightly different approach. First, we do not override the OnBackKeyPress event – instead, we declare a new BackKeyPress event in the page’s constructor:

public MainPage()
{
    InitializeComponent();     
    BackKeyPress += MainPage_BackKeyPress;
}

 

Then, add this code to the newly generated event handler:

        //handle back key press to prevent accidentally exit of the app
        void MainPage_BackKeyPress(object sender, System.ComponentModel.CancelEventArgs e)
        {
            //go back to the first pivot on all other pivots
            if (MainPivot.SelectedIndex != 0)
            {
                MainPivot.SelectedIndex = 0;
                e.Cancel = true;
            }
            //handle app exit
            else if (MainPivot.SelectedIndex == 0)
            {   
                ////check if bool isExitQuestionCheckBoxChecked is false and the message needs to be displayed
                if (isExitQuestionCheckBoxChecked == false)
                {
                //generate a CheckBox as Content
                CheckBox chkbox = new CheckBox()
                {
                    Content = "don't ask me again, just exit next time",
                    Margin = new Thickness(0, 14, 0, -2)
                };

                //generate msg and handle the result
                CustomMessageBox msg = new CustomMessageBox()
                {
                    Title = "Attention",
                    Message = "Do you really want to exit the app?",
                    Content = chkbox,
                    LeftButtonContent = "yes",
                    RightButtonContent = "no"
                    
                };

                msg.Dismissed += (s1, e1) =>
                    {
                        switch (e1.Result)
                        {
                            case CustomMessageBoxResult.LeftButton:
                                //save check box value
                                isExitQuestionCheckBoxChecked = (bool)chkbox.IsChecked;

                                //save the check box value
                                if (IsolatedStorageSettings.ApplicationSettings.Contains("isExitQuestionCheckBoxChecked"))
                                {
                                    IsolatedStorageSettings.ApplicationSettings.Remove("isExitQuestionCheckBoxChecked");
                                }
                                IsolatedStorageSettings.ApplicationSettings.Add("isExitQuestionCheckBoxChecked", isExitQuestionCheckBoxChecked);

                                IsolatedStorageSettings.ApplicationSettings.Save();

                                //exit the app
                                Application.Current.Terminate();
                                break;
                            case CustomMessageBoxResult.RightButton:
                                //save check box value
                                isExitQuestionCheckBoxChecked = (bool)chkbox.IsChecked;

                                //save the check box value
                                if (IsolatedStorageSettings.ApplicationSettings.Contains("isExitQuestionCheckBoxChecked"))
                                {
                                    IsolatedStorageSettings.ApplicationSettings.Remove("isExitQuestionCheckBoxChecked");
                                }
                                IsolatedStorageSettings.ApplicationSettings.Add("isExitQuestionCheckBoxChecked", isExitQuestionCheckBoxChecked);

                                IsolatedStorageSettings.ApplicationSettings.Save();

                                //go back to the app
                                break;
                            case CustomMessageBoxResult.None:
                                break;
                            default:
                                break;
                        }
                    };
                    //show message
                    msg.Show();

                    //cancel all BackKey events
                    e.Cancel = true;

                }
                //check if bool isExitQuestionCheckBoxChecked is false and the app should be exited
                else if (isExitQuestionCheckBoxChecked == true)
                {
                    Application.Current.Terminate();
                }
            }
        }

 

This code is taken from a Windows Phone 8 project and does the same as the first snippet by using the Windows Phone Toolkit.

As always, I hope this is helpful for some of you.

Happy coding, everyone!

Posted by msicc in Archive, 0 comments