Pages

Monday, August 29, 2011

[How To] Disable Pivot swipe gesture in Windows Phone

If you need to disable Pivot gestures in WP7 you only need use the IsHitTestVisible  property. This property gets or sets a value that declares whether this element can possibly be returned as a hit test result from some portion of its rendered content.

If you set to true the contained area of this control can be used for hit-testing,
If set this property to false the control will not report any event when the user manipulate it.

In code, you only need mark the IsHitTestVisible property to false.

pivotControl1.IsHitTestVisible = false;

Remember that this action is not a recomended practice in Windows Phone.

Wednesday, August 24, 2011

[Code Snippet] Custom UINavigationBar back button

Back from my holidays, I come back with my weekly wednesday's code snippet.

Sometimes when we work with UINavigationcontroller we want to custom the back button for a more visual image, or just an arrow. Today let's see how to create a custom back button with our own image for the UINavigationBar.

First of all, you have to implement in viewDidLoad the next piece of code

    if ([self.navigationController.viewControllers count] > 1)
    {
        //Creating our custom back button
        UIButton *home = [UIButton buttonWithType:UIButtonTypeCustom];
        [home setTitle:@"Volver" forState:UIControlStateNormal];
       
        UIImage *homeImage = [UIImage imageNamed:@"backbutton.png"];
       
        [home setBackgroundImage:homeImage forState:UIControlStateNormal];
        home.frame = CGRectMake(0, 0, 80, 30);
       
        [home addTarget:self action:@selector(cancel:) forControlEvents:UIControlEventTouchUpInside];
       
        UIBarButtonItem *cancelButton = [[[UIBarButtonItem alloc]
                                          initWithCustomView:home] autorelease];
        self.navigationItem.leftBarButtonItem = cancelButton;
    }
After that, we just have to implement the selector to pop the view controller and back to the previous one:

-(IBAction)cancel:(id)sender{
    [self.navigationController popViewControllerAnimated:YES];
}
And that's all. Now you can improve your UI with a custom back button. Enjoy it

Tuesday, August 23, 2011

Windows Phone SDK 7.1 Release Candidate

The Windows Phone Software Development Kit (SDK) 7.1 provides you with all of the tools that you need to develop applications and games for both Windows Phone 7.0 and Windows Phone 7.5 devices. This download is the Release Candidate (RC) and provides a ‘Go Live’ license that enables you to develop and publish applications to the Windows Phone Marketplace.

The Windows Phone SDK includes the following

  • Windows Phone SDK 7.1 (RC)
  • Windows Phone Emulator (RC)
  • Windows Phone SDK 7.1 Assemblies (RC)
  • Silverlight 4 SDK and DRT
  • Windows Phone SDK 7.1 Extensions for XNA Game Studio 4.0
  • Microsoft Expression Blend SDK for Windows Phone 7
  • Microsoft Expression Blend SDK for Windows Phone OS 7.1
  • WCF Data Services Client for Window Phone
  • Microsoft Advertising SDK for Windows Phone

 

You can download this tools here: Windows Phone SDK 7.1 RC

Monday, August 22, 2011

[How To] Scroll a ListView from code

Scroll a ListView from code, sometimes could be a headache, but you only need do this in the next way.

public MainPage()
{
    InitializeComponent();
    miListBox.Loaded += new RoutedEventHandler(miListBox_Loaded);
}

void miListBox_Loaded(object sender, RoutedEventArgs e)
{
    miListBox.SelectedIndex = 14;

    miListBox.ScrollIntoView(miListBox.SelectedItem);
}

The key of this Tip is that you must call ScrollIntoView Metod after loading ListView control.

 

Regards!

Monday, August 15, 2011

[How to] Discover User Agent in Windows Phone

As you know, we can recover the UserAgent from web browser using javascript, specifically using the navigator object. With this object we can see the platform version, user agent and other properties of our browser, in this case we will use the navigator.userAgent property.

Windows Phone do not allow us exec javascript in native mode, but we can do this inside a WebBrowser control, for this, you can follow these setps:

1) Add a WebBrowser control to our PhoneApplication page.
2) Using the function NavigateToString to load the script,  you can see the script in the example showed below.
3) Finally we intercept the ScriptNotify event from WebBowser control and we will process and store the value in the IsolatedStorage for when we need.

Declare a WebBroser control.

private WebBrowser webBrowserControl;

In the constructor of our PhoneApplicationPage, instance and add the control.

        public ManiPage()
        { 
            (…) 
            control.Loaded += new RoutedEventHandler(webBrowserControl_Loaded);

            webBrowserControl = new WebBrowser();
            webBrowserControl.IsScriptEnabled = true;
            webBrowserControl.Visibility = System.Windows.Visibility.Collapsed;
            webBrowserControl.ScriptNotify += new EventHandler<NotifyEventArgs>(webBrowserControl_ScriptNotify);
            contentPanel.Children.Add(webBrowserControl);
        }

