Sunday, April 24, 2011

There’s a hole…

First things first, small modifications to the plan, including nutting out the spacing for the top buttons. Actually, there were also “on the job” mods to the spacing around the spinner that I have incorporated here:

ScreenShot100

The idea with the control sets is that they are centred about the midpoint between the stick and the first buttons. They are equally spaced between the sets on that centre, with a little extra for the centre sets (player 1 and 2). It does look like the right most set is closer to the edge than the leftmost, but the centres are the same distance – when you are standing in the playing position you feel like you are all pretty evenly spaced.

Day two this weekend, holes marked out and centre punched:

DSCN2425 DSCN2426

Drilling them out in sets, 28mm for the buttons and the spinner, 16mm for the joysticks, one 24mm for the coin button, and a large one at 86mm for the trackball I did with the jigsaw:

DSCN2427 DSCN2428

Here is a shot of all them holes:

DSCN2429

After a dust off and a shop clean-up I got out the vinyl and the t-moulding for a nice, neat finish to the day:

DSCN2430

Saturday, April 23, 2011

Top and a lick of paint

First thing completed today was the console deck frame:

DSCN2419 DSCN2418

DSCN2420 DSCN2421

Then there was a bit of clean-up of the edges to be done, they are planed flush with the sides.

With the frame complete the top can be measured exactly and cut to size. I marked up some layout lines on the control surface, and freehanded some curves on the front:

DSCN2422

The last thing today was the slot for the t-moulding, and I painted the edge of the top in preparation for the application of the top vinyl – the last step before I can make the holes and cut-outs for the controls, after that I can take the top home and wire up the controls at home.

DSCN2423

Feels good to get a bit of paint on the thing Smile

Next time will be marking out and drilling for the controls, here is the layout for the deck:

ScreenShot099

Sunday, April 03, 2011

Heavy…

Made some good progress today. I Got the front panels on as you can see here:

DSCN2411 DSCN2410 DSCN2412

I have the extra bracing from front to back (double width drawer sides) in also. The pocket screws hold the angle join nicely, very solid.

After a late lunch break I finished off the rail around the top, 50mm down from the edge, that the console deck frame will sit on:

DSCN2414 ScreenShot098

The rail part at the front (the long piece that you see above, plan one the right) is by far the most fiddly piece that I have had to do. With all the adjustments that I am having to make because of the 19mm ply I ended up doing them by marking up the piece off the assembled part of the job. Fits just fine.

So here is where we are at now:

DSCN2413

And I can just lift it without putting my back out. Mostly because of the shape and no hand holds rather than the sheer weight, so I reckon that it must weigh in about 30kg. You can push it over if you try, but then again, you can push a fridge over as well.

I’ve left it up on the saw horses (75cm dead lift, great way to finish the day) for a couple of minor glue ups – there were a couple of out of square corners that I needed to patch up a bit.

Next weekend: Measuring up for the top. Will try to get the deck panel cut out and holes drilled so I can bring it home and work on the wiring over the following week. Should be able to do that and get some of the console deck frame started.

Tuesday, March 29, 2011

Buttons and other stuff

I didn’t work all night tonight, so I took the opportunity to take some shots of the arcade hardware that I will be using. Here is the spread:

DSCN2401

So we have the main buttons, player 1 and 2 are going to be red v blue, 2 and 3 will be green and orange:

DSCN2402

There are some nice 1up, 2up, 3up and 4up buttons, also in this shot you can see the I-PAC and the OptiPAC – these are the keyboard emulator for the buttons (including joysticks) and the controller for the spinner and the trackball:

DSCN2404

The joysticks are Sanwa are feel really great:

DSCN2406

Other than that there is the spinner, and the (huge) trackball:

DSCN2408

One neat find from OzStick is the coin button:

DSCN2409

The buttons came with pretty good micro-switches. In the overview you can also see the hook-up wire, spade connectors, the various bits of mounting hardware and the couple of USB cables. There are also 4 other white buttons, 8 black buttons, and 8 yellow buttons that I will probably put near the rotary controls (need at least a couple to the left of the trackball). Looking forward to getting the deck top cut out so I can wire up the switches and test out the controller boards. Must be patient though – need to measure the exact size once the console is built up.

