Mono WinForms layout and invalidate issues

Issue 1: Layout of anchored, non-visible control

I had a custom subcontrol anchored left and right within a parent control. The subcontrol was not visible and would only appear when I called a function to make it visible. The parent control had a default width and height, of course, but would be resized as necessary when placed on a form. With Mono, after being placed on a form, the anchoring seems to take effect based on the default dimensions of the control, not the dimensions of it in the form. This, of course, results in the subcontrol being an incorrect size and position.

I haven’t found a solution to this issue as yet.

Issue 2: Repaint after SuspendLayout/ResumeLayout

When adding a number of custom subcontrols (Dock=Top) to a Panel, I called SuspendLayout() before adding them, and called ResumeLayout() after. The height of the controls are adjusted right after they are added to automatically fit a word-wrapped block of text. On Mono, the Panel is never repainted (meaning the custom controls are never repainted either, and its text is not shown).

Calling Refresh() or Invalidate() after ResumeLayout() solves this issue.


Ekkio feed 2.0

A new feed for the Ekkio desktop client. This replaces the flat buttons with hyperlinks, for a more concise and elegant look.

The real challenge here was creating a WinForms controls where text and links could be rendered side-by-side. The standard Label and LinkLabel controls don’t allow for this.

ekkio feed v2

I’ll do writeup and post some code soon on how to make a control like this.


The end of :hover

Interesting post on the realization that :hover (in CSS, this defines what occurs when the mouse is over an HTML element) is no longer viable for layout on touchscreen devices.

When I sat down to a redesign of the Gameplan2 admin interface I suddenly came to a realisation, :hover doesn’t work. It’s entirely possible I’d skim read this somewhere, but somehow the implications for my design work had passed me by until I saw an iPad in use.

I came to the same realization when designing the Ekkio web client, and realizing I couldn’t open the file and folder submenus on my Palm Pixi.

Ekkio web client submenu

The arrows on the left would only appear when the user hovered over a file or folder. The solution, as shown, was to always show the arrows, but make then a lighter shade; on hover or when the dropdown is open, the arrows become a darker shade. This works well, despite the visual clutter of the arrows always being visible.

I agree with Croll’s conclusion,

So my proposition is this: :hover as an web interface design tool going forward is going to be less and less important.

I see :hover (and javascript mouse events such as onmouseover, for that matter) being unused or used only for non-essential stuff, such as added visual flair.

On a related note, touchscreen also don’t allow viewing the alt-text when hovering over an image. This is probably not a big deal when it comes to web layout, but it sucks for reading xkcd.


Safari 5 form submission bug

This applies specifically to Safari 5 (no problems in Safari 4) and forms with an enctype of multipart/form-data, submitted with a POST request built manually (for an AJAX [XMLHttpRequest] call).

Safari 5 injects a “charset=UTF-8” name/value pair into the ContentType field after the boundary string. This generates an invalid request. On the server-side of things, this resulted in no data in PHP’s $_POST global variable.

I tracked down the issues thanks to this post. The bug itself is a WebKit bug, described here.

The simple fix is to prevent Safari from automatically putting the charset parameter in by putting it in manually – before the boundary string. Here’s some jQuery code that demonstrates the issue/fix:

function ajaxSubmitForm(servlet, theForm, extraFunc)
{
var boundaryString = 'AaB03x';
var boundary = '--' + boundaryString;

var requestBody = new Array();

requestBody.push(boundary);

for (var i=0; i<theForm.length; i++)
{
requestBody.push('Content-Disposition: form-data; name="' + theForm.elements[i].name + '"');
requestBody.push('');
requestBody.push(theForm.elements[i].value);
requestBody.push(boundary);
}

var reqBodyText = requestBody.join('\r\n');

$.ajax({
url: servlet,
type: 'POST',
contentType: 'multipart/form-data; charset=UTF-8; boundary=' + boundaryString + '',
data: reqBodyText,
error: function(reqobj, errType, exceptionObj){
alert('Failed to submit form data.\r\nStatus = ' + reqobj.statusText);
},

success: function(xml)
{
if(extraFunc != null)
extraFunc();
}

});
}


Outlook interop exception when updating appointments

An odd issue I encountered doing Outlook interop with the Outlook Primary Interop Assembly; an exception with the message “You don’t have the permission to move this item” is raised when attempting to update an appointment. Thanks to this post I discovered the issue is caused by attempting to set the start and end times of an appointment with a recurrence pattern.

You cannot set the Outlook._AppointmentItem.Start and Outlook._AppointmentItem.End properties. You only set the Outlook.RecurrencePattern.StartTime and Outlook.RecurrencePattern.EndTime properties to indicate the start and end times of the event.


Cloning and changing the TYPE attribute of an INPUT element

Cool snippet I found here, which was helpful in building Ekkio’s login forms.

ekkio login form

Notice that the password field is really a text field when the page loads – it does not mask characters. However, once the the field has focus and the user beings typing his password, masking is expected, so the field is transformed into a password field. This is trickier than it sounds because you can’t change the type attribute of an input element.

A possible solution is to clone the input element, then change the type attribute of the clone.

var clone = $('#login_field_password').clone(); clone.attr('type', 'password'); clone.attr('id', 'new_login_field_password'); clone.insertBefore($('#login_field_password')); $('#login_field_password').remove(); clone.attr('id', 'login_field_password'); $('#login_field_password').val(''); $('#login_field_password').css('color', '#000'); $('#login_field_password').focus();