When the WebBrowser control is loaded completely, we will load the scritp using NavigateToString function.

        void webBrowserControl_Loaded(object sender, RoutedEventArgs e)
        {
            string html = @"<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.01 Transitional//EN"">
                <html>
                <head>
                <script language=""JavaScript"" type=""text/JavaScript"">
                function getUserAgent() {
                    window.external.notify(navigator.userAgent);
                }
                </script>
                </head>
                <body onload=""getUserAgent();""></body>
                </html>";

            webBrowserControl.NavigateToString(html);
        }

Finally process the ScriptNotifi event and recover the UserAgent value. The format of UserAgent looks like this (in this case the User Agent of a Windows Phone Emulator)

Mozilla/4.0 (compatible; MSIE 7.0; Windows Phone OS 7.0; Trident/3.1; IEMobile/7.0; Microsoft; XDeviceEmulator)

void webBrowserControl_ScriptNotify(object sender, NotifyEventArgs e)

    _userAgent = e.Value;  
    System.IO.IsolatedStorage.IsolatedStorageSettings.ApplicationSettings["UserAgent"] = _userAgent;

    if (UserAgentChanged != null)
    {
        UserAgentChanged(e.Value, new EventArgs());
    }
}

NOTE: If you want to recover this value later, you can do this:

string userAgent;
System.IO.IsolatedStorage.IsolatedStorageSettings.ApplicationSettings.TryGetValue<string>("UserAgent", out userAgent);

Wednesday, August 10, 2011

[Tutorial] Windows Azure Toolkit for iOS 1.1. Integrating iOS apps with Windows Azure

To write this article I've borrowed  Wade Wegner's article: Getting Started with the Windows Azure Toolkit for iOS which explains how to create an Azure - iOS project with Windows Azure Toolkit for iOS 1.0 and updated it because class names and method names has changed and could cause some confusion for those developers who wants to use this toolkit.

So here we go!

Unpacking the v1.0.0 library zip file

