IronCow and Milkify now more open-source
The source code for IronCow and Milkify are now hosted directly on Codeplex. Anybody can therefore checkout the latest source code and submit patches!
The source code for IronCow and Milkify are now hosted directly on Codeplex. Anybody can therefore checkout the latest source code and submit patches!
I’m a huge fan on pass-phrases. Since Jeff already evangelised them over passwords, giving arguments and advice, there’s no need to add anything…
Except, well, some good old complaining.
It pisses me off that some websites have a limited length for passwords, thus preventing users from using pass-phrases. It’s not a pass-phrase if it can only have a maximum of 12 characters, is it? But the worst is how most of those websites won’t even warn you that your password is too long… they will just truncate it and tell you everything’s okay! And then, the next time you log in, you spend 10 minutes wondering how you can mistype 50 times a passphrase you’re absolutely sure about.
Now, time to point some fingers. Recently, the 2 websites that gave me this kind of crappy user experience were the Archos Store (after creating a new account) and Linked In (after changing my password on an existing account). It’s especially surprising how a high profile website like Linked In can be so poorly implemented.
One of my laptops is getting old and the lid is not as sturdy as it used to be. It now has the unwanted tendency of triggering a “laptop lid open” event when you barely touch it because the lid moves up a bit and back down. This is problematic because it wakes up the operating system, which doesn’t always detect that the lid was closed immediately.
When you run an internet search about laptop lids and putting Windows on stand by or hibernate, you find a lot of stuff, but nothing useful about disabling resume. To solve this problem you need to think like a programmer, i.e. find a solution that kinda makes sense, but not really.
Obviously, the answer lies in the Power Options dialog, but the only setting you have access to is what to do when the lid is closed, not when it is open.
Well, here comes the shocking answer: if you put your computer on stand by when you close your lid, it will wake up when you open it. But if you don’t do anything when you close your lid, it won’t do anything either when you open it!
Setting that first combobox above to “Do nothing” therefore fixed my problem. Now, I can close the lid, let the computer go to sleep after 5 minutes of inactivity, and move it around without fear of it waking up because the lid is too sensitive. I do have to press the power button to wake it up instead of just opening it, but that’s not too awful.
Stephen Walther recently blogged about tricks that every developer should know about Visual Studio. Most of those he mentioned I use on a daily basis, so I highly recommend them. It actually surprises me how many other programmers don’t know about those features. Somehow, most programmers know Visual Studio as much as they know Microsoft Word: there’s a big space in the middle to type your text, and then maybe they know a couple of menus and shortcuts and that’s it.
Anyway, here are a few other features I use frequently:
Tip #1 – Use CTRL-I for incremental search
I’m a big fan of incremental search. It’s actually the reason I originally switch from Internet Explorer to Firefox, back when Firefox was in beta (I already had tabs with Netcaptor). By the way, I’m happy to see IE8 now also features incremental search but, well, I’m hooked on FF now… anyway…
In Visual Studio, the incremental search mode is entered with CTRL-I. Then you can start typing right away what you want to find. You can also use backspace and all, as expected. The only problem is that it uses the last search mode defined in the “Find” dialog, so if the “Match case” option is currently checked, it will only perform incremental search on what you type in a case sensitive way. This may be a bit confusing at first, but using incremental search really makes navigating code faster.
Tip #2 – Use navigate backward and forward
Like the first tip, this tip make it faster to navigate code (because we’re spending more time reading code than writing code).
CTRL– (minus sign) and CTRL-SHIFT– allow you to respectively navigate backward and forward. The first one is the one I use almost all the time: I’m looking at some code, see a call to a function, go to the definition of that function, search for something, and then I want to go back to where I was at first. Well, without having to worry about anything, I can navigate backward twice and I end up where I want. No need to find the correct tab, figure out if I stayed in the same file or not while jumping through the code, etc. Wicked!
Tip #3 – Define some external tools
You can define “external tools” with, surprisingly, the Tools > External Tools menu item. A common thing for me is to define revision control related stuff there because most of the time I don’t like how buggy and slow source control plugins are. I also do this in Visual Studio Express where there is no support for plugins at all in the first place.
For example, say you’re using Perforce. You can create a new external tool like this:
It will checkout the current file (the one you’re editing if the focus is in the text editor, or the one selected in the Solution Explorer if that’s where the focus is). Now you just need to bind “Tools.ExternalCommand2” (because it’s the second external tool) to the keyboard shortcut of you choice (mine is CTRL-K, CTRL-E for “open for edit”). Shazam! Just use your keyboard shortcut and you can checkout a file without leaving the text editor.
You can setup other commands, like show the history of the file or make a diff with the previous version. You can also easily adapt this to other systems, like SubVersion (except in this case you won’t need the “open for edit” command because SVN doesn’t lock files by default).
IronCow is a library that wraps the Remember The Milk (RTM) web services. The “upper layer” of the IronCow API is an object model that stays in sync with the server and is designed with data binding in mind.
Of course, one of the things that went into IronCow’s design was testability. IronCow ships with a suite of unit tests that, well, test that the API is working fine. However, there’s another testability aspect: how the clients of your API are going to test their stuff. These are 2 different things:
The easy way to make an API testing friendly is to put everything behind interfaces. This way, the client can replace your stuff with test objects. But for some reason, I don’t feel like adding this kind of complexity to IronCow. It’s a pretty small API, with an object models that contains less than a dozen of classes, and hiding everything behind interfaces would triple the number of classes, add a couple of abstract factories, and more generally confuse clients that would otherwise expect a straightforward API.
Therefore, right now, to use IronCow in a test environment, you can disable the “syncing” behaviour like this:
Rtm rtm = new Rtm(); // You can also pass in your apiKey and // sharedSecret here but it doesn't matter. rtm.DisabledSyncing(); // From now on, there's no requests being sent.
When syncing is disabled, the IronCow object model just acts like a “dumb” object tree. Setting the name of a task or adding a new contact won’t trigger a request to RTM. Instead, it will just modify the objects locally, as if it was just a classic simple in-memory object model.
Note that you can’t reenable syncing.
The problem with this is that although the complexity of the public interface stays the same, the complexity of the internal code increases. I find it doesn’t increase nearly as much as when I tried to hide everything behind interfaces though. The other bigger problem is that it’s more complicated for clients to do behavioural testing. For example, if they want to test what happens in their application when a certain action makes IronCow throw an exception, there’s nothing to help them do that… In that case, they have to mock the IRestClient class, and use it with their Rtm instance. There are helper classes and methods to build RTM XML responses, but it’s not what you would call super user friendly (check the IronCow.UnitTests assembly source code for examples of how to use it).
So is this fine? No? Should I bite the bullet, add interfaces, and make this simple API be 3 times bigger and more complex? Is there a third option?
Microsoft apparently fixed something in .NET Framework 3.5 Service Pack 1 that previously didn’t work, or somehow worked differently. As a result, Milkify will crash if used on a machine that doesn’t have this service pack installed.
What you get is a XamlParseException that says that a ContentStringFormat property cannot be converted into a TemplateBindingExtension. This is because Milkify is using its own WPF skin where, among others, the check box control has a new custom template. This template is mainly a copy of the default one, courtesy of ShowMeTheTemplate, and looks like this:
<ControlTemplate x:Key="CheckBoxControlTemplate"> <BulletDecorator> <BulletDecorator.Bullet> <Grid> <Border Width="18" Height="18" CornerRadius="4" BorderThickness="2" BorderBrush="{TemplateBinding BorderBrush}" Background="{StaticResource MilkifyWhite}" HorizontalAlignment="Center" VerticalAlignment="Center" /> <Rectangle Width="6" Height="6" Fill="Black" Name="RectCheck" HorizontalAlignment="Center" VerticalAlignment="Center" /> </Grid> </BulletDecorator.Bullet> <ContentPresenter RecognizesAccessKey="True" Content="{TemplateBinding ContentControl.Content}" ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" Margin="{TemplateBinding Control.Padding}" HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" /> </BulletDecorator> <ControlTemplate.Triggers> <Trigger Property="CheckBox.IsChecked" Value="False"> <Setter TargetName="RectCheck" Property="Visibility" Value="Hidden" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate>
Note how the ContentPresenter control defines ContentStringFormat so that it uses whatever string format has been defined on the actual, instanced, check box. Of course, my main programming machine has SP1 installed so it worked fine.
Anyway, for some reason, this works in .NET 3.5 SP1, but not on plain default .NET 3.5. I can’t find much in the documentation about changes brought by SP1 that would explain why it behaves differently, and I don’t think it’s possible to tell ClickOnce that SP1 is a prerequisite to my application (you can only specify .NET 3.5 or not). I could remove that attribute completely, as I never specify it anyway, but it’s not the ideal solution…
The official website for Milkify is now open! Don’t be shy… download Milkify, and leave some feedback.
For those who don’t know about it, Milkify is a desktop client for Remember The Milk, written with WPF. It allows you to manage your tasks from the desktop, the same way Thwirl or Twitterrific manage your tweets. It’s got hotkeys and keyboard shortcuts, so managing tasks is easier and faster than in a web browser. I also have a few ideas up my sleeve to make Milkify really unique in the future, but I obviously need to make the basic functionality solid first.
The source code will still be available at CodePlex.
I was just adding CPPUnit to one of my projects. It ships with old VC6 workspaces, so you need to update them to the latest Visual Studio. While updating them to VS2005, I got a few of those little dialogs:
So? Yes or No? Choose wisely!
These, days, I’m back doing PHP stuff at home, and therefore had to install Apache. Of course, I could do PHP under IIS7, which would be easier, what with the nice administration interface and all, but I need to recreate the same environment as my hosting solution, complete with .htaccess and all that stuff.
One of the first thing you need to do in this situation is to add an alias to your websites because they probably aren’t located in the default documents root. So I did that, I opened httpd.conf in Notepad, edited it, saved it, restarted Apache, and off I went to write some PHP code.
A few days later, I want to move my websites to another directory, and add a few other ones. This time, I open httpd.conf in SciTE because I remember it’s got some nice syntax highlighting for this. I edit it, save it, restart Apache, and… mmmh, Apache doesn’t look like it noticed the changes. It’s still using the old locations, and none of the new ones.
After a couple hours of debugging, reading the logs and cursing at Apache, I realize who’s to blame: Vista. I should have known… I mean, everybody’s blaming it for everything, so I should have followed the crowd from the start. As it always is in these situations, the basic problem was that I was not editing the correct file. This is one of the golden rules of troubleshooting:
If a program looks like it’s not picking up the changes in a file you just edited, you most likely edited the wrong file.
This time, though, I really didn’t think there was a problem. After all, I had an explorer window open on Apache‘s conf directory, and I was either drag and dropping httpd.conf on SciTE, right-cliking and using “Open in SciTE“, or going File > Open directly in SciTE.
When I entered “full paranoid mode” (you know, that mode you get into when nothing works and you feel you don’t trust anything anymore, even the magnetic fields and gravity), I noticed an unknown button in explorer:
Do you see it? It’s the “Compatibility Files” button on the tool bar. “What the fuck is that?“, I thought, and I clicked on it. It led me to this:
I’ve selected the address bar so you can see the physical location of this thing.
All my cursing immediately redirected to Vista.
Scott Hanselman already got burned by the same thing and he explains it all, so go there if you want to know more about this whole thing… but basically, it’s a backward compatibility system that allows “legacy” applications that don’t explicitely require privilege elevation to still “work” by being redirected to a virtual storage when they perform file system operations on items the current user doesn’t have access to. In plain language, it allows crappy applications that assume you’re an Administrator to work correctly even though you’re not.
Now, the problem is that SciTE is not a crappy application. It’s just a text editor. When I opened the file, it should have seen I didn’t have access to that file, therefore treating it like any other read-only file: display a “Read Only” warning in the title bar, prevent me from editing or saving it, etc. But no, because Vista told it otherwise. Vista said “yeah, it’s okay, this file is totally writeable, no problem” while hiding the fact that it was redirecting that process to another place, so SciTE went along with it.
I understand that backward compatibility is a huge thing in the enterprise, and is actually one of the main reasons of Windows‘ commercial success, but it obviously fails in this situation. It’s wrong to tell a text editor that a configuration file is writeable when it’s not. It probably works in lots of other cases, allowing lots of big, expensive legacy programs to run correctly, but it fails here.
Scott suggests that the UI should do a better job of, well, not letting the user waste time figuring out where his files went, but I think the problem is deeper. I think this kind of “feature” should be a choice in the first place, not something that’s forced upon the user. The assumption that users are Administrators was in the long run a mistake, and there’s no way around a mistake without getting bitten in the ass at some point. There should be a way to just face it, and risk breaking programs. This is not desirable in most business places, but it may be desirable on lambda users’ machines. Yes, it would break stuff, but Vista already had a hard time with it already anyway, and Apple managed to go through a similarly harsh transitions before. We should be able to install Windows without 20 years of Side by Side libraries and “magical” weirdnesses like this one if we want to.
In this world of web 2.0 tagging madness, any good (or at least shiny enough) application needs a way to apply tags in a user-friendly way, namely with auto-completing text boxes. For example, the awesome Remember The Milk application has this:
What if we want a similar text box in WPF that would display a drop-down list of all the existing tags that match what the user is currently typing? The answer is, unfortunately, that we need to do it ourselves… but don’t be afraid, we’ll be playing around with cool things!
Auto-complete WPF text boxes have their fair share of articles on the web, but I find that Jason Kemp is the only one who wrote something interesting on the subject with his 4 part post (part 1, part 2, part 3, part 4). The main problem, however, is that all those articles deal with only auto-completing the full text of the text box, not each word as it is the case for a tag list. Let’s try to build our own solution, then and at the same time come up with a variation of Jason’s implementation.
The thing I liked about Jason’s solution was that he was using the Attached Property Pattern, which is one of the very powerful concepts that WPF and Silverlight offer. This pattern has already been discussed by Nikhil Kothari, John Gossman, and, err, BenCon (what’s his real name anyway?). What I didn’t like with Jason’s solution, though, was that in the end he was hijacking the control template of the text box to replace it with one that contained the popup to be used for showing the auto-complete suggestions. Since it’s common for designers to already replace a control template to re-look a control, I went with a different approach, which is to specify the “external” popup you want to use.
It goes like this:
<Grid Margin="10"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <TextBlock>Tags: </TextBlock> <TextBox Grid.Column="1" Name="TextTags" local:TextBoxAutoComplete.WordAutoCompleteSource="{Binding Source={StaticResource Tags}}" local:TextBoxAutoComplete.WordAutoCompletePopup="{Binding ElementName=PopupTags}" /> <Popup Name="PopupTags" IsOpen="False" Placement="Bottom" PlacementTarget="{Binding ElementName=TextTags}"> <Grid> <ListBox Name="PART_WordsHost" /> </Grid> </Popup> </Grid>
In this example, we have a text box called “TextTags” which has 2 attached properties: one that defines the source for all the suggestions, and one that defines the popup that will show the matching suggestions. The tricky part is that you need to know where to “feed” those matching suggestions. There’s a good chance there’s going to be some kind of list control in the popup where the suggestions should be inserted, but how to get to it?
It’s somewhat of a convention in WPF that if you need some “handshaking” between the look and the logic of a control, you should use named controls with a “PART_” prefix. This is what happens here, with the ListBox being called “PART_WordsHost”. This decouples the logic from the appearance, letting you arrange the popup as you want, or even use a ComboBox or a ListView instead of a ListBox.
You can read more about this “PART_” business in books like “WPF Unleashed” or “Programming WPF” (I haven’t found a good article on the web yet). Also, note that this convention is usually used between the logic of a control and its own control template, which is not exactly the case here, but it works all the same.
Now let’s look at the interesting bits in the code. This is implemented in a static class called “TextBoxAutoComplete”.
First, we need to register the attached dependency properties.
public static readonly DependencyProperty WordAutoCompleteSourceProperty; public static readonly DependencyProperty WordAutoCompleteSeparatorsProperty; public static readonly DependencyProperty WordAutoCompletePopupProperty;
static TextBoxAutoComplete() { var metadata = new FrameworkPropertyMetadata(OnWordAutoCompleteSourceChanged); WordAutoCompleteSourceProperty = DependencyProperty.RegisterAttached("WordAutoCompleteSource", typeof(IEnumerable), typeof(TextBoxAutoComplete), metadata); metadata = new FrameworkPropertyMetadata(",;"); WordAutoCompleteSeparatorsProperty = DependencyProperty.RegisterAttached("WordAutoCompleteSeparators", typeof(string), typeof(TextBoxAutoComplete), metadata); metadata = new FrameworkPropertyMetadata(OnWordAutoCompletePopupChanged); WordAutoCompletePopupProperty = DependencyProperty.RegisterAttached("WordAutoCompletePopup", typeof(Popup), typeof(TextBoxAutoComplete), metadata); }
public static void SetWordAutoCompleteSource(TextBox element, IEnumerable value) { element.SetValue(WordAutoCompleteSourceProperty, value); } public static IEnumerable GetWordAutoCompleteSource(TextBox element) { return (IEnumerable)element.GetValue(WordAutoCompleteSourceProperty); } public static void SetWordAutoCompleteSeparators(TextBox element, string value) { element.SetValue(WordAutoCompleteSeparatorsProperty, value); } public static string GetWordAutoCompleteSeparators(TextBox element) { return (string)element.GetValue(WordAutoCompleteSeparatorsProperty); } public static void SetWordAutoCompletePopup(TextBox element, Popup value) { element.SetValue(WordAutoCompletePopupProperty, value); } public static Popup GetWordAutoCompletePopup(TextBox element) { return (Popup)element.GetValue(WordAutoCompletePopupProperty); }
You can check MSDN for some explanation on this. Don’t forget the static getters and setters, because without them, the XAML syntax won’t work.
Here are the “dependency property changed” callbacks:
private static void OnWordAutoCompleteSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TextBox textBox = (TextBox)d; SetWordsHostSourceAndHookupEvents(textBox, (IEnumerable)e.NewValue, GetWordAutoCompletePopup(textBox)); } private static void OnWordAutoCompletePopupChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TextBox textBox = (TextBox)d; SetWordsHostSourceAndHookupEvents(textBox, GetWordAutoCompleteSource(textBox), (Popup)e.NewValue); } private static void SetWordsHostSourceAndHookupEvents(TextBox textBox, IEnumerable source, Popup popup) { if (source != null && popup != null) { //TODO: make sure we do this only this once, in case for some reason somebody re-sets one of the attached properties. textBox.PreviewKeyDown += new KeyEventHandler(TextBox_PreviewKeyDown); textBox.SelectionChanged += new RoutedEventHandler(TextBox_SelectionChanged); textBox.TextChanged += new TextChangedEventHandler(TextBox_TextChanged); Selector wordsHost = popup.FindName("PART_WordsHost") as Selector; if (wordsHost == null) throw new InvalidOperationException("Can't find the PART_WordsHost element in the auto-complete popup control."); wordsHost.IsSynchronizedWithCurrentItem = true; wordsHost.ItemsSource = source; textBox.SetValue(WordAutoCompleteWordsHostPropertyKey, wordsHost); } }
What this code does is that whenever a text box has been assigned both a source and a popup for the auto-complete feature, we hook up some event handlers on the text box to listen for user input. We also look for the selector control that will host the auto-complete suggestions (in our case, the ListBox), and set its data source to be our own source for those suggestions.
Obviously, this code needs some more work, like making sure we’re not re-registering the same events twice (which shouldn’t happen if you only set this in XAML). Also, as I mentioned earlier, we’re only looking for a control named “PART_WordsHost”, and throw an exception if we don’t find it, or if it’s not a selector control. We could be a bit nicer and try to explore the popup’s tree, looking for some selector control, but this exception will be raised the first time the user tests his code anyway, and is pretty self-explanatory, so I think it’s not a big deal for now.
Now that we’ve hooked up some event handlers to the text box, we can start doing the work. I won’t post the whole code here, as it’s mostly boring logic code that figures out what the user is doing and shows or hides the popup accordingly. However, there’s a few interesting things to discuss about this code.
First, we have a dependency property set up that contains the separator characters we should use to split and parse the text box’s text. Since our main use case is tags, the default separators are “,” and “;”. Use the TextBox’s CaretIndex, SelectionStart and SelectionLength to figure out where the user is currently typing things.
Second, we can take advantage of the filtering features of WPF’s data binding (more specifically the ICollectionView). When we have figured out what tag name the user is currently typing, we can set the filtering delegate on the words host items collection:
private static void TextBox_TextChanged(object sender, TextChangedEventArgs e) { TextBox textBox = (TextBox)sender; Popup popup = GetWordAutoCompletePopup(textBox);
string currentWord;// (SKIPPED CODE: get the currently typed word) if (currentWord.Length > 0) { // Filter all the auto-complete suggestions with what the user is currently typing. Selector wordsHost = (Selector)textBox.GetValue(WordAutoCompleteWordsHostProperty); wordsHost.Items.Filter = o => GetTextSearchText(wordsHost, o).StartsWith(currentWord, StringComparison.CurrentCultureIgnoreCase);
// (MORE SKIPPED CODE)
}
// (MORE SKIPPED CODE)
}
This leads us to another interesting point… see that “GetTextSearchText” method? It’s supposed to return the string representation of any item in the auto-complete suggestion list. Because we’re doing all this to handle tags, we know each item will actually be a string, so it’s easy. But it’s not so easy if you’re handling custom objects, and you want some kind of auto-complete text box for writing lists of such objects.
In this case, you would probably get the TypeConverter of each object and use that to get a string representation. After all, you need some bi-directional conversion in order to later parse the list the user typed in the text box! The TypeConverter is well suited to this task, but the whole thing made me look at the TextSearch class.
TextSearch is a class that defines attached properties that allow you to control the text representation of objects in search and auto-complete scenarios. The typical example of this is for editable ComboBoxes, where the user can type something in the editable part, and the system automatically pre-selects the correct entry in the ComboBox’s drop-down menu (actually, simple auto-complete text boxes can be implemented with a ComboBox and a few lines of XAML!). In this case, each entry in the ComboBox can have a TextSearch attached property that provides the string they can be matched against. Looking at the ComboBox’s code shows that it calls methods on TextSearch like “FindMatchingString(Object)” or “GetPrimaryText(Object)”. Those methods are nice because they handle all kinds of other cases, like when the object is an XmlNode, or is a FrameworkElement. The problem is that those methods are internal, so we can’t use them! Some people don’t want to rewrite that logic code and, hoping Microsoft will one day make those methods public, use awful ways in the meantime to work around the problem. I can’t really blame them, especially when they feel bad already.
Luckily, in our case, we’re only manipulating strings so all is fine, but you may want to rewrite that “GetTextSearchText” method to your liking.
The last point I wanted to discuss is that this kind of attached behaviour sometimes needs to stores some custom data on its target. In our case, we may want to “cache” the control that acts as the words host because we don’t want to look for “PART_WordsHost” every time the user types something. If you look at that last snippet of code, you can see I stored a reference to that control in a dependency property called “WordAutoCompleteWordsHostProperty”.
This dependency property is a read-only attached property, and those are pretty useful to store things only you should be able to set. I use them here to cache the words host control, but also to set a variable that tells us whether a selection change in the text box was caused by text input, or caused by the user navigating left and right (using the left and right keys, or clicking on the text with the mouse… this has some effect on whether to show or hide the popup).
Well, I believe that sums it up. The code as an attachment to this post, with a demo application that uses all the names of the “Key” enumeration as the source for auto-complete suggestions. See the screenshot below:
Note that this demo code won’t be maintained. To get my latest version of it, you can download the source code of Milkify and look for TextBoxAutoComplete.cs. For example, I plan to try and get the popup to show up just below the currently typed tag name, instead of aligned at the bottom left of the text box… but that’s all details. You have everything you need to write your own!