This is the final post at this location. The new location of the blog is www.rajapet.com. Visit me there!
All of the existing content has been moved over. This version of the blog will be around for a while, but nothing new will happen here.
Christopher Miller's random thoughts
Semi-random notes on programming, adoption, and life in general
Tuesday, December 10, 2013
Thursday, December 05, 2013
A work around for the files in use bug with HeatDirectory in MSBuild
I have this multi-project solution in Visual Studio 2013 and one of the projects is a Windows Installer project. It uses WiX (Windows Installer XML) 3.8 and when I rebuild the solution, the final result is a nice .MSI file that will install the executable bits from the other projects.
To get the files that need to be bundled with the installer, I copy the files that I need from the project bin folders to a folder in the WiX project named “files”. This folder is not part of the project or the solution and is not in source control. I started out with a prebuild event of the WIX project that did the following:
With Windows Installer, every object that gets installed has to be defined in a WiX source file. You get end up with stuff that looks like:
Which is hideous to do by hand. You can run heat.exe on a folder and it will generate that the include file for all the files in that folder for you. In my prebuild event, I had the following lines:
The 5th line is the heat command line. The various command line options are documented here. This ran without any problems on my dev machine. Hilarity ensued when I tried to make a build from our TFS server. I was getting build errors when it executed heat.exe
That was annoying. During the build, heat was recreating the adminfiles.wxs file each time. Since that file was in source control, it was set to read only on the build server. That caused heat.exe to abort out since it couldn't recreate that file. Our build engineer suggested using the attrib command to clear the read only bit. The light bulb (LED, should last longer than incandescent) flickered above my head and I realized that since that file was in source control, I didn't need to created it on the build server. I just needed to set the build so that heat didn't run on the build server.
There are probably a few ways of doing this, I went with setting it up so that heat would only get run for debug builds. Our build server is only doing release builds, this would work for me. So I moved the prebuild code out of the project property settings and implemented them as individual MSBuild tasks.
The first part of doing that was to install the MSBuild Extension Pack from CodePlex. I did that to get a RoboCopy task for MSBuild. Robocopy is very powerful tool for copying and synching up files, but has this one little quirk. It return 1 as a success code. Everything else on Planet DOS returns 0 for success and non-zero values to indicate an error. The MSBuild.ExtensionPack.FileSystem.RoboCopy task knows about that quirk and prevents MSBuild from reporting a robocopy success code as an error. Lots of good stuff in the Extension Pack, you'll want to have one in your toolbelt.
When you install WIX, you get WIX specific extensions for MSBuild. The task for heat is called HeatDirectory. The HeatDirectory equivalent of the heat.exe command line that I was using looks like this:
The first element is Condition, which is comes with MSBuild. By setting the value to " '$(Configuration)|$(Platform)' == 'Debug|x86' " , MSBuild will only execute that task when the condition evaluates to true.
That worked perfectly, but only for the first time. After doing one debug build, the next build bombed out on the RoboCopy task. There was a problem with the files being in use. If I restarted VS, I could do another build. If I commented out the HeatDirectory task, the build would work. I went to the WIX site and sure enough, this was a known bug. The heat.exe was keeping the file handles open for the files that it read.
By default, HeatDirectory was running heat.exe from within the Visual Studio process. This was the fast way to execute heat, but you pick up any handle heaks from the heat.exe. In one of the comments to the bug report, a work around was suggested. Add RunAsSeparateProcess="true" to HeatDirectory. This forces heat.exe to be run as a separate process and the leaked handles get flushed when that process ends.
That took care of the problem. While this is a known bug, the comments associated with that bug made it clear that it's not going toget addressed any time soon.
So what is CTT? It is a command line version of the XDT transform that Visual Studio uses when it transforms web.config from web.release.config and web.debug.config. It's another good tool.
If you are still reading this, here is the final version of the prebuild events
To get the files that need to be bundled with the installer, I copy the files that I need from the project bin folders to a folder in the WiX project named “files”. This folder is not part of the project or the solution and is not in source control. I started out with a prebuild event of the WIX project that did the following:
- Delete the files folder. I just assume that everything in the folder is obsolete
- Robocopy the deployable files from a WPF project to the files folder.
- Robocopy an ASP.Net MVC 4 project to the filles folder
- Run ctt.exe (Config Transformation Tool) to clean up the web.config file and set some default values.
- Run the WiX Harvest tool, heat.exe, to generate a .wxi include file of all of the files in the files folder.
With Windows Installer, every object that gets installed has to be defined in a WiX source file. You get end up with stuff that looks like:
Which is hideous to do by hand. You can run heat.exe on a folder and it will generate that the include file for all the files in that folder for you. In my prebuild event, I had the following lines:
The 5th line is the heat command line. The various command line options are documented here. This ran without any problems on my dev machine. Hilarity ensued when I tried to make a build from our TFS server. I was getting build errors when it executed heat.exe
heat.exe: Access to the path 'C:\Builds\31\VSTancillary\FleetVision_Dev\Sources\WixSetupProject\adminfiles.wxs' is denied.
That was annoying. During the build, heat was recreating the adminfiles.wxs file each time. Since that file was in source control, it was set to read only on the build server. That caused heat.exe to abort out since it couldn't recreate that file. Our build engineer suggested using the attrib command to clear the read only bit. The light bulb (LED, should last longer than incandescent) flickered above my head and I realized that since that file was in source control, I didn't need to created it on the build server. I just needed to set the build so that heat didn't run on the build server.
There are probably a few ways of doing this, I went with setting it up so that heat would only get run for debug builds. Our build server is only doing release builds, this would work for me. So I moved the prebuild code out of the project property settings and implemented them as individual MSBuild tasks.
The first part of doing that was to install the MSBuild Extension Pack from CodePlex. I did that to get a RoboCopy task for MSBuild. Robocopy is very powerful tool for copying and synching up files, but has this one little quirk. It return 1 as a success code. Everything else on Planet DOS returns 0 for success and non-zero values to indicate an error. The MSBuild.ExtensionPack.FileSystem.RoboCopy task knows about that quirk and prevents MSBuild from reporting a robocopy success code as an error. Lots of good stuff in the Extension Pack, you'll want to have one in your toolbelt.
When you install WIX, you get WIX specific extensions for MSBuild. The task for heat is called HeatDirectory. The HeatDirectory equivalent of the heat.exe command line that I was using looks like this:
The first element is Condition, which is comes with MSBuild. By setting the value to " '$(Configuration)|$(Platform)' == 'Debug|x86' " , MSBuild will only execute that task when the condition evaluates to true.
That worked perfectly, but only for the first time. After doing one debug build, the next build bombed out on the RoboCopy task. There was a problem with the files being in use. If I restarted VS, I could do another build. If I commented out the HeatDirectory task, the build would work. I went to the WIX site and sure enough, this was a known bug. The heat.exe was keeping the file handles open for the files that it read.
By default, HeatDirectory was running heat.exe from within the Visual Studio process. This was the fast way to execute heat, but you pick up any handle heaks from the heat.exe. In one of the comments to the bug report, a work around was suggested. Add RunAsSeparateProcess="true" to HeatDirectory. This forces heat.exe to be run as a separate process and the leaked handles get flushed when that process ends.
That took care of the problem. While this is a known bug, the comments associated with that bug made it clear that it's not going toget addressed any time soon.
So what is CTT? It is a command line version of the XDT transform that Visual Studio uses when it transforms web.config from web.release.config and web.debug.config. It's another good tool.
If you are still reading this, here is the final version of the prebuild events
Monday, October 07, 2013
Taking the Acer W3 from Preview to RTM
It was time to install Windows 8.1 on my Acer Iconia W3-810. I received the tablet at the Build conference. The W3 came with the 32-bit edition of Windows 8 and Microsoft provided a USB drive with preview copies of Windows 8.1 for it and the Surface Pro. I had installed the preview version of Windows 8.1. With the availability of Windows 8.1 RTM on MSDN, I decided to repave the Acer with a fresh 8.1 install
The first thing I did was download the ISO image. I needed the 32 bit version, the Atom Z2760 processor on the Acer is a 32-bit CPU. Next step was to get the latest drivers for the Acer. Headed over to the Drivers and Manuals page on the Acer site and searched for "W3-810". This brought up all of the files available for the W3.
There is a BIOS update and a Driver Package download. I grabbed them both. I downloaded the BIOS update to the desktop on the Acer and ran it. It rebooted and installed itself with out any issue. I didn't see any release notes with the BIOS update, but the tablet was fine after installing it. The BIOS upgrade may have been moot, when I installed the Drive Package later on, it did a BIOS update with a newer version.
I chose to repave the W3 and do a clean install. Windows 8.1 does not come with the touch screen drivers for W3. That's why I downloaded them ahead of time. If you do this, get a USB hub and a spare USB mouse and keyboard, this will make life much easier for the upgrade.
There is a hidden folder on the c: partition named c:\oem, make a backup copy of it just in case something goes wrong. That has a bunch of Acer specific files and it should have a copy of the Office 2013 installer.
One more file I needed to get was the Windows 7 USB/DVD Download Tool. Ignore the "Windows 7" part of the title, it works just fine with Windows 8. This tool makes it easy to make a bootable USB drive from an ISO file.
When you download/install/run this tool, it will prompt you for the ISO file and then ask if you want do a USB hard drive or a USB DVD. Pick the hard drive option and let it reformat the drive. It will then make the drive bootable and extract the ISO image to the drive. I used this to make the /Build drive a bootable Win 8.1 boot disk. It turned out that I didn't need to make the drive bootable, but it's good to know to do it.
With the drive now a bootable bucket of 32 bit Windows 8.1 joy, I then copied the contents of the driver package ZIP that I had downloaded from the Acer site to the thumbdrive. I had what I needed to upgrade the Acer. I went into the Acer BIOS and changed the boot order so that it would boot from an external drive first. To get into the BIOS screen, reboot the Acer and press the F2 key on the USB keyboard. You can get into the BIOS by holding the up volume button while pressing the power button. But since you'll need the USB keyboard, you might as well start off with it attached.
There is probably more than one way to do this, and I hope an easier one. To get the Acer to install from the USB, I had to boot into recovery mode. Press and hold the power button and the Windows button as it boots up. That should boot up into the Windows 8.1 Troubleshooter. It will ask you for your language. On the next screen, select the "Troubleshoot" option. On the Troubleshoot screen, select "Advance Options". I then selected "Command line prompt"
This opened up a cmd.exe shell. From here, I switched to the D: drive and ran setup.exe. This started the Windows 8.1 install. From that point on, it was just like installing the OS as a new install on any other machine. When it prompts you for a destination partition, choose the largest one, it should be about 48Gb in size on this model.
After a long while, the Acer booted up into Windows 8.l, RTM. The touch drivers will need to be installed. I went to the Windows Desktop and use Explorer to access the thumbdrive. This is where it is handy to have a keyboard and mouse connected. Then I opened the folder with the Acer drivers and ran the setup.exe. If you do this, you will see a a banner for the Intel Atom Processor drivers. Click through it and go have a sparkling beverage, it''s going to take a while. After it's was done, it will prompted to restart the tablet, on the reboot it flashed the BIOS.
After rebooting, I had touch, but I visual glitches in about half of the Windows Store apps. The text had the same color background as the foreground, making the apps unusable. Fortunately desktop mode was fine. I was able to run Windows Update and that seems to have sorted it all out.
I do need to re-install the Home & Student Edition of Office 2013 that came with the tablet. Installing 8.1 in this way will remove all the installed apps. I wanted to start with a clean slate, so I knew this going in. The installer is supposed to be in the hidden c:\oem folder, but I couldn't find it on mine. I still have the registration key, I'll either find another source for the installer or just install Office Pro.
Now that everything is in place, my last step was to remove the remaining bits of the previous version of Windows. The installer had renamed the c:\windows to c:\windows.old , and that was still there. Microsoft has a page that explains how to this.
And that's how I did a clean install install of Windows 8.1. If you have Windows 8, you shouldn't need to go through of this. The update to 8.1 will be in the Windows Store and will be a free download.
One of the nice touches with the Build giveways was that Microsoft included a 16GB USB3 flash drive. You don't get any faster performance from the USB3 drive on the Acer, but the Surface Pro has a USB3 port.
The first thing I did was download the ISO image. I needed the 32 bit version, the Atom Z2760 processor on the Acer is a 32-bit CPU. Next step was to get the latest drivers for the Acer. Headed over to the Drivers and Manuals page on the Acer site and searched for "W3-810". This brought up all of the files available for the W3.
There is a BIOS update and a Driver Package download. I grabbed them both. I downloaded the BIOS update to the desktop on the Acer and ran it. It rebooted and installed itself with out any issue. I didn't see any release notes with the BIOS update, but the tablet was fine after installing it. The BIOS upgrade may have been moot, when I installed the Drive Package later on, it did a BIOS update with a newer version.
I chose to repave the W3 and do a clean install. Windows 8.1 does not come with the touch screen drivers for W3. That's why I downloaded them ahead of time. If you do this, get a USB hub and a spare USB mouse and keyboard, this will make life much easier for the upgrade.
There is a hidden folder on the c: partition named c:\oem, make a backup copy of it just in case something goes wrong. That has a bunch of Acer specific files and it should have a copy of the Office 2013 installer.
One more file I needed to get was the Windows 7 USB/DVD Download Tool. Ignore the "Windows 7" part of the title, it works just fine with Windows 8. This tool makes it easy to make a bootable USB drive from an ISO file.
When you download/install/run this tool, it will prompt you for the ISO file and then ask if you want do a USB hard drive or a USB DVD. Pick the hard drive option and let it reformat the drive. It will then make the drive bootable and extract the ISO image to the drive. I used this to make the /Build drive a bootable Win 8.1 boot disk. It turned out that I didn't need to make the drive bootable, but it's good to know to do it.
With the drive now a bootable bucket of 32 bit Windows 8.1 joy, I then copied the contents of the driver package ZIP that I had downloaded from the Acer site to the thumbdrive. I had what I needed to upgrade the Acer. I went into the Acer BIOS and changed the boot order so that it would boot from an external drive first. To get into the BIOS screen, reboot the Acer and press the F2 key on the USB keyboard. You can get into the BIOS by holding the up volume button while pressing the power button. But since you'll need the USB keyboard, you might as well start off with it attached.
There is probably more than one way to do this, and I hope an easier one. To get the Acer to install from the USB, I had to boot into recovery mode. Press and hold the power button and the Windows button as it boots up. That should boot up into the Windows 8.1 Troubleshooter. It will ask you for your language. On the next screen, select the "Troubleshoot" option. On the Troubleshoot screen, select "Advance Options". I then selected "Command line prompt"
This opened up a cmd.exe shell. From here, I switched to the D: drive and ran setup.exe. This started the Windows 8.1 install. From that point on, it was just like installing the OS as a new install on any other machine. When it prompts you for a destination partition, choose the largest one, it should be about 48Gb in size on this model.
After a long while, the Acer booted up into Windows 8.l, RTM. The touch drivers will need to be installed. I went to the Windows Desktop and use Explorer to access the thumbdrive. This is where it is handy to have a keyboard and mouse connected. Then I opened the folder with the Acer drivers and ran the setup.exe. If you do this, you will see a a banner for the Intel Atom Processor drivers. Click through it and go have a sparkling beverage, it''s going to take a while. After it's was done, it will prompted to restart the tablet, on the reboot it flashed the BIOS.
After rebooting, I had touch, but I visual glitches in about half of the Windows Store apps. The text had the same color background as the foreground, making the apps unusable. Fortunately desktop mode was fine. I was able to run Windows Update and that seems to have sorted it all out.
I do need to re-install the Home & Student Edition of Office 2013 that came with the tablet. Installing 8.1 in this way will remove all the installed apps. I wanted to start with a clean slate, so I knew this going in. The installer is supposed to be in the hidden c:\oem folder, but I couldn't find it on mine. I still have the registration key, I'll either find another source for the installer or just install Office Pro.
Now that everything is in place, my last step was to remove the remaining bits of the previous version of Windows. The installer had renamed the c:\windows to c:\windows.old , and that was still there. Microsoft has a page that explains how to this.
- Open Disk Cleanup by swiping in from the right edge of the screen, tapping Search (or if you're using a mouse, pointing to the upper-right corner of the screen, moving the mouse pointer down, and then clicking Search), entering Disk Cleanup in the search box, tapping or clicking Settings, and then tapping or clicking Free up disk space by deleting unnecessary files.
- If you're prompted to choose a drive, select the drive that you just installed Windows on, and then click OK.
- In the Disk Cleanup dialog box, on the Disk Cleanup tab, click Clean up system files.
- If you're again prompted to choose a drive, select the drive you just installed Windows on, and then click OK.
- Select the Previous Windows installation(s) check box, and any other check boxes for the files you want to delete, and then click OK.
- In the message that appears, click Delete files.
And that's how I did a clean install install of Windows 8.1. If you have Windows 8, you shouldn't need to go through of this. The update to 8.1 will be in the Windows Store and will be a free download.
Wednesday, September 25, 2013
Today's lesson in voice mail etiquette
I just had a fun adventure in returning a wrong number voice mail. I arrived into work late today and I had a voice mail message time stamped at 10:00am. The message was the following:
However Tyler is a big enough company to have another Chris Miller. That Chris works for another division a few time zones away. He was hired a few months back and we get emails and meeting invites for each other all the time. I make sure that any communication meant for the Chris Miller is sent to intended destination.
So I went under the assumption that this call may have been for the other Chris Miller. Steve didn't say who he worked for, or where he was calling from, or even the area code. Our voice mail system lets you dial the caller back, so I did that.
When Steve answered, the conversation went more or less like this:
This is Steve F____, number 1163. I need to know what time to come in for the ____ meeting. Please call me right back at XXX-XXXXI have no idea who Steve is and we don't number our clients, we go by their school district name. We also don't any ____ meetings.
However Tyler is a big enough company to have another Chris Miller. That Chris works for another division a few time zones away. He was hired a few months back and we get emails and meeting invites for each other all the time. I make sure that any communication meant for the Chris Miller is sent to intended destination.
So I went under the assumption that this call may have been for the other Chris Miller. Steve didn't say who he worked for, or where he was calling from, or even the area code. Our voice mail system lets you dial the caller back, so I did that.
When Steve answered, the conversation went more or less like this:
Steve: Hello?Then we ended the call. If you call my number and get dumped to voice mail, you get the following message:
Me: Hi, is this Steve F____? This is Chris Miller from Tyler Technologies, and I am returning your call from 10:00 this morning
Steve: Who is this? I didn't call you
Me: You left a voice mail asking me to call XXX-XXXX
Steve: I called someone else at ZZZ-ZZZZ
Me: That is my number (and I repeated his message back to him)
Steve: I was calling ____ at the ____ company, they must have given me the wrong number.
Hi, you have reached Chris Miller at Tyler Techologies. I'm sorry I am not able to take your call right now, but if you leave your name and phone number, I'll return your call...If you are going to leave a message, please listen to the outgoing message to make sure that you have called the right person and/or company. Also, you need to leave your area code. We have customers across the country and in Canada, I do need your area code if you want me to call back.
Friday, August 23, 2013
Increasing the target area of a table's DetailDisclose button with Xamarin.iOS
Can you make that button bigger? I went slightly under the hood in Xamarin.iOS to make an accessory button target area larger.
I'm finishing up an iPad app for our fall release schedule. One of the comments that came up in testing was that it was too hard for some people to hit the detail disclosure button in the tables. I was asked to make the button larger.
What we are talking about is the standard blue circle with a white ">" in the center. Something like this:
The target area that responds to finger touches is about 44x44 pixels, centered around the button. We wanted to increase that target area to make it easier to reach. My first pass was to create new button that was a larger size. That worked, but it didn't look like the standard detail disclosure button (actually, it looked hideous, but that's another story). I prefer to use the standard iOS imagery unless I have a good reason not to. If you have spent any amount of time with an iPhone or an iPad, you have seen that button before and you know that touching it will provide you with more details. The more familiar a UI is, the less training the user will need.
I decided to take another approach. Instead of changing the image, I would make the target area around the button wider. The button will look the same, but clicking more of the white area around that button would trigger the button. And it wasn't hard to do.
We are going to looking at some Xamarin.iOS C# code. This should also work with Objective-C, just with different syntax.
I started out with a custom table cell
The constructor creates a new SubTitle cell. I then add a UIButton of type DetailDisclosure. The button then gets a new Frame that is much wider, 120px, than the default size. That will give the user a wider target to hit. Since the default is to left align the image, we need to shift the image inside the frame. For that we add a new UIImageEdgeSets, to set the margin on the drawing rectangle for the image. By setting the left inset to the new width minus the old width, we align the image to the right side of the frame.
The last thing to do is to set the AccessoryView property of the cell to the new button, that will let the default code draw the button in the right place and we do not need to know how wide the cell is at runtime. What you lose is the AccessoryButtonTapped event is no longer called, we have to handle that functionality.
The next step would be define the table. I'm using a UITableViewSource and I override the GetCell method to create the custom cell. In addition to creating the custom cell, I needed to assign a TouchUpInside event to the new button as the default accessory behavior will no longer handle that button.
With GetCell, we create or update an instance of our custom cell. When the cell gets created, I assign the table row to the Tag property of the button. Since we are not using the default code for adding a DetailDisclosure button, we have to handle the touch event. Right after the cell is created, the TouchUpInside event of the custom button gets a new delegate assign to it. I cast the sender as the UIButton and access the Tag property to get the selected row.
My code only had a single section in the table, so I only needed to track the table row. If I had needed to know the current section, I would have created a UIButton descendant and added Section and Row properties. That would make the code a little cleaner. The end result is the user gets the a button with the default look and feel, but with a larger target area.
I'm finishing up an iPad app for our fall release schedule. One of the comments that came up in testing was that it was too hard for some people to hit the detail disclosure button in the tables. I was asked to make the button larger.
What we are talking about is the standard blue circle with a white ">" in the center. Something like this:
The target area that responds to finger touches is about 44x44 pixels, centered around the button. We wanted to increase that target area to make it easier to reach. My first pass was to create new button that was a larger size. That worked, but it didn't look like the standard detail disclosure button (actually, it looked hideous, but that's another story). I prefer to use the standard iOS imagery unless I have a good reason not to. If you have spent any amount of time with an iPhone or an iPad, you have seen that button before and you know that touching it will provide you with more details. The more familiar a UI is, the less training the user will need.
On a side note: If you want to create a custom button and want to use imagery that will scale between Retina and non-Retina displays, take a look at PaintCode. I was able to take my vector based image and convert it to code and created a button that drew the imagery at runtime at the device resolution. I don't often need that tool, but I'm glad I have it.
I decided to take another approach. Instead of changing the image, I would make the target area around the button wider. The button will look the same, but clicking more of the white area around that button would trigger the button. And it wasn't hard to do.
We are going to looking at some Xamarin.iOS C# code. This should also work with Objective-C, just with different syntax.
I started out with a custom table cell
public class MyCustomCell : UITableViewCell { public UIButton detailDisclosureButton; public MyCustomCell (string Action, string Status, NSString identKey) : base (UITableViewCellStyle.Subtitle, identKey) { detailDisclosureButton = UIButton.FromType (UIButtonType.DetailDisclosure); detailDisclosureButton.Frame = new RectangleF (0f, 0f, 120f, 44f); detailDisclosureButton.ImageEdgeInsets = new UIEdgeInsets (0f, 120f - 44f, 0f, 0f); AccessoryView = detailDisclosureButton; UpdateCell (Action, Status); } public void UpdateCell(string Action, string Status) { TextLabel.Text = Action; DetailTextLabel.Text = Status; } }
The constructor creates a new SubTitle cell. I then add a UIButton of type DetailDisclosure. The button then gets a new Frame that is much wider, 120px, than the default size. That will give the user a wider target to hit. Since the default is to left align the image, we need to shift the image inside the frame. For that we add a new UIImageEdgeSets, to set the margin on the drawing rectangle for the image. By setting the left inset to the new width minus the old width, we align the image to the right side of the frame.
The last thing to do is to set the AccessoryView property of the cell to the new button, that will let the default code draw the button in the right place and we do not need to know how wide the cell is at runtime. What you lose is the AccessoryButtonTapped event is no longer called, we have to handle that functionality.
The next step would be define the table. I'm using a UITableViewSource and I override the GetCell method to create the custom cell. In addition to creating the custom cell, I needed to assign a TouchUpInside event to the new button as the default accessory behavior will no longer handle that button.
public class MyCustomTableSource : UITableViewSource { protected ListtableItems = new List (); protected string cellIdentifier = "myTableCell"; public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath) { MyCustomCell cell = (MyCustomCell)(tableView.DequeueReusableCell (cellIdentifier)); var Action = SomeMethodToReturnTitle(tableItems [indexPath.Row]); var Status = SomeMethodToReturnSubTitle(tableItems [indexPath.Row]); if (cell == null) { // Create our custom cell cell = new MyCustomCell(Action, Status, new NSString (cellIdentifier)); // Set the tag property of the button to the current row. // If you are doing sections and rows, then I would subclass the UIButton and // add Section and Row properties to make the code easier to work with cell.detailDisclosureButton.Tag = indexPath.Row; // Set the TouchUpInside event to check the button's tag property to figure out // which row triggered the event. And then do something cell.detailDisclosureButton.TouchUpInside += delegate(object sender, EventArgs e) { EditAction (tableItems[(sender as UIButton).Tag]); }; } else { cell.UpdateCell(Action, Status); } return cell; } public void EditAction(MyCustomItem thisAction) { // Do something here } }
With GetCell, we create or update an instance of our custom cell. When the cell gets created, I assign the table row to the Tag property of the button. Since we are not using the default code for adding a DetailDisclosure button, we have to handle the touch event. Right after the cell is created, the TouchUpInside event of the custom button gets a new delegate assign to it. I cast the sender as the UIButton and access the Tag property to get the selected row.
My code only had a single section in the table, so I only needed to track the table row. If I had needed to know the current section, I would have created a UIButton descendant and added Section and Row properties. That would make the code a little cleaner. The end result is the user gets the a button with the default look and feel, but with a larger target area.
Monday, July 01, 2013
Getting around 0x80073cfb errors after installing Windows 8.1 Preview
As an attendee of the //build/ conference, I received a Surface Pro and an Acer Iconia W3, along with a USB drive with the Windows 8.1 Preview update for each device. After installing 8.1, Windows Store on the Surface Pro showed that there a bunch of apps that needed updates. So I updated them all and it failed to update five of the apps:
Each one reported reported the same error code 0x80073cfb. That error code is defined as ERROR_PACKAGE_ALREADY_EXISTS (see here) and it basically means that something is wrong with the app signature. It kind of matches, but not exactly and Windows doesn't know how to proceed.
- Reader
- Windows Alarms
- Windows Calculator
- Windows Reading List
- Windows Sound Recorder
Under the app name, there was the message "This app wasn't installed - view details.". When you click on the message, a dialog would come up with the following message:
Something happened and this app couldn't be installed. Please try again. Error code: 0x80073cb
You got two buttons, "Try again" and "Cancel install".
The simplest way around this is to uninstall the version that is already on the machine and then install it again from the Windows Store. It's annoying, but doesn't take that long. I did it the following way:
I would love to find a way to script this with Power Shell. What would be nice would be if the Windows Store app would give you an uninstall/reinstall option when it encounters 0x80073cfb errors. I'm not the only person seeing this and it's happening with the Acer, just with a different set of apps. On Acer, it gets that error with these apps:
There is some overlap, but only with 2 of the apps. With the Acer, I found that if I burned Alarms, Help, and Reading List, the Bing apps installed normally. I also had the same problem with the HP Envy 23 that I bought last December. I had to burn the village to save the village on that machine too.
The burning village image comes from The Witcher 3 Set, from the Flickr feed of Gameranx.
- Run the Windows Store app and have it try to update the apps
- Get the errors and while on the "Installing apps" screen, then press the Win key to get back the Metro screen
- Start typing the app name. When the app appears, do a long press to get the options menu and select uninstall.
- Go back to the Windows Store app and click on the app that you deleted. You'll see the "Something happened" dialog, click the "Try again" button.
- The app should install without any problems now.
I would love to find a way to script this with Power Shell. What would be nice would be if the Windows Store app would give you an uninstall/reinstall option when it encounters 0x80073cfb errors. I'm not the only person seeing this and it's happening with the Acer, just with a different set of apps. On Acer, it gets that error with these apps:
- Windows Alarms
- Bing Food & Drink
- Help & Tips
- Bing Health & Fitness
- Windows Reading List
There is some overlap, but only with 2 of the apps. With the Acer, I found that if I burned Alarms, Help, and Reading List, the Bing apps installed normally. I also had the same problem with the HP Envy 23 that I bought last December. I had to burn the village to save the village on that machine too.
The burning village image comes from The Witcher 3 Set, from the Flickr feed of Gameranx.
Friday, May 24, 2013
Certified Xamarin Mobile Developer
I just received the email notification from Xamarin that I successfully passed their Mobile Developer certification exam. I was given a free pass for the exam for attending the Xamarin Evolve Developer conference back in April.
It was a tough exam, it went pretty deep on some of the internals and covered a lot of iOS and Android territory. Passing grade was 50% correct of 100 questions. I hit 90% and the exam software showed me what the correct answers were for what I got wrong. Does it make me a better developer? No, but it shows that I have the knowledge and skill set to create iOS and Android apps using C# with Xamarin technology.
More importantly, I am using the skills that I learned at Evolve while I work on a new app for work. I really like how Xamarin had put together the training materials for sessions. Instead of the usual slide deck and sample code that you get a conference training session, Xamarin provided chapters of an training manual that covered each session. Plus the source code. You still get the source code.
Yesterday, I went from zero experience with SQLite to being able to create, populate, and use a SQLite database with the sqlite-net ORM code in just a couple of hours. My only reference was the materials from the Evolve session on cross platform data handling. It's been hugely productive to be able to use C# and the .NET Framework on the mobile side as well as the server side.
It was a tough exam, it went pretty deep on some of the internals and covered a lot of iOS and Android territory. Passing grade was 50% correct of 100 questions. I hit 90% and the exam software showed me what the correct answers were for what I got wrong. Does it make me a better developer? No, but it shows that I have the knowledge and skill set to create iOS and Android apps using C# with Xamarin technology.
More importantly, I am using the skills that I learned at Evolve while I work on a new app for work. I really like how Xamarin had put together the training materials for sessions. Instead of the usual slide deck and sample code that you get a conference training session, Xamarin provided chapters of an training manual that covered each session. Plus the source code. You still get the source code.
Yesterday, I went from zero experience with SQLite to being able to create, populate, and use a SQLite database with the sqlite-net ORM code in just a couple of hours. My only reference was the materials from the Evolve session on cross platform data handling. It's been hugely productive to be able to use C# and the .NET Framework on the mobile side as well as the server side.
As a side note, the SQLite Database Browser is great open source tool for checking the contents of a database created in the iPhone/iPad simulator. It's also useful testing SQL queries before you compile them into your code.Evolve had two parallel training tracks going on at the same time. I was taking the Fundamentals track to make sure that I had the foundation of Xamarin coding down. Now I can review the Advance training materials and move up to the next level.
Subscribe to:
Posts (Atom)