You can download the compiled storage library on github (found under downloads in https://github.com/microsoft-dpe/watoolkitios-lib).  When you upzip the zip file, you’ll find several folders:

•    /4.3-device – the library binary for iOS 4.3 (device)
•    /4.3-simulator – the library binary for iOS 4.3 (simulator)
•    /include – the headers for the library

Creating your first project using the toolkit

If you are not familiar with XCode, this is a short tutorial for getting your first project up and running. Launch XCode 4 and create a new project:


Select a View-based application and click Next.
Give the project a name and company. For the purposes of this walkthrough, we’ll call it “FirstAzureProject”. Do not include Unit Tests.


When the project opens, right click on the Frameworks folder and select “Add Files to…”


Locate the libwatoolkitios.a library file from the download package folder (from either the simulator or device folder), and add it to the Frameworks folder.



Now, click on the top most project (FirstAzureProject) in the left hand column.  Click on the target in the second column.  Click on the “Build Settings” header in the third column.  Ensure that the “All” button is selected to show all settings.
In the search box, type in “header search” and look for an entry called “Header Search Paths”:



Double-click on this line (towards the right of the line), and click on the “+” button in the lower left.



Add the path to where the folder containing the header files are located (this is the include folder from the download).  For example, "~/Desktop/v1.0.0/include" if you have extracted the folder on your desktop.  Be sure to encapsulate in quotes if you have spaces in the path.



Now, click on the “Build Phases” tab and expand the “Link Binary with Libraries” section:


Click on the “+” button in the lower left, and scroll down until you find a library called “libxml2.2.7.3.dylib”.  Add this library to your project. Don’t forget to add the header search path to /usr/include/libxml2

Testing Everything Works

Now that you’ve added all of the required references, let’s test that the library can be called.  To do this, double click on the [ProjectName]AppDelegate.m file (e.g. FirstAzureProjectAppDelegate.m), and add the following imports to the class:

#import "WAAuthenticationCredential.h"
#import "WACloudStorageClient.h"

Perform a build.  If the build succeeds, the library is correctly added to the project.  If it fails, it is recommended to go back and check the header search paths.

Assuming it builds, in the .m file, add the following declarations after the @synthesize lines:

WAAuthenticationCredential *credential;
WACloudStorageClient *client;

Now, add the following lines after the [self.window makeKeyAndVisible] line in the didFinishLaunchingWithOptions method:

credential = [WAAuthenticationCredential credentialWithAzureServiceAccount:@"ACCOUNT_NAME" accessKey:@"ACCOUNT_KEY"];
client = [WACloudStorageClient storageClientWithCredential:credential];
[client fetchBlobContainersWithCompletionHandler:^(NSArray* containers, NSError* error)
{
if (error)
{
NSLog(@"%@",[error localizedDescription]);
}
else
{
NSLog(@"%i containers were found…",[containers count]);
}
}];

Maybe you could be more used to work with delegates, so, in this case you have to implement in your class <WACloudStorageClientDelegate> and sets your client’s delegate property to self and invoke fetchBlobContainers.


    storage.delegate = self;
    [client fetchBlobContainers];

Once you’ve done this you have to implement two methods, first one is to handle is an error occurs or the request fails, and this method is common for any action accomplished with our WACloudStorageClient object and second one is called when the WABlobContainer list is retrieved.

- (void)storageClient:(WACloudStorageClient *)client didFailRequest:(NSURLRequest *)request withError:(NSError *)error
{
    NSLog(@"%@", [error description]);
}

- (void)storageClient:(WACloudStorageClient *)client didFetchBlobContainers:(NSArray *)containers
{
    NSLog(@"%i Blob containers found", [containers count]);   
}

Be sure to replace ACCOUNT_NAME and ACCOUNT_KEY with your Windows Azure storage account name and key, available on the Windows Azure portal

Build and run the project.  You should something similar to the following output in the debug window:

2011-05-06 18:18:46.001 FirstAzureProject[27456:207] 2 containers were found…

The last line shows that this account has 2 containers.  This will of course vary, depending on how many blob containers you have setup in your own Windows Azure account.

Doing more with the toolkit

Feel free to explore the class documentation to explore more of the toolkit API.  To help, here are some additional examples:

In [ProjectName]AppDelegate.m class, add the following headers:

#import "WAAuthenticationCredential.h"
#import "WACloudStorageClient.h"
#import "WABlobContainer.h"
#import "WABlob.h"
#import "WAAableEntity.h"
#import "WATableFetchRequest.h"
In the didFinishLaunchingWithOptions method, after the [self.window makeKeyAndVisible] line, try testing a few of the following commands.  Again, running the project will return results into the debugger window.
To authenticate using account name and key:

credential = [WAAuthenticationCredential credentialWithAzureServiceAccount:@"ACCOUNT_NAME" accessKey:@"ACCOUNT_KEY"];
To authenticate instead using the proxy service from the Windows Phone 7 toolkit, you can use the following:
credential = [WAuthenticationCredential authenticateCredentialWithProxyURL:[NSURL URLWithString:@"PROXY_URL"] user:@"USERNAME" password:@"PASSWORD" password:withCompletionHandler:^(NSError *error)
{
if (error)
{
NSLog(@"%@",[error localizedDescription]);
}
else
{
NSLog(@"Successfully logged in");
}
}];
Replace the PROXY_URL, USERNAME, and PASSWORD with the information required to access your proxy service.

Once again, if you prefer using delegates instead of handlers you must implement WAAuthenticationDelegate and chage the method invoked.

[WAAuthenticationCredential authenticateCredentialWithProxyURL:[NSURL URLWithString:proxyURL] user:usernameField.text password:passwordField.text delegate:self];

After that we have to implement  both methods -loginDidSucceed which will be invoked if the login is succeed and loginDidFailWithError: if the login isn’t.

- (void)loginDidSucceed
{
    Azure_Storage_ClientAppDelegate        *appDelegate = (Azure_Storage_ClientAppDelegate *)[[UIApplication sharedApplication] delegate];

    StorageTypeSelector *newController = [[StorageTypeSelector alloc] initWithNibName:@"StorageTypeSelector" bundle:nil];
    newController.navigationItem.title = @"Storage Type";
    [appDelegate.navigationController pushViewController:newController animated:YES];
    [newController release];
}

- (void)loginDidFailWithError:(NSError *)error
{

    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Login Error" message:[NSString stringWithFormat:@"An error occurred: %@", [error localizedDescription]] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
    [alertView show];
    [alertView release];
    proxyURLField.text = @"";
    usernameField.text = @"";
    passwordField.text = @"";
}
To create a new client using the credentials:

client = [WACloudStorageClient storageClientWithCredential:credential];


To list all blob containers (this method is not supported via the proxy server):

// get all blob containers
[client fetchBlobContainersWithCompletionHandler::^(NSArray *containers, NSError *error)
{
if (error)
{
NSLog(@"%@",[error localizedDescription]);
}
else
{
NSLog(@"%i containers were found…",[containers count]);
}
}];
To get all blobs within a container (this also is not supported by the proxy):
// get all blobs within a container
[client fetchBlobs:@"images" withBlock:^(NSArray *blobs, NSError *error)
{
if (error)
{
NSLog(@"%@",[error localizedDescription]);
}
else
{
NSLog(@"%i blobs were found in the images container…",[blobs count]);
}
}];
To get all tables from storage (this works with both direct access and proxy):
// get all tables
[client fetchTablesWithCompletionHandler:^(NSArray* tables, NSError* error)
{
if (error)
{
NSLog(@"%@",[error localizedDescription]);
}
else
{
NSLog(@"%i tables found",[tables count]);
}
}];
To create a table (works with both direct access and proxy):
// create table
[client createTableNamed:@"wadestable" withBlock:^(NSError *error)
{
if (error)
{
NSLog(@"%@",[error localizedDescription]);
}
else
{
NSLog(@"Table created");
}
}];
To delete a table (works with both direct access and proxy):
//delete a table
[client deleteTableNamed:@"wadestable" withBlock:^(NSError *error)
{
if (error)
{
NSLog(@"%@",[error localizedDescription]);
}
else
{
NSLog(@"Table was deleted");
}
}];
To get entities for a table (works with both account key and proxy):

// get entities for table developers
WATableFetchRequest* fetchRequest = [WATableFetchRequest fetchRequestForTable:@"Developers"];
[client fetchEntities:fetchRequest withCompletionHandler:^(NSArray *entities, NSError *error)
{
if (error)
{
NSLog(@"%@",[error localizedDescription]);
}
else
{
NSLog(@"%i entities found in the developer table",[entities count]);
}
}];
To get entities for a table using predicate (works with both account key and proxy):
// get entities for table developers with predicate request
NSError* error = nil;
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"Name = 'Wade' || Name = 'Vittorio' || Name = 'Nathan'"];
WATableFetchRequest* anotherFetchRequest = [WATableFetchRequest fetchRequestForTable:@"Developers" predicate:predicate error:&error];
[client fetchEntities:anotherFetchRequest withCompletionHandler:^(NSArray *entities, NSError *error)
{
if (error)
{
NSLog(@"%@",[error localizedDescription]);
}
else
{
NSLog(@"%i entities returned by this request",[entities count]);
}
}];

