Process.exit(0)

|

This is very likely the last post I'll publish here for the foreseeable future. The primary reason for this is because for nearly two years now I have not used .NET seriously in my day-to-day work; .NET is no longer my present or my future.

Therefore, I'm closing down this blog. I will keep the domain alive for as long as the Google Analytics tell me posts here are still finding and helping developers; I've been very lucky and written some relatively popular posts over the years so I think it worth keeping alive.

That brings up the question of the present and future. Currently my focus is on design, iOS, Node.js and HTML5. I have also recently started blogging again, so if you would still like to follow my adventures in design and development please visit http://blog.paulj.me/ and if you've found this post by way of your feed reader, then please update your links to point to http://feed.paulj.me/.

Note that both of these URLs redirect to my new home, which is just a stop-gap, so please ensure that you bookmark the addresses above not where you end up after following the links.

Finally, a big thank you to all the people who have followed my .NET adventures and I sincerely hope you follow me on to my next adventure too.

--pj

WPF: Read-Only Selectable Text

|

In WPF making a read-only text area is easy, add a TextBlock, and then set the Text property. However, now imagine that you would like to enable your users to select the read-only text--a very common scenario--that's easy too. Create a TextBox, and then toggle the IsReadOnly property to True, job done, right?

Depending on why you want the TextBox to be read-only this may not be enough. Typically I want a read-only TextBox not because I want TextBox where the text cannot be edited, but what I actually want is a TextBlock where the text can be selected; the difference between these two might not be obvious, so take a look at the following screen shot:

At the top is the TextBlock and bottom is a TextBox; the difference is that there is more chrome associated with the TextBox, which is rendering here as a grey border around the content; however, TextBlock does not provide the functionality to select the text, therefore we have to work with a TextBox. Happily the border is easily removed, set the BorderBrush property to {x:Null} and the border is all gone.

Unfortunately that is only a superficial fix--the illusion is ruined the moment you move your mouse over the TextBox; annoyingly the border returns but this time with the highlight colour. There is no toggle on the TextBox control to turn off that annoying behaviour :(


The good news is that this is not the end of the road; there are a couple of ways to fix this problem. The easiest I have found is to replace the control template for the TextBox. That may sound drastic, and not normally something I would encourage you to do to just change something as simple as this; the reason being the moment you change a template you now 'own' that code, and the less code you own the better.

So why is the TextBox different in this case? Well, first I need to explain a little bit about how control templates actually work, how the behaviour and look join together.

WPF controls, when first unveiled back in back in 2006, were described as 'lookless' controls. What that actually means is that the look of the control is divorced from the implementation of the control. By way of an example, take a Button control: the only behaviour required for a Button to be a Button is the Click event--beyond that everything else is considered the look.

WPF provides the mechanism for this approach to control building by using templates, specifically a ControlTemplate. Templates define the look for all sorts of things in WPF, be it a control, a piece of data, or a panel. Templates can be defined imperically but are typically defined declaratively, by using XAML. The behaviour is defined by using managed code--C# for example.

This all sounds lovely and gives a wonderful separation of concerns, however, there is an implmentation detail that requires an a element of pragmatism to make this system work in the real world. For some controls it is possible for the imperative code to know nothing of the declarative code and work cleanly through events and triggers; however, the moment a control gets even mildly complex there is a need for the imperative and declarative worlds to meet. When this is required the control author uses a naming convention by setting the x:Name attribute to PART_nnn; in the case of the TextBox the surface on which the text is to be rendered this element is called: PART_ContentHost. This then enables the imperative element of the control to reference to the visual and work its magic.

The upshot of all this for our scenario is this: so long as our template contains an element with the x:Name value of PART_ContentHost, we're golden:


Here I have chosen a Border element, but you can use any Decorator or ScrollViewer derived elements. The result should be indistinguishable from a TextBlock with the exception that the text can be selected, as shown below:


So 'owning' the template in this case is trivial as the vast majority of the implementation for the control is hidden behind a single element, making for easy maintenance in comparison to a control with lots of moving parts.

If you have any comments, questions, flames, or enhancements I would love to hear from you. In the meantime, think deeply and enjoy.

-pj



WPF: Left Align Text in a CheckBox

|

The default text layout for a CheckBox is to position the text to the right of the box-chrome. During my development today I wanted to put that text to the left of the box-chrome.


This is a screenshot of the application I'm working on at the moment. At the top of the graphic you can see the default layout for a CheckBox is for the text to appear to the right of the box-chrome; at the bottom of the graphic is the effect I wanted with the text to the left of the box-chrome.

When looking around for a good way to achieve this result I came across many posts and articles that solved the problem by creating a new template for CheckBox, which manipulated the DockPanel container used in the template to position the chrome for the box and the text. While that approach works, and in some cases it may even be necessary, it does not need to be that hard.

By far the simplest solution is to use the FlowDirection property, and set the value to RightToLeft.


I must admit, that this is a fairly unintuitive approach to the problem, as FlowDirection is typically associated with localisation. However, as the help from Visual Studio states, the purpose of the property is to set the direction of the text within a parent element, which is all that is needed in this simple case.

This approach, however, while simple does introduce a new problem:


The check-mark also renders right-to-left, which is not what we want. To fix this you need to understand the CheckBox template a little, in the sense that the template uses a Path element to render the check-mark; armed with that information you can easily fix the problem with a Style scoped to just the CheckBox, as shown below:



Notice the FlowDirection for the CheckBox is RightToLeft, but I've overridden that with a Style in the CheckBox instance. Bingo! Job done, left-aligned text in a CheckBox, a little unintuitive but after you know the secret sauce, easy enough to do.

If you have any comments, questions, flames, or enhancements I would love to hear from you. In the meantime, think deeply and enjoy.

-pj