Saturday, May 29, 2010

MonoTouch.Dialog: Improved List Documents!

After completing my last example on listing Documents using MonoTouch, Miguel de Icaza pointed out that MonoTouch.Dialog could make it easier. He was right and below are the results.

Two ways to start off, you can add an "IPhone Window-based Project" and then add a "UINavigationController" to the "MainWindow.xib", or do the route I took and create a "iPhone Navigation based Project" and just delete the extra "RootViewController.xib" we won't be needing.



If you haven't already, download MonoTouch.Dialog (use the "Download Source" link at the top) and then add a reference to it in your project and also be sure to add a "using MonoTouch.Dialog" at the top of "Main.cs"

Below is all the code I need to place in Main.cs to do exactly what my last blog post did which used a TON of extra auto generated code. The code I added starts under the "EDITED" comment.

public class Application
 {
  static void Main (string[] args)
  {
   UIApplication.Main (args);
  }
 }

 // The name AppDelegate is referenced in the MainWindow.xib file.
 public partial class AppDelegate : UIApplicationDelegate
 {
  // This method is invoked when the application has loaded its UI and its ready to run
  public override bool FinishedLaunching (UIApplication app, NSDictionary options)
  {
   
   window.AddSubview (navigationController.View);

   
   //EDITED: this is it!!! Takes care of generating the whole Table View!
   var menu = new RootElement ("Documents"){
    new Section("") {
     from ff in System.IO.Directory.GetFiles(Environment.GetFolderPath (Environment.SpecialFolder.Personal)).ToList()
      select (Element) new StringElement (new System.IO.FileInfo(ff).Name)
    }  
   };
   var dv = new DialogViewController (menu) {
    Autorotate = true
   };
   navigationController.PushViewController (dv, true);    
   dv.Style = UITableViewStyle.Plain;
   
   
   window.MakeKeyAndVisible ();
   
   return true;
  }

  // This method is required in iPhoneOS 3.0
  public override void OnActivated (UIApplication application)
  {
  }
  
 }

You'll need to read my last blog post if you need to add some files to the "Documents" directory (there aren't any by default).

Here are the results or those 12 lines of code (yes, the last sample only had 5 lines added but these extra 7 lines eliminated LOTS of auto generated code and is much simpler):



Amazing! Miguel de Icaza and the Mono/MonoTouch crew didn't stop at the awesome achievement of bringing C# and the .NET Framework to IPhone development; with MonoTouch.Dialog they've outright made Apple and their ancient Object-C language embarrassing. If you can't see the ROI on the $400 a MonoTouch license costs, then your time isn't worth money.

Be sure to visit the MonoTouch.Dialog page on Github and Miguel's blog post on it for more amazingness!

MonoTouch - List Documents

Use the following MonoTouch code to easily list all the files in your Applications Documents folder. First create a regular IPhone Navigation based Project.


Open "RootViewController.xib.cs" and add the following code. I only added five lines of code. I've put a "//EDITED:" comment in front of each line that I added. Make sure to add a "using System.Linq" to the top of the file as well.