All of these actions could be accomplished using WACloudStorageDelegate methods instead of completion handlers. If you are interested in just have a look at the documentation to find which methods you should implement for which actions.

Doing even more with the toolkit

If you are looking to explore the toolkit further, I recommend looking at the sample application that can be found in the watoolkitios-samples project.  This project demonstrates all of the functionality of the toolkit, including creating, uploading, and retrieving entities from both table and blob storage.

Thursday, August 4, 2011

[Code Snippet] Dynamic height for UITableViewCell

Hi there, let's see a new code snippet this week that's very useful when we are loading dinamic text in UITableView cells and we don't know which its exactly lenght is, so we have to adapt both UILabel and UITableViewCell height.

First thing to do is calculate the UITableViewCell height inside heightForRowAtIndexPath:(NSIndexPath)indexPath. That's the first of the two methods that we have to implement for UITableViewDataSource protocol in order to calculate the total of cell height. Be careful because you have to add all cell heights for any control that are docked vertically.

Obtaining the text size of the label is quite easy, we only have to specify the label widht, the font size, line break mode and text content, and we'll obtain a CGSize variable storing the label size.
   
    CGSize labelSize = CGSizeMake(labelWidth, 20000.0f);
    CGSize textSize = [@"Lorem ipsum dolor" sizeWithFont:[UIFont systemFontOfSize: 12.0f] constrainedToSize:labelSize lineBreakMode:UILineBreakModeWordWrap];
   
    cellHeight = textSize.height + 21.0f + 30; //Adding other control heights
   
    return cellHeight;
Next, you have to implement cellForRowAtIndexPath method for dinamic resizing of the UILabel which shows our text. Using the same method described before you can set label's frame to show text completely.

    UILabel *textDescription = (UILabel*)[cell viewWithTag:3];
    textDescription.text = @"Lorem ipsum dolor...";
    CGSize labelSize = CGSizeMake(labelWidth, 20000.0f);
    CGSize textSize = [rssItem.descripcion sizeWithFont:[UIFont systemFontOfSize: 12.0f] constrainedToSize:labelSize lineBreakMode:UILineBreakModeWordWrap];
    [txtDescripcion setFrame:CGRectMake(13.0f, 45.0f,
                                          labelWidht, textSize.height)];

And that's all to dynamic resizing of UILabels and UITableViewCells for show unknow length text. I hope this had helped you

NOTE: A good practise is to have the label widht defined as a constant, in our case labelWidth.