You clone the field, change the type attribute of the clone, then delete the original. Unfortuantely, this doesn’t work in IE, as even changing the type attribute of a clone is not allowed. The only solution I’ve found so far is to clone manually by actually writing the HTML markup with the new type:

var clone = $('<input id="new_login_field_password" name="password" type="password" />');

This works but it’s not as versatile. The revised code is shown below.

var clone = $('<input id="new_login_field_password" name="password" type="password" />'); clone.attr('id', 'new_login_field_password'); clone.insertBefore($('#login_field_password')); $('#login_field_password').remove(); clone.attr('id', 'login_field_password'); $('#login_field_password').val(''); $('#login_field_password').css('color', '#000'); $('#login_field_password').focus();


Mono Stream issue

An issue I discovered in Mono. When attempting to write a zero-length byte array (representing an empty string of UTF8 characters) to a HttpWebRequest stream, the stream is cut short at the position the write is being attempted; nothing after it gets written to the stream.

protected void WriteAllToStream(Stream stream, byte[] data)
{
// data.Length needs to be > 0
stream.Write(data, 0, data.Length);
}

I’m not sure if this is specific to the HttpWebRequest stream. I encounter the issue on Mono 2.4 (under Ubuntu) and Mono 2.6.1 (under openSUSE).


Ekkio

At some point last year, FragmentSync morphed into Ekkio. Aside from a name change and a facelift (a major facelift), Ekkio introduces some new concepts and features that push it beyond the peer-to-peer sync functionality offered by, the now deprecated, FragmentSync.

ekkio logo

I was planning on doing one massive blog post, but I think it would be best to do a series of smaller posts highlighting major features, it’ll be easier to understand and easier to write. In this post, I’ll introduce the 3 core concepts surrounding Ekkio, that is, the ability to sync files, store them online, and allow for collaborate with others working on the same document or set of documents.

ekkio core concepts

Sync files

Ekkio allows you to sync files to a number of different devices and services including, of course, other computers running Ekkio; you can also sync with USB devices (really, anything that show us as a removable disk in Windows), Bluetooth devices, Amazon S3, Google Docs, and Flickr (other online services will be supported based on what users demand).

I use the term files pretty loosely because Ekkio can also sync things that can be treated like files, which is pretty much anything. Ekkio will have support for syncing contacts and calendars, initially supporting Outlook, Google Contacts, and Google Calendar.

ekkio dashboard

When syncing with other computers, Ekkio can do a peer-to-peer sync, either over the web or through a local area network connection, or sync with the Ekkio cloud service (see below), automatically choosing the best connection that will give the best performance and most up-to-date files.

Store them online

Ekkio offers of a cloud storage platform allowing you to store your files online (allowing easy access to them from any internet-connected PC) and keep them in sync with your computers running Ekkio.

ekkio cloud

Storing your files in the cloud also allows Ekkio to keep files in sync between computers that may not be online at the same time (e.g. a home PC and work PC that are used independently), and this is one of the big benefits over a pure peer-to-peer sync. As long as the most recent copy of a document is in the cloud, the Ekkio desktop app can sync and update outdated copies of it on your PCs.

Collaborate

One of the big benefits of syncing files comes when you need to share or work with others on documents. Those who’ve been in this position will probably know the hassle of emailing files back and forth or trying to track down who has the latest version of a file. Ekkio alleviates this problem by allowing you to sync a folder with other users. When a document is updated, the new version is automatically sent to everyone else, making the necessary updates on their PCs and/or their folders on the Ekkio cloud service. Ekkio’s feed helps on the collaboration front. It displays who updated a document and when they performed the updated. Users can also leave and reply to messages in the feed, which is invaluable when it comes to explaining what was actually done during an update.

ekkio feed

We’re always looking for users, testers, and various assortments of people. It’s easy to connect with us: follow us on twitter or our Facebook page for updates. Our official blog is also up (though lacking content, at the moment).


What kind of company charges people $1500 to sit them in a room and tell them lies?

From Apple’s Carbon dev mailing list:

  • On Jun 13, 2007, at 7:53 PM, Matthew Formica wrote:
    We can’t speak to future plans to make WWDC sessions available to non-Select/Premier members. In general, getting a Select/Premier membership, and in particular attending WWDC, is the best way to stay current with programming directions on the platform.

Do you realize how ridiculous this sounds? You don’t stay “current” going to WWDC. You get to watch Steve perform. You hobnob with Apple people and hear the latest promises. Then you go home and hope what was promised actually comes to pass, but the other 51 weeks of the year WWDC does nothing to keep you current.

Last year developers at WWDC there told would be 64-bit support for Carbon. What kind of company charges people $1500 to sit them in a room and tell them lies?

Larry


PHP session_start() “Node no longer exists”

I stumbled upon this error earlier today as I attempted to store the value of a SimpleXMLElement as a session variable. I was able to narrow down the issue thanks to this post on bytes.com.

According to a user post on the PHP site, this occurs because SimpleXML returns a reference to an object containing the node value, and you can’t store a reference as a session variable. The value must be dereferenced and copied which can be done by casting.

// Bad! $storageBoxSize = $xml->data->storage_box_size;

// Good! $storageBoxSize = (int)$xml->data->storage_box_size;

I find myself hating loosely-typed languages more and more.