partial class RootViewController : UITableViewController
 {
   //EDITED: list to hold file names.
  private System.Collections.Generic.List<string> dataItems = null;

  public RootViewController (IntPtr handle) : base(handle)
  {
  }

  public override void ViewDidLoad ()
  {
   base.ViewDidLoad ();
   //Show an edit button
   //NavigationItem.RightBarButtonItem = EditButtonItem;
   
     //EDITED: build list of files.
   string path = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
     dataItems = System.IO.Directory.GetFiles(path).ToList();
   
   this.TableView.Source = new DataSource (this);
  }

  /*
  public override void ViewWillAppear (bool animated)
  {
   base.ViewWillAppear (animated);
  }
  */
  /*
  public override void ViewDidAppear (bool animated)
  {
   base.ViewDidAppear (animated);
  }
  */
  /*
  public override void ViewWillDisappear (bool animated)
  {
   base.ViewWillDisappear (animated);
  }
  */
  /*
  public override void ViewDidDisappear (bool animated)
  {
   base.ViewDidDisappear (animated);
  }
  */

  /*
  // Override to allow orientations other than the default portrait orientation
  public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
  {
   //return true for supported orientations
   return (InterfaceOrientation == UIInterfaceOrientation.Portrait);
  }
  */

  public override void DidReceiveMemoryWarning ()
  {
   // Releases the view if it doesn't have a superview.
   base.DidReceiveMemoryWarning ();
   
   // Release any cached data, images, etc that aren't in use.
  }

  public override void ViewDidUnload ()
  {
   // Release anything that can be recreated in viewDidLoad or on demand.
   // e.g. this.myOutlet = null;
   
   base.ViewDidUnload ();
  }

  class DataSource : UITableViewSource
  {
   RootViewController controller;

   public DataSource (RootViewController controller)
   {
    this.controller = controller;
   }

   public override int NumberOfSections (UITableView tableView)
   {
    return 1;
   }

   // Customize the number of rows in the table view
   public override int RowsInSection (UITableView tableview, int section)
   {
    //EDITED: return count of files.
    return controller.dataItems.Count();
   }

   // Customize the appearance of table view cells.
   public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
   {
    string cellIdentifier = "Cell";
    var cell = tableView.DequeueReusableCell (cellIdentifier);
    if (cell == null) {
     cell = new UITableViewCell (UITableViewCellStyle.Default, cellIdentifier);
    }
    
    // EDITED: Configure the cell.
       cell.TextLabel.Text = (new System.IO.FileInfo(controller.dataItems[indexPath.Row])).Name;
   
    return cell;
   }

   /*
   // Override to support conditional editing of the table view.
   public override bool CanEditRow (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
   {
    // Return false if you do not want the specified item to be editable.
    return true;
   }
   */
   /*
   // Override to support editing the table view.
   public override void CommitEditingStyle (UITableView tableView, UITableViewCellEditingStyle editingStyle, MonoTouch.Foundation.NSIndexPath indexPath)
   {
    if (editingStyle == UITableViewCellEditingStyle.Delete) {
     controller.TableView.DeleteRows (new NSIndexPath[] { indexPath }, UITableViewRowAnimation.Fade);
    } else if (editingStyle == UITableViewCellEditingStyle.Insert) {
     // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
    }
   }
   */
   /*
   // Override to support rearranging the table view.
   public override void MoveRow (UITableView tableView, NSIndexPath sourceIndexPath, NSIndexPath destinationIndexPath)
   {
   }
   */
   /*
   // Override to support conditional rearranging of the table view.
   public override bool CanMoveRow (UITableView tableView, NSIndexPath indexPath)
   {
    // Return false if you do not want the item to be re-orderable.
    return true;
   }
   */

   // Override to support row selection in the table view.
   public override void RowSelected (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
   {
    // Navigation logic may go here -- for example, create and push another view controller.
    // var anotherViewController = new AnotherViewController ("AnotherView", null);
    //controller.NavigationController.PushViewController (anotherViewController, true);
   }
  }
 }

By default your app won't have any files in the documents folder but you can manually add some. In you user accounts "~/Library/Application Support/IPhone Simulator/" directory there will be multiple folders for each version of IPhone OS you can test. Pick the one you'll be test and put some files in the "Documents" folder.


Once that is done you can run your application in the simulator and it should give you the list of files you added to the "Documents" folder. Pretty simple huh?



I'll be using this code in a prototype that uploads Cycorder recordings from my IPhone 3G (I have a separate app for 3GS to use the built-in video recording) to Qwikcast, my company's WebCast presentation software. I'll be using SSH to create a symbolic link so Cycorder saves it's recordings to my applications Documents folder. Then I'll be doing a HTTP Upload to the Qwikcast web server where the video will automatically be encoded, published to a streaming media server, and then available on a "catalog" page for viewing (iPad and iPhone compatible of course) !

Friday, May 7, 2010

Custom iPhone Mount for Evo

Since I was rarely using my Griffin iPhone 3G windshield mount, due to always removing it when parked because I try not advertise I have stuff in my car and I think it's technically illegal in MN to have one, I decided I'd like my iPhone mounted on the dash. Well I think I found a pretty decent spot. See the slide show below for how it was made or if you don't have flash visit my Picasa web album. Read the captions on the photos for more details.


More discussion here on EvoMN.

Monday, April 19, 2010

Printers Suck

Tried to install a consumer, all-in-one printer for the first time in a loooonnnnggggg time tonight. All I can say is WOW! Are we moving backwards in regards to easy of use? How would someone who is not in IT ever use this thing? The printer is a HP C4580 and I'm running Windows 7 Enterprise. What a disaster install. First attempt a "fatal error" happened during the installation itself, but it "found a solution" or at least that's the lie it wanted to stick to. After I finally got the computer to connect to the printer over WiFi, I tried to launch "Solution Center" and it came up with another error and would not launch. Tried to re-run the installer like it suggested and the only option presented was to uninstall which sounded like a great idea to me! The funnest part of the process were the no-warning reboots HP decided to include with the installer. Nothing like hitting Ok and then watching all your windows close.

There is a reason I hate hard copy and avoid printing documents and it's name is HP (printers). I've hated printers ever since I stared using computers and my hatred is completely renewed for at least another 5.

Better go. I have one more program to uninstall (why it left one behind after saying it would uninstall "everything" is beyond me) which I'm guessing will cause a reboot so better publish now. Way to go HP! You suck!

Friday, April 16, 2010

Visa Fail with Authorize.NETs CIM

Just heard from a client that their "Save Credit Card" feature stopped working. They use Authorize.NET's Customer Information Manager (CIM) to securely save the credit cards.

Suddenly the application was just returning:
3,1,290,There is one or more missing or invalid required fields.
Why two, large, successful companies like VISA and Authorize.NET can't tell you which fields they want is beyond comprehension.

According to this message thread:
Visa has a mandate in place that allows us to do $0.00 authorizations to test the validity of a card, but in order to do it they require that an address be passed also. Since VISA is the only company that has this policy, the other card types will be unaffected and not experience the same error.
Up until recently they only required Card Number, Expiration, and Security Code. I tried using a dummy address like the message thread suggested. This would only work if the Authorize.NET Address Verification Service settings were configured to ignore the address, so in my case we'll likely be updating the code to pass the billing address in since we have it anyway.

Thanks for the notice on this VISA and Authorize.NET! You have to wonder how much time and money changes like this cost all the organizations affected?

Monday, April 12, 2010

SQL Service Broker Compatibility Level Issue

Spent about 3 hours troubleshooting why SQL Service Broker wouldn't work in production when it was working fine on two dev boxes with nearly identical configurations. The only indication there was an issue was that as soon as I'd create a Subscription the OnChange event would fire.

The SqlNotificationEventArgs contained the following:
Type:Subscribe
Source:Statement
Info:Options

Finally got a clue as to what this meant from these two sources:

1) The quote below from this page at MSDN clued me in that my TSQL was not valid (which meant there must be more to the story since the same statement works in dev)
Statement : The Transact-SQL statement is not valid for notifications; for example, a SELECT statement that could not be notified or a non-SELECT statement was executed.
2) I focused in on why SQL Server didn't like my "SET OPTIONS" and found the quote below from this page
I ran a compare between the two databases.