Bring on the weekend! (Plan is to get the front panels on, the rest of the top rail in and maybe get the doors on.

Saturday, March 26, 2011

Vote 1 MAME

Just a small update today. After having to do my civic duty and throw my vote away I only had a couple of hours this morning to work in the shop.

I made the sides, which have a chamfered edge to accommodate the front panels:

DSCN2395 DSCN2396

Due to the problem with two of three sheets of the ply being 19mm rather than 17mm, the piece that I had roughed out for the front panels is not going to be suitable – the doors and other door frame parts are 19mm which would leave the doors 2mm proud or would have them inset to sit flush which I don't care for either. Unfortunately, the only piece that I have left of the 19mm that is big enough for the front panels has the grain running in the direction that would be up and down the panel, i.e. along the bend, not around the bend… I had a go of bending the sheet in that way, but it is just far too brittle.

I am going the have to go with a corner there after all. Back to sketchup then to figure out the exact dimensions.

Here is an overview of today’s progress (short day, but at least I did get to use a hand plane… mmm):

DSCN2398

Now, GO VOTE!

Sunday, March 20, 2011

Sunday is MAME day!

Managed to spend about 5 hours in the workshop today.

Did some test bends for the front case elements. In doing so I discovered that not all of the 17mm ply sheets are 17mm thick. Two of them are 19mm! This will put all of the measurements out, but I should been able to adjust most of them as I work. The main thing that I can’t adjust now is that the base with the sides attached will be 2mm wider on each side… I will be able to get back a little bit when I assemble it and I am hoping that the rest is taken up by the thickness of the t-moulding when applied. In the end, the whole thing is painted anyway so you are not going to be able to see small gaps in the joinery, and they could be filled anyway.

I am a bit disappointed with the quality of the ply. It is certainly better than Bunnings (they can’t even supply flat stock), but this is no furniture grade stuff. I have future projects planned that will use ply finished like regular timber, and this stuff with great pink putty filled gouges and scallops of veneer patches even before you start is not what I would expect for $71 a sheet. Looks like you have to really go for the BB (this is CD) which is over $100 a sheet.

Anyway, pics or it didn’t happen…

This is what I got done today:

DSCN2394

What you see here is the base (completed last week) now joined to the back with its console deck support rail and the inner frame. The hole at the bottom is where the doors will be, the one at the top is the drawer. The whole thing is pretty sturdy already, with the front and sides attached it is going to be a solid unit. Definitely a two person lift. Anyone know how big the elevator is? (Just btw…)

Here is the plan overview for this stage (oriented for easy comparison):

ScreenShot097

A couple of joinery close-ups. The cross pieces are what will hold the shape of the assembled cabinet, and are securely joined with 4 pocket screws each:

DSCN2390

You can also see there the flush cabinet screws I am using where I can – here on the back rail, and also to join the base to the back from underneath. There could be quite a bit of load on the members that the doors attach to, so they are a composite joined in an L shape:

DSCN2392

Probably with far too many pocket screws :) Here is a small detail of how the front part of the frame connects to the front-to-back members:

DSCN2393

Fastener placement has been working out ok so far. I didn’t really plan the screw joints at all, just the joinery joints so, so far so good. The pocket screws are really good to use, they are pretty easy to get in. With the impact driver they are quick to go in even with one hand, and they are nice and tight when the joint is edge to face – they are less secure edge to edge, I do have some slightly longer screws though that I have used once or twice when the first one hogs the hole out too much. (They are too long for an edge to face join though – the point will come out of the opposite face)

So, what’s next? Well I don’t have a lot of time next weekend, but having done the bend test today I might be able to attach the sides and front bent elements on Saturday morning.

Sunday, March 13, 2011

MAME Cabinet

Have been working on a MAME project for use in the break room at work. I have a mass of buttons, joysticks, switches, wire and other electronics. I also went out an bought plywood and other hardware. I have made a plan in SketchUp over several design iterations.

I broke down the three plywood sheets last weekend to get them to more manageable sizes. Today I made a few design tweaks and got started on the construction for real. Here is a pic of the very first completed component part. It is the base panel:

DSCN2381

You can see the roughly cut pieces for the top, front and doors behind the saw, and the other remaining ply on the right.

Here is most of the other hardware that I will be using:

DSCN2386

Left to right you can see the latches that will hold the control console down to the base, the slides for the keyboard drawer, hinges for the front doors, various screws for joining the ply and attaching the other hardware, including some Kreg screws for pocket screwing, and of course it has got to be black!

Here is an overview of the design (the left door is hidden as is the keyboard drawer front to give a bit of a view inside:

ScreenShot091

The front is indicated as an angled join but it will be a kerf bend in the actual piece, the front ‘corners’ of the control deck will also be curved rather then exactly as indicated. Here is a closer view of the main player control spacing:

ScreenShot092

The final positions of the trackball and spinner are yet to be decided. There will be a row of button along the back edge of the deck for coin drop, 1up to 4up, start, etc. etc.

Most of the joints will be concealed pocket screws, visible in this shot of the first two pieces actually to be joined together:

DSCN2383

After today’s session, the base is complete, here is an underside view showing the box bracing:

DSCN2385

Here it is on the floor:

DSCN2388

The cabinet back needs to go on next, and then the inner frame can be constructed in place and after that the front skin panels, which reach to the floor concealing the spaces in the box work underneath the base.

Lastly, here is the reasonably final construction diagram for the next piece of work – the internal frame and back. (What is missing is a cross piece for the drawer to close against, the short members at the top of where the sides should go I forgot to delete from the diagram, they are no longer needed as I removed a bent member across the top of the front to make the construction a bit simpler).

ScreenShot093

Stay tuned for more updates, including some shots of the buttons, sticks, trackball, spinner, keyboard emulator, rotary control boards…

Thursday, May 28, 2009

TomTom sucks for customisation.

I recently emailed TomTom technical support stating that I was a software developer (and TomTom owner) interested in writing software for the TomTom device. I wanted to know where to get the SDK that they did have available up to about 1 year ago but now seems to have disappeared. This was their response:

Dear Mr Clark,

Thank you for your query. Your incident reference number is 090526-001861.

Unfortunately the Software Development Kit is no longer available from TomTom.

Please note that we are unable to offer any technical support for 3rd party add ons or software tools used in conjunction with your TomTom device.

Best Regards,

David A

TomTom Customer Support

Damn that sucks. What is with companies that want to keep you locked down to the software they make on a device that you own. They don’t even sell the navcore, they make nothing from it – they sell the hardware and the maps! It should only increase the value of the device and maps if there is more software available, and the cost to them of releasing their SDK would be minimal. Pretty short sighted if you ask me.

There are lots of little software projects that are now dead in the water due to the lack of an SDK for the latest version.

Tuesday, May 26, 2009

How to make images look disabled (greyed out) when the Button or MenuItem they are within is disabled in WPF

By default in WPF image controls that are within disabled menus and buttons will not be greyed out. One common way to achieve a standard look is to apply a style to the image that will cause it to be partially transparent when its parent is disabled. You create a style with TargetType of Image that is a Setter for the Opacity property with a Style.Trigger bound to the IsEnabled property of the image's parent (via RelativeSource). (Code later...) I made two triggers initially, as some of my Images are in Buttons and some are in MenuItems.

Just looking at my output window, I noticed a whole bunch of errors when the UI was coming up, some like this:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 
'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.MenuItem', 
AncestorLevel='1''. BindingExpression:Path=IsEnabled; DataItem=null; target 
element is 'Image' (Name=''); target property is 'NoTarget' (type 'Object')

And others like this:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 
'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.Button', 
AncestorLevel='1''. BindingExpression:Path=IsEnabled; DataItem=null; target 
element is 'Image' (Name=''); target property is 'NoTarget' (type 'Object') 

Thinking about it for a second, you can see that both of the style triggers will get applied to each image. For each image one will work and one will fail - there can only be one type for the parent element, Button or MenuItem not both. It is a silent failure so could just be lived with but I wanted to fix it.

First I was trying to find a way to choose which trigger to apply depending on the type of the parent*. I know you could remove the TargetType from the style and apply it as a named style to each element, but that just becomes a mess. The whole idea of this solution is to make at as simple to use as possible - basically just letting it modify the behaviour of all images. The real solution of course is to realise that the IsEnabled property is not a member of Button nor MenuItem directly, but it is on the UIElement class.

The fix then is to have only one Style.Trigger with the AncestorType of UIElement:

<Style TargetType="{x:Type Image}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type UIElement}, AncestorLevel=1}, Path=IsEnabled}" Value="False">
            <Setter Property="Opacity" Value="0.3"></Setter>
        </DataTrigger>
    </Style.Triggers>
</Style> 

* I would still like to know how to do this, but that will have to wait until another time when I really do need to do it. No time!

Programmatically changing TreeViewItem IsSelected fails to set IsFocused

I was having an odd problem with the IsSelected property of TreeViewItems. After adding an item and setting its IsSelected property, the originally selected item is no longer selectable.

I am using the Model-View-ViewModel pattern and a HierarchicalDataTemplate to bind a TreeView. The ItemsSource is an ObservableCollection. I noticed that when I added a new item to the collection (making it IsExpanded and IsSelected) it was added fine and was selected, but the parent item was no longer selectable. Any other item in the TreeView was selectable, and if you select one then the parent was again selectable, but right after the Add on the collection it was broken.

Seems to be a known problem: the IsFocused property is not updated when you change IsSelected via code. I am a little surprised that it is also not kept up to date when you set it via a binding… but I guess in the end binding is just code that you didn’t have to write yourself. Hopefully someone, somewhere will decide that this is indeed a bug so I can remove the event handler that I have put in place as a workaround*

Sample reproduction code:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1;assembly="
    Title="Window1" Height="300" Width="300">
    <Window.CommandBindings>
        <CommandBinding Command="{x:Static local:Window1.AddChildItem}" 
                            CanExecute="AddChildItem_CanExecute"
                            Executed="AddChildItem_Executed" />
    </Window.CommandBindings>
    <Window.Resources>
        <HierarchicalDataTemplate DataType="{x:Type local:Item}"
                                  ItemsSource="{Binding Children}">
            <TextBlock>
                <TextBlock Text="Name -> " />
                <TextBlock Text="{Binding ItemName}" />
                <TextBox></TextBox>
            </TextBlock>
        </HierarchicalDataTemplate>
        <Style TargetType="{x:Type TreeViewItem}">
            <!-- property bindings -->
            <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
            <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
            <!-- Workaround: Keep the IsFocused property up to date when the IsSelected property changes -->
            <EventSetter Event="Selected" Handler="TreeViewItem_Selected" />
        </Style>
    </Window.Resources>
    <DockPanel LastChildFill="True">
        <ToolBarTray DockPanel.Dock="Top" Height="21">
            <ToolBar>
                <Button Command="{x:Static local:Window1.AddChildItem}">
                    <TextBlock Text="Add" />
                </Button>
            </ToolBar>
        </ToolBarTray>
        <TreeView Name="tv1" ItemsSource="{Binding Items}">
        </TreeView>
    </DockPanel>
</Window>

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using System.Windows.Controls;
 
namespace WpfApplication1 {
    public partial class Window1 : Window {
        private ObservableCollection<Item> _items = new ObservableCollection<Item>();
        public ObservableCollection<Item> Items {
            get { return _items; }
        }
 
        public static readonly RoutedCommand AddChildItem = new RoutedCommand("AddChildItem", typeof(Window1));
 
        public Window1() {
            InitializeComponent();
 
            _items.Add(new Item { ItemName = "One" });
            _items.Add(new Item { ItemName = "Two" });
            _items.Add(new Item { ItemName = "Three" });
 
            this.DataContext = this;
        }
 
        private void AddChildItem_CanExecute(object sender, CanExecuteRoutedEventArgs e) {
            if(tv1 != null && tv1.SelectedItem != null) {
                e.CanExecute = true;
            }
        }
 
        private void AddChildItem_Executed(object sender, ExecutedRoutedEventArgs e) {
            if(tv1.SelectedItem != null) {
                (tv1.SelectedItem as Item).AddChildItem();
            }
        }
 
        // Without this event handler you will see the problem
        private void TreeViewItem_Selected(object sender, RoutedEventArgs e){
            TreeViewItem tvi = e.OriginalSource as TreeViewItem;
            if(tvi != null && !tvi.IsFocused) {
                tvi.Focus();
            }
        }
    }
 
    public class Item : INotifyPropertyChanged {
        private string _itemName = "New Item";
        public string ItemName {
            get { return _itemName; }
            set { _itemName = value; }
        }
        private ObservableCollection<Item> _children = new ObservableCollection<Item>();
        public ObservableCollection<Item> Children {
            get { return _children; }
        }
        private Item _parent = null;
        public Item Parent {
            get { return _parent; }
        }
 
        public Item() : this(null) { }
        public Item(Item parent) {
            _parent = parent;
        }
 
        public void AddChildItem() {
            Item i = new Item(this);
            _children.Add(i);
            i.IsSelected = true;
        }
 
        private bool _isSelected;
        public bool IsSelected {
            get { return _isSelected; }
            set {
                if(_isSelected != value) {
                    _isSelected = value;
                    OnPropertyChanged("IsSelected");
                }
            }
        }
 
        private bool _isExpanded = true;
        public bool IsExpanded {
            get { return _isExpanded; }
            set {
                if(_isExpanded != value) {
                    _isExpanded = value;
                    if(_isExpanded && _parent != null) {
                        _parent.IsExpanded = true;
                    }
                    OnPropertyChanged("IsExpanded");
                }
            }
        }
 
        #region INotifyPropertyChanged Members
 
        public event PropertyChangedEventHandler PropertyChanged;
 
        #endregion
 
        protected virtual void OnPropertyChanged(string propertyName) {
            if(this.PropertyChanged != null) {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

Just Comment out the call to Focus to see the problem.

Of note also is the fact that you must set IsSelected after the new item is inserted into the visual tree. For me that meant a small refactor (seen in the example in AddChildItem) to create the item, add it to the collection then set its IsSelected property rather than creating it with IsSelected already set to true. Otherwise it seems that the call to Focus fails.


* I.e. my code was all nice and separated, I was not handling any TreeView or TreeViewItem events, it was all done with smoke and mirrors** in a layer between the UI and the BO

** Data binding

Thursday, April 09, 2009

Tweet Delete?

Ack! all of my twitterings since over a month ago have disappeared!

I feel lost! They were only silly irrelevant mutterings for the most part, but they were my silly irrelevant mutterings and I trusted you to store them!

I have logged a ticket with twitter, hopefully they will return from the void…

Wednesday, April 08, 2009

Page.IsAsync broken on ASP.Net MVC

I was just trying to add a condition to my validation code so it would not run when the page was asynchronously posted (my controls were getting highlighted as an error before the user has even had the chance to enter any values because of some ajax that was updating another area of the page), but I found that the Page.IsAsync member is always false.

I managed to find another member that you can access via the ScriptManager:

ScriptManager.GetCurrent(Page).IsInAsyncPostBack

Which seems to work.

Wednesday, March 18, 2009

TextChanged event of TextBox not raised by the Internet Explorer AutoComplete feature

As noted in this msdn article, The TextChanged event of a TextBox control may not fire if the AutoComplete feature is enabled in Internet Explorer. And it appears to be “by design” – I hate that.

Fortunately, it is pretty easy to add some JavaScript to make the ‘right thing’ happen.

All you need to do is raise the onchange event at the appropriate time. For me that is when the TextBox loses focus. As I am doing this from code behind (as usual) I am registering a client script, then when I add the TextBox I set its onblur attribute accordingly:

Page.ClientScript.RegisterClientScriptBlock(typeof(FormPage), "RaiseOnChange", "function RaiseOnChange(ctrl){ctrl.fireEvent('onchange');}", true);
tb.Attributes[HtmlAttributes.OnBlur] = string.Format("RaiseOnChange({0})", tb.UniqueID);

The server side TextChanged event only gets raised if the TextBox.Value has really changed. I needed to do this because I am using the TextChanged event of some TextBox controls to trigger an asyncpostback to update an UpdatePanel. The code that sets the content of the UpdatePanel is in the server side TextChanged handler.

Friday, March 13, 2009

Quoted strings

I posted something about this once before, but having just given myself a headache trying to fix something similar once again I feel like writing some more.

Using the quote delimiter character inside of a quoted string at always a minor problem. There are two ways you can fix it – you can escape the quote using whatever method is valid at the time* or you can change the type of quote delimiter, i.e. you can switch from " to ' or vice-versa. There is a deeper problem though that is only really seen when you are not just embedding a delimiter in a string, but (as seems to be often the case with web development) when you are passing such a string to someone or something else. Say for example you are writing ASP.Net code behind to output a __doPostback where one of the arguments is a string with an embedded delimiter. The string in .Net code will be delimited (say with ") then the argument to __doPostback will also be delimited (say with ') but then the data in that string might contain ' (e.g. O'Neil) which will have to be escaped.

My exact situation this time was slightly more complicated still – I have three levels of indirection! I am in c# code behind, setting the .Text property on a Telerik DataGridItem to be an html anchor tag which will do a postback. So the .Net string is delimited (with " naturally), the onclick of the a tag is delimited (with " also by convention, so escaped for .Net as \"), the argument to the __doPostback function is delimited (with ' because there is no way of escaping nested " characters for html) and finally the data in that argument might have ' characters so it needs to be escaped (by \')! And certain parts need to be UrlEncoded also, but before you put in the \' escaping or else you will UrlEncode the \ character. *Hum*

item[colName].Text = string.Format("<a href=\"#\" onclick=\"__doPostBack('', '{1}{0}{2}')\">{3}</a>", QueryString.PostBackArgSep, postbackType, item[colName].Text.Replace("'", "\\'"), item[colName].Text);

* Mmm, yes. Whatever method is valid at the time. This is not always straight forward with some situations calling for \ to give \' or \", some for a doubling up of the offending character giving '' or "", or even for escaping to be impossible in the current context, leaving you with only the ability to switch delimiters. This last problem with why I try to stick with " as the delimiter most of the time and escaping where required rather than the simpler change to ' so as to save the other character for situations where it is the only method (e.g. html). I think that it is probably possible to get yourself into a situation where there is no possible way to pass the string ‘down the line’ as it were without breaking something. If that happens either you need to encode and decode the whole string somewhere, or admit that you are doing something the hard way and find the right way to do it… I almost think that is what is going on here with my current problem – I think it could be solved by keeping the information that I am passing through to __doPostback somewhere else and just passing a key to it to the code I am calling, but I don’t have the time to do that right now, and this form will be soon superseded by an ASP.Net MVC version.

Wednesday, March 04, 2009

Virtual Root (~) gives 404 error

We had a server reboot after a power failure yesterday, and this morning an ASP.NET application that has been working for months started giving this error:

Server Error in '/' Application.

The resource cannot be found.

Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable.  Please review the following URL and make sure that it is spelled correctly.

Requested URL: /~/direct.aspx


Version Information: Microsoft .NET Framework Version:2.0.50727.3082; ASP.NET Version:2.0.50727.3082

Seems to me that it is not translating the ~ into the Application Root path, but I am at a loss as to why. I have posted a question about the ~ virtual root giving a 404 on the ASP.NET newsgroup, but as is often the case with these WTF kind of posts I am not really expecting a response…

It was easily ‘fixed’ by just making the form action use the absolute path to the aspx file, but I want to know why it is broken.

Tuesday, March 03, 2009

Telerik RadUploadProgressHandler and ASP.NET MVC

Just ran into a small problem with the Telerik radUpload control and ASP.NET MVC.

The upload progress needs to have a httpHandler and httpModule configured in Web.config for it to work correctly – I think it is that which handles the GUID that it tacks onto the end of the url to maintain state (among other things). The path is normally Telerik.RadUploadProgressHandler.ashx but with MVC this will be routed to a controller and the handler will not be found.

I have added an exclusion to my Global.asax.cs file and it seems to work.

routes.IgnoreRoute("Telerik.RadUploadProgressHandler.ashx/{*pathInfo}");

Remains to be seen if this is the right way to do it or if there is anything else wrong, but for now I am just trying to get two existing web applications merged together as one MVC application. A lot of the stuff that those apps are doing is not “correct” from a MVC point of view, but this is version 0.9 :)


[Edit] Meh. Don’t need to do that. There are instructions on the Telerik site for how to configure the httpHandler for RadUpload under ASP.NET MVC

Shake to do something

What? That has to be the most stupid interface trick that I have ever heard of. Why the hell would I want to shake my iPhone to delete the current entry or shake it to start the recording? Jeebus. Perhaps if it was really sensitive and the shaking was totally in context with what you are using the device for, but shake to delete a database entry? That is just a stupid gimmick!

Monday, March 02, 2009

More iPhone icons

I am not quite happy with the template that I made for these icons… The corners are not quite right. But at least the first page of my applications all are about the same brightness now, and they all have the same border look. One for Twittelator* and one for gNotes:

Twittelator gNotes

Next!


* The channels of the png are in the wrong order, or a different order, or something on the iPhone so you have to use fixpng or something to fix it before you can open it for editing… but that seems to modify the colours (fair enough I guess, you are changing the channels…). I thought it was just a straight negative, but I don’t think it is. Rather than fiddling too much though, I quite like the colour of the Twittelator one as it is – better than the aqua and purple one that is the default anyway.

iPhone themes…

Wow, there are a bunch of themes out there for WinterBoard etc.

I am using iGlassSol which is very nice, but there are a couple of things I didn’t like. The clock could have a better time on it, and there was no icon for WideEmail. So I made some:

Clock WideEmail

The other thing that I made was a new dock with 5 icons on it… but it seems like there is a way to make it generate the glassy looking dock on the fly… but I can’t find it, only forum posts talking about it. Anyway, the dock (with WideEmail as the extra icon):

SBDockBG

Fun.

Tuesday, February 24, 2009

Call a method on an object only when that object is not null

I have often wanted an operator or something that will do something like run a method on an object if that object is not null (returning a default value if it is null). An example:

string s = SomeClass.SomeMember.ToString(); 

maybe for output or something. Now this works just fine, unless SomeMember happens to be null, when this code will throw an exception. So the code has to become:

string s = SomeClass.SomeMember != null ? SomeClass.SomeMember.ToString() : ""; 

or something like that. Upon finding the ?? ‘null coalescing operator’ I thought that would do the trick, but that will only munge the ToString (say) return value to "" if it was null, not let you call members on a null reference. You could do something with a chain of ?? operators, but that looks nasty and if anything in the chain is actually a method call rather than a property access then it may be called multiple times…

I think that I have come up with something neat and simple that works.

public static TResult Try<T, TResult>(this T left, Func<T, TResult> func) { 
    return Try(left, func, default(TResult)); 
} 
 
public static TResult Try<T, TResult>(this T left, Func<T, TResult> func, TResult defaultValue) { 
    if(left != null) { 
        return func(left); 
    } else { 
        return defaultValue; 
    } 
} 

Which can be used like this:

string s = SomeClass.SomeMember.Try(m => m.ToString(), ""); 

I named it Try in reference to functions such as TryParse. Perhaps not the best choice of name, but I am pretty phenomenally bad a choosing names for things… If you use it on a null reference you will get back the default value you specify or if you don't specify one you get the default value of type of the lambda expression. This second case (not specifying the default explicitly) is more useful when the type is not nullable... It is useful for calling functions on members of a class that might be null. More than that of course though, as that is a lambda (well actually a Func<T, TResult> Generic Delegate which is most easily populated with a lambda) you can pretty much do whatever you like in there.

Now I understand that this is not for everybody and that it is not going to work in all situations. Sometimes a null return value will not always have the same meaning as the default value for that type, but if you keep this in mind to does clean up a lot of code.

Another example to illustrate:

public class DataObject { 
    public List<string> Strings; 
} 
 
DataObject myDataObject = new DataObject(); 
// int stringCount = myDataObject.Strings.Count; // *boom!*
int stringCount = myDataObject.Strings.Try(l => l.Count); 

So this does not give you all of the same information that you get from receiving the null value, but it makes some common stuff painless, like telling the user how many strings there are. I find myself hiding the null value a lot of the time anyway, converting it to "" or 0 or whatever, so there you go.

Real world ‘improvement’. This:

object obj = ExecuteScript(script);
if(obj != null) {
    return obj.ToString();
} else {
    return "";
}
Becomes this:
return ExecuteScript(script).Try(o => o.ToString(), "");

Incidentally, I really love how well the type inference works now. There is no need to specify the types when calling the function - like myDataObject.Strings.Try<string, int>(l => l.Count) - and the return type gets updated when you add or change the return type of the lambda expression. Very neat.