The local one, in 80-compatibility, needed the various SET options.

The remote one, in 90-compatibility, needed nothing extra to work.

When I changed the local one to 90-compatibility, the program magically worked, with or without the SET options.

Then I realized the Production environment had been upgraded from SQL 2000 in the past and it was likely I was running in "80-compatibility". Sure enough I was, and changing to "90-compatibility" fixed my issues as well!

3 hours down the drain but learned a little more about Service Broker debugging and troubleshooting.

Service Broker Troubleshooting by Jeremy Kadlec was excellent and so was Using and Monitoring SQL 2005 Query Notification by Sanchan Sahai Saxena

Note to self: Use SQL Server Profiler more.

Friday, April 2, 2010

Message to Apple: Enough with the Terms of Service!!!

Every other time I open iTunes I have to accept a new Terms of Service. WTF? Not only does it do it every time it installs one of its frequent software updates, but when I go to update the Apps on my iPhone I get another one for the iTunes Store in the middle of trying to update my apps. And then when you accept you have to go back and re-request the app updates. Why do I buy stuff from this company? And while I'm on the topic why do I have to reboot my computer to update iTunes? It should not be installing low level drivers but apparently it does because my DVD/CD Drive under Windows 7 disappeared one day. Go here for more info:
http://support.apple.com/kb/HT2615

Either Apple is losing it or all the hype they get for such a great user experience is completely undeserved.