Windows Live Writer del.icio.us Plug-In...an update

|

UPDATE 2008-08-14: When the boys at Delicious updated their site recently (nice work BTW, it looks great) they also changed their URL for feeds, causing my plug-in to break :-(

I have fixed up the code; the download links to the code on the original post are all correct and contain the updated code. The boys at Windows Live are currently approving the new upload, so please check to make sure you're downloading v1.1 if you get the plug-in from the link in this post.

Sorry for any hassle this may have caused. </PJ>

When I wrote the original post on the WLW plug-in, I had no intention of releasing it publicly; it was all about the process of building software and coding in general, I just needed a real piece of WLWDPI.jpgsoftware to focus on for the post. However, after a brief conversion with Derek, the other day, I spent 10 minutes packaging it all up, and then  submitted it to the Windows Live Gallery... it was accepted over the weekend:

del.icio.us Plug-In

So if you're not interested in the code and just want to use it then please feel free to download it from the link above.

Enjoy!

WPF - Settings Dialog... the Movie

|

WARNING: This is an experiment! I thought it might be interesting (and fun) to record a brief screencast (<10 minutes) showing how to do the settings element of my previous post, and this is the result:

I tried both YouTube and MSN Video to host this video and as you can probably see I've ended up with the latter. While YouTube uploaded the file faster it consistently failed to process it, with the upshot being that I could not view my video. MSN Video, however, accepted the file, gave me great feedback while it was uploading and then processing (whatever processing means!); but it did take nearly an hour for the entire cycle to complete. Which is a whole bunch longer than it took to produce the content in the first place. I'm not sure what I expected but it was not that.

I'm also not overly impressed with the quality of the end result; I'm sure there is more I can do my end, at the expense of a larger file, to improve that however.

To that end I'm making the raw WMV file available for download, purely because of the sub optimal quality and I think it might be frustrating to watch and code along with in the current form factor:

WPF Setting Example... the Movie

Please let me know what you think - if you like, I'll do more; this really is my first time at doing something of this nature so only your feedback can make it better (or go away :). Enjoy!

Update: Here's the code (albeit cleaned up a little) created during the video, as requested:

WPF Settings Example Code
 
kick it on DotNetKicks.com

WPF - Send to Flickr, Settings Dialogs and Security

|

There are literally hundreds of tools for sending your image files to your Flickr account. This post is not really about sending images to Flickr, it's not even about sending e-mails from .NET code by using GMail as an SMTP server (I chose that approach over mastering the vast Flickr API - or using a .NET wrapper of some description, however here is a good one if you're interested).

What I really want to explore with this post and the sample application are two things:

  • How to create a settings window the WPF way, e.g. by using data binding to the Settings class and successfully handling the Cancel scenario, and
  • Storing secrets, like your GMail password, in plain sight e.g. by using a settings configuration file, also this must be in a WPF friendly way.

Given my previous experience with tools that help me with my Flickr account, and my simple requirements, I'm sure you'll forgive me for writing my own Flickr uploader, which forms the basis for the sample application.

Simply, the WPF application has three very basic windows:

SENTTOFLICKRSCREENSHOOTS.JPG

The Help window, the Configuration window and the Sending window. The Help window is simply a FlowDocumentViewer with an inline FlowDocument. SENTTOFLICKRMENU.JPGThe Sending window is the one that sends an email by using the settings information. Finally, the Settings window for capturing the necessary settings information.

The application works by you placing a shortcut to the assembly in your Send To folder (the path on Vista will be:
%APPDATA%\Microsoft\Windows\SendTo), right-click the target image, and then click Send to Flickr (or whatever you called your shortcut).

Providing you've populated your settings information, that process will send an email to your Flickr account with the selected image as an attachment.

Data Binding to Settings
DATABINDINGTOSETTINGS.JPG

The diagram above provides a visual explanation of how the settings works for this application (click the image to see a larger version). The goal with this design is to only use WPF data binding, in order to remove any of the tedious right-hand/left-hand code; this type of code, as described by Scott Hanselman, is:

[the code] where you've got an object on the left and some other object/bag/pileOdata on the right and you spend a lot of lines just going "left side = right side, left side = right side."

Basically property field mapping; really boring, time consuming and error prone code. This design makes all that go away.

However, the usual downside with this approach is something I like to call "The Cancel Problem". This is where the user has updated a value in the dialog, but then changes their mind and clicks the Cancel button. The behaviour you want is to ignore the update, but because your UI and the backing store are bound together updates are dynamic. This means when the user tabs off the control, or presses ENTER, an update is immediately sent to the underlying data store.

Solutions to this problem tend to involve using intermediate objects to remember the old settings or store the new, and then when the user saves you write some left-hand/right-hand code to persist the values, booooh!

The simple solution I have chosen for this problem is shown in the diagram; basically in the OK button click you call Save on the Settings class, and on a Cancel button click you call Reload. This appears to be a little known technique, but solves the Cancel problem completely and removes any need for intermediate objects, and therefore any right-hand/left-hand code, yay! The Reload method simply reads the values again from the backing store, in effect cancelling the operation, and due to the data binding update the in memory view of all the values too.

Next we tackle the more prickly problem of storing sensitive information in your configuration files.

Storing Secrets

With the myriad of tools out there to help you with this social service and the other social service, be it: Flickr, FaceBook, del.icio.us or what-have-you, all asking for your password and potentially a mountain of other personal or sensitive information, all to do things on your behalf making your life easier - what confidence do you have:

  • A) assuming that you trust the installed software not to do anything naughty, and
  • B) that the developers involved were security conscious

that your secrets will not be easily discoverable by third parties by simply spelunking through the plain text files on your machine?

Here's an experiment:

Go to your favourite command line tool (mine's PowerShell), navigate to your AppData folder, in Vista that's: <drive>:\Users\YOU\AppData, and then type:

Get-ChildItem -r * | Select-String [your password]
(or the equivalent for your command line tool)

Then do the same for <drive>:\Program Files and <drive>:\Windows, and then, finally, search the registry for the same information.

The question I have for you is: How confident are you that you won't find any instances of your password?

I'm not saying that you will come up with anything, but what I am asking you is how confident do you feel that you won't, on a scale of 1 to 10 - I bet it's not 10!

With this sample application I wanted to explore a good way to store your email password in the Settings plain-text XML file, which was also a good fit for WPF applications, whilst not adding to your potential security woes.

My search was a pretty short one to find the answer I needed: Data Protection API, provided natively by Windows. Keith Brown explains this all very well in his free book The .NET Developer's Guide to Windows Security. What it boils down to for this application is the use of the ProtectedData class, provided by the .NET Framework since version 2.0, which simply has two methods: Protect and Unprotect. To protect a value you would write code like:

byte[] buffer = Encoding.UTF8.GetBytes(targetValue);
byte[] encryptedData = ProtectedData.Protect(
    buffer,
    this.entropy,
    DataProtectionScope.CurrentUser);

To make this all WPF friendly I wrapped the ProtectedData calls into value converter - so when data binding you can store and retrieve secure information by using my ProtectedDataConverter class as the Converter on the binding.

For passwords where you want to use the WPF PasswordBox control however, you cannot data bind to the Password property, it's not a dependency property - for obvious security reasons, therefore in this application I create an instance of the converter in code and use it that way:

this.PasswordBox.Password = DataCoverter.Convert(
    Settings.Default.Password,
    typeof(string),
    null,
    CultureInfo.CurrentUICulture) as string;

To convert the string value back to plain text (decrypt) is shown above, and to convert back in to a secure value (encrypt):

Settings.Default.Password = DataCoverter.ConvertBack(
    this.PasswordBox.Password,
    typeof(string),
    null,
    CultureInfo.CurrentUICulture) as string;

The converter returns the cipher text in a Base64 encoded string for easy plain-text storage.

Conclusion

I think I achieved my goals with this software; you, dear Reader, are the real judge of my assertion; to that end the code available for your review and use:

PaulJ.Windows.SendToFlickr

Obviously if you have an problems with the code then let me know. Your comments and personal conclusions are also very much welcome. I would love to know where you use this code, or indeed any of the code I publish, so all I ask is if you intend to use the code please drop me a line to let me know.

Enjoy!

kick it on DotNetKicks.com

Tufte complete... Book4

|

I've finished all the books now, this one was easily as good as his later books. The Visual Display of TufteBook1Quantitative Information offers practical advice and clear examples; I can see how this was the springboard for his later works.

I'm going to end this Tufte series with a quote from the book shown on the right; here Tufte is talking about designs for the display of information, but I think it equally applies well to software development and design:

What is to be sought in the designs for the display of information is the clear portrayal of complexity. Not the complication of the simple; rather the task of the designer is to give visual access to the subtle and the difficult - that is,

the revelation of the complex.

Personally, I think all software development and design boils down to the management of complexity, at some level or other. What I see in Tufte's words is simply:

Manage complexity; avoid making the simple complex.

The second part is always tricky - especially when designing at the keyboard. Turning a simple solution into a complex implementation is obviously undesirable (albeit quite common), to learn that the same is true for information design is not that surprising I guess, and it probably holds true for many other technical fields as well, I'm sure.

I am a little sad that I have finished this series and I will continue to blog about Tufte occasionally and I will also continue to follow his work. I do feel that I've savoured, enjoyed and poured over each book, but I cannot hear soon enough that there is another book coming from Graphics Press on information design.

vdqiei
vebe

Finally, my greatest hope is that you've been inspired to take a look at this fascinating field yourself - I would love to hear about your adventures with information design and Tufte, what you have done or plan to do, please drop me a line and share the wealth.

WPF - The Zoom Decorator: Part 3

|

Despite what the title says, this post is not about Decorators in WPF, the previous post in this series explains why decorators are not on the menu; the post before that gives the background to what we're going to delve into in this post.

Now that's out the way, on the with the show. In this post we're going to take the simple XAML we defined for zooming and turn that into a reusable Zoom control.

Migrating Loose XAML into a Control

Our first step is to migrate the loose XAML into a control, first lets define a class called Zoom that inherits from ContentControl.

namespace PaulJ.Windows.Controls
{
    using System;
    using System.Windows.Controls;

    public class Zoom : ContentControl
    {
        static Zoom()
        {
            DefaultStyleKeyProperty.OverrideMetadata(
                typeof(Zoom),
                new FrameworkPropertyMetadata(typeof(Zoom)));
        }
    }
}

The interesting part here is in the code for the static constructor; note that it overrides the metadata property for the controls DefaultStyle. What this says is that our new control's type is the resource key for it's style. What this enables us to do is define a style for our control without having to provide a resource key name for it, we can just specify the type - like you would for a Button or a TextBox.

For example, the following would replace the style for a Button:

<Style TargetType="{x:Type Button}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">

               <!-- Control Template XAML -->

            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Whatever you specify for the content of the control template will be how the button looks; as an x:Key value has not been specified the Type value will be used as the key - this will effectively change all buttons in scope. If we specify an x:Key value then only the Buttons that specify a Style property bound to that key would show the content specified in the new control template.

<Button /> <!-- Good -->
<Button Style="{StaticResource myButtonStyle}" /> <!-- Bad -->

If we did not override the metadata in the static constructor for our control, we would have to use the syntax shown for the second button in all the places we want to use our control; which would be a little tedious and would not give the same experience as using the built in controls.

So now we have a resource key defined and we know what we want our control to look like (the loose XAML already written), the question now is: where to put it, where do we specify the default style for our control? There are two things that we need to do to provide our a Default style: First, add attribute to our assembly and second, add a generic resource dictionary.

[assembly: ThemeInfo(
    ResourceDictionaryLocation.None,
    ResourceDictionaryLocation.SourceAssembly)]

The ThemeInfoAttribute class is an assembly level attribute, and in the example above we are saying that we have no theme level specific resources (we're not replacing Aero or Luna here!) and we have a generic dictionary located within the source assembly i.e. our control assembly.

With this code in place, WPF is now going to look for a resource dictionary in the following location at run time:

pack://application:,,,/Themes/Generic.xaml

That resource dictionary is as close to System Scope as we can get with our assembly; without defining any new themes (something you will probably never do, unless you're writing an operating system or intend to replace Aero!).

With that file in place, we now have somewhere to dump our controls XAML. We only need to make a couple of minor adjustments to migrate the loose XAML in to a control template, I've highlighted some of important the changes:

<Style TargetType="{x:Type local:Zoom}">
<Setter Property="Template">
   <Setter.Value>
     <ControlTemplate TargetType="{x:Type local:Zoom}">
       <Grid Height="{TemplateBinding Height}"
             Width="{TemplateBinding Width}">
         <Border ...>
           <ContentControl ClipToBounds="True">
             <ContentPresenter ...>
                <ContentPresenter.RenderTransform>
                  <ScaleTransform ScaleX="{Binding Path=Value,
                              ElementName=PART_ZoomSlider}"
                                  ScaleY="{Binding Path=Value,
                              ElementName=PART_ZoomSlider}"/>
          ...
          
          <Slider x:Name="PART_ZoomSlider" ... />
          ...

</Style>

The key changes are the TargetType association to our control, the use of TemplateBinding rather than fixed values, meaning the values will be obtained at run time from the templated parent (which will be an instance of our control). Finally, I renamed the slider so that it uses a standard naming convention for template parts; other than that the template remains pretty much unchanged.

We now have a working control identical to the loose XAML version in functionality, but it can now be used like this:

<Page x:Class="PaulJ.Windows.MainPage"
   xmlns=..."
   xmlns:x="..."
   xmlns:z="clr-namespace:PaulJ.Windows.Controls;assembly=...">
    <Grid>
        OrangeZoom.JPG<z:Zoom>
            <Rectangle
                Height="150"
                Width="150"
                Fill="Orange" />
        </z:Zoom>
    </Grid>
</Page>

Fixing the ClipToBounds

There is a small problem with our current implementation: when we zoom to full-size we loose the border; the image below demonstrates:

ZoomMissingBorder.jpg

This is because the ClipToBounds property is applied to the Border, so while the contained element (a rectangle in this example) does not leak outside the bounds of the Border control, there is no room left for the control to draw the border lines. The simplest way to fix that is to introduce a child control to the Border that acts as the clipping container:

<Border BorderBrush="{TemplateBinding BorderBrush}"
        BorderThickness="{TemplateBinding BorderThickness}">
  <ContentControl ClipToBounds="True">
ZoomBorderFixed.JPG    <ContentPresenter ... />
  </ContentControl>
</Border>

I used a ContentControl for this purpose as it does not have any visual appearance of it's own, meaning it's lightweight, but it does participate in layout of the visual tree - so it is perfect for our needs. No more Border issues.

Adding some Knobs and Dials

Currently all the slider behaviour is static, you'd have to completely replace the template just to make the zoom go from 0 to 500 percent (the default is 200 percent), or to start at 25 percent instead of a hundred. You also would be unable to change any of these values for an animation effect or in even in code without jumping through lots of hoops.

So lets expose three core properties Value, Minimum and Maximum; after we've done that you'll easily see how you could add more flexibility to your version of the control.

The process is pretty straight forward: define a Dependency Property for each value we wish to represent, and then update the control template to use a TemplateBinding for that value:

public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
    "Value",
    typeof(double),
    typeof(Zoom),
    new UIPropertyMetadata(1.0));

This creates a Dependency property to represent the Value of the Zoom control, and then we expose the dependency property value by using a standard .NET property:

[Bindable(true), Category("Behavior")]
public double Value
{
    get { return (double)GetValue(ValueProperty); }
    set { SetValue(ValueProperty, value); }
}

By doing with we make the dependency property accessible both from code and from XAML. Note that I've also added a couple of attributes to the property so that it is located sensibly in the property window of any UI designers, such as Expression Blend or Visual Studio, and I've also said that the value can be safely used for data binding.

You just repeat that process for the other properties and then we're done. The following link is WPF Browser Application (XBAP) that uses the new Zoom control's various different properties:

PaulJ.Windows.ZoomApplication.xbap 

I'm also making all the source code available for you to do with as you wish. All that I ask is that if you do anything cool with it then please send me a link or an email:

Download the Source

There are various improvements that could be made, such as adding animation to the zooming effect or adding the ability to move the zoom slider into different positions within the control. Also feel free to make these changes and then drop me a line.

Obviously if you find any bugs or have any problems with the code then please let me know.

Enjoy!

Windows Live Writer, Plug-Ins, WPF, Code Analysis and Tufte!

|

After the other days debacle with Nostalgia and Flickr I looked to simplify my picture posting process for this blog. My requirements are simple: something like right-click an image, and then click "Send to Flickr" or something similar. I figured that someone must have written this already.... but no, I came up dry.

I figured I'd have to write my own version against the Flickr APIs (which are vast!). However, during my initial investigations I found out two interesting things:

  1. You can post images to Flickr via email, and
  2. There is a Windows Live Writer plug-in for Flickr images (WLW is the text editor that I use to write all my posts).

Armed with this information, I managed to completely streamline my image uploading process with zero code on my part! Good enough... for now.

With that, I del.icio.us'd the appropriate links and figured that I would blog about my experience, share the solution, with you dear Reader, and seek your opinion on the matter. Then it occurred to me that there must be a Windows Live Writer plug-in for del.icio.us... my search began anew. But, again, I came up dry (well, I found one, but it really sucked).

By this time my interest was really piqued with regards to Windows Live Writer plug-ins; I wondered what it would take to write a plug-in with my exacting requirements:

  • It must be a WPF front-end (nothing else will do)
  • It must use XLinq for the back-end (experiment)
  • It must be FxCop and Microsoft Source Analysis compliant (as I want to ship it, to you dear Reader)
  • The UI should "suck-less" and follow as many Tufte principals as makes sense for an application of this type (experiment)

WLWDPI.jpg

When I started out on this adventure I was far from sure if the WPF approach was even possible; Windows Live Writer is a Windows Forms based application, therefore the plug-ins must also be WinForms. However, you can load WPF controls into WinForms using some fancy interop, so I was confident I could make something work. But, what I really wondered was:

Is it possible to load a WPF Window from WinForms?

I wanted to write something like:

private void buttonOpenDialog_Click(object sender, EventArgs e)
{
    MyWpfWindow dialog = new MyWpfWindow();
    if (dialog.ShowDialog() == true)
    {
        MessageBox.Show(dialog.SomeVlaue);
    }
}

Where the buttonOpenDialog method was inside a WinForms application. It turns out that this is not only possible but it also work extremely well.

I wanted to use XLinq given that the data will be coming from del.icio.us, in the form of an RSS feed, and I want to filter the results locally XLinq seemed like a perfect fit, and indeed it has been:

IEnumerable<LinkItem> result =
from i in this.xdoc.Element(rdf + "RDF").Elements(rss + "item")
    select new LinkItem
    {
        Categories = i.Element(dce + "subject").Value,
        Date = (DateTime)i.Element(dce + "date"),
        Description = i.Element(rss + "description").Value,
        Link = i.Element(rss + "link").Value,
        Title = i.Element(rss + "title").Value
    };

This is a simple query to deserialize the RSS feed into a list of custom LinkItem class, which is then used by the WPF UI.

To load the RSS feed in the first instance is as simple as:

this.xdoc = XDocument.Load(
    "http://del.icio.us/rss/compilewith.net);

That forms the basis of the back-end provider.

Next is the static code analysis tools. The main difference between the two tools I have chosen is that FxCop reports on the assemblies (post build), whereas the Source Analysis tool does what it says on the tin, and looks at the source text files (pre build).

The important aspect to understand here is that I'm not looking for a zero bounce with these tools. It may be possible, and indeed I did nearly achieve a zero bounce with the Source Analysis tool, I was finally thwarted due to the way WPF works. As was the case with this code, sometimes you simply cannot obey all the rules and still compile!

The rules are there to help you, not hand-cuff or hurt you, remember to only apply the rules that make your code better, cos aiming for 100 percent compliance in my experience means less than optimal code; not to mention the extra time required to chase down the last 1 or 2 percent of the violations, that is time better spent on shipping new features.

So with that in mind, here is my analysis of the remaining FxCop rules that I have no intention of fixing and why:

FxCopAnalysis.JPG

Note also that there is a way to suppress the violations in your source code for FxCop (and other static code analysis tools?), using code analysis attributes and providing compile time hints, which in production code, I strongly recommend you do. That way (1) you formally acknowledge the rule violation, (2) you also explain why the rule is ignored, and (3) most importantly, you explain why as close to the code as possible.

(If anyone is interested in how to achieve the suppression of FxCop rules in this way with attributes then drop me a line an I'll knock a "how-to" post together).

And finally, the Tufte analysis. This is probably the most subjective part of the work I've done for this plug-in; but I honestly believe that this UI is one of the best I've done.

This is the bit where I would most appreciate feedback:

TufteAnalysis.JPG

In the final analysis I'm happy with the result, the code is available in two different forms:

This is the first time that I've released code in this way, so your feedback would be greatly appreciated. Enjoy!

Flickr and Nostalgia Woes

|

Apologies for those of you who will get some of my older posts in your feeds this morning. I've had to repost a bunch of articles with fresh image links.

I've been using flickr for almost as long as this blog as been alive, with great success, I'm a huge fan; more recently I've been using Nostalgia from the boys a Thirteen23, which is where the trouble begins... I think. I don't know for sure but a bunch of pictures went AWOL yesterday after what appeared to be a successful session, and now I cannot trust the application anymore.

 

Which is a real shame as Nostalgia looks great and is seriously usable, but it is only a proof of concept and it's my own fault for using it for something an important to me as my blog. Ho-hum, lesson learned.

Sorry for any inconvenience in your RSS feed, my bad :-(

(Note: have "touched" my newer posts so they should appear at the top of feed)

Make my code better... please!

|

Having moved away from the world of software design and architecture, for my day job at least, does not mean that I have not been keeping a keen eye on the tools and technology for Technical Architects working with .NET. This post is a round up of the tools, documentation and podcasts that have crossed my path over the last few weeks and months in relation to code design, maintenance and architecture:

Tools

While FxCop does WPF and .NET 3.5 in their latest beta release, there is still some way to go with static code analysis; mainly because FxCop will only look at compiled assemblies. This is important to note when looking a code style; which is what a fair percentage of most code reviews are about. To help with that issue Microsoft have used a tool internally called StyleCop for yonks, but officially it has now been dubbed Microsoft Source Analysis for C#, the purpose of which is to examine the source (text) files as opposed to the compiled assembly. The documentation of all the rules is a work in progress, but if you want a consistent enforceable coding style in your shop, you could do a lot worse.

For XAML, HTML and ASP.NET markup there is the Visual Studio add-in called Tame Markup, for keeping that pesky X[A]ML/HTML in-line, literally. As with both this tool and the style cop above, you may not agree with all the rules or layout choices of the developers that created the tools but at the end of the day consistency is king and most of the time any rules are better than none - you can write your own version when you have the time ;)

Code complexity is an interesting concept and something all architects should care about when having to maintain a product or project with a large code base. Standards go a long way to helping reduce complexity but there are limits to that approach. The Reflector add-in, CodeMetrics is a useful tool for looking at code complexity and other code metrics, but you still need your own guidelines in-house to make effective use of this tool, as well as a good understanding of cyclomatic complexity. But, for a top notch solution look no further than the Metrics feature within CodeRush. All the other tools up until this point have been free, however, CodeRush is a pay-for product, it's worth the price tag in my opinion, and there are beta versions available for download for free; where you can see some of these metrics at work. Mark Miller, the brain behind CodeRush, has some very interesting views on code complexity and code maintenance, which are now being reflected in his product and Maintenance is a great metric for your code.

For the budding framework designer there is Framework Design Studio. Initially written "on the plane" by one of the writers, Krzysztof Cwalina, of the illustrious Framework Design Guidelines (which is getting the second edition treatment due out at the end of this year!). This tool enables you quick review and compare your new and old APIs.

Documentation

Krzysztof has published a digest of the Framework Design Guidelines. It is an interesting list of do's and don't without the explanatory text provided by the full blown version of the book, which is then ultimately enforced by FxCop.

For WPF developers, Paul Stovell offers his coding guidelines and there are the WPF Application Quality Guide from the Microsoft developers too; both are worthy of incorporation into your WPF development practices.

From a design perspective there are the Design Patterns in C# and VB.NET from the Data Object Factory, a nice little site for getting to grips with the GOF design patterns (and not this GOF). There is also a great MSDN article by James Kovacs on loosely coupled design.

Podcasts

There has been a lot of decent "live" content out there recently in the form of podcasts and Webcasts but the notable sessions for me centre around two broadcasts involving Mark Miller, the first is a .NET Rocks! podcast and the other is a DNRTV episode on exactly the same topic, the Science of Good UI, but the second link uses pictures (oooh-aaaahhhhh!)

Enjoy! I know that I have.

WPF - The Zoom Decorator: Part 2

|

In the first post of this little series we took a look at adding a simple zooming capability to a WPF application. In this post I promised that we'd talk about turning that code in to a reusable component by way of a Decorator. After doing a little research (via Programming WPF) it turns out that a Decorator is not what we want; what we actually want is a ContentControl. Here's what Chris and Ian have to say about ContentControl vs. Decorator:

....[a] reason to derive from ContentControl is to offer a service wrapped around arbitrary content.... this wrapping scenario may seem like the job for which the Decorator was designed. However, there is one critical difference: ContentControl behaves like a Control. This means that it should provide some interactive behaviour [PJ: e.g. such as zooming!].

ContentControl is therefore the base class for wrapper-like elements that provide a specific interactive behaviour around their content, .... whereas Decorator is the base class for lower-level wrapper elements with no particular behaviour, and which either have no appearance or have a fixed appearance [PJ: e.g. such as Border].

Given this little piece of of great advice, coupled with the desire to "do the right thing", this post will not be about decorators, indeed this little series will not be about decorators even though the title says differently :-O

Zoom

Quite simply we're going to turn our little zooming "loose XAML" into a ContentControl for multiple reuse in our applications.

During this process the control will not change visually, but it will then become a simple step to get zooming into our applications.

The goal, to achieve the screen shot above, should be something as simple as:

<ns:Zoom ...>
   <Button Content="I'm some Content" />
</ns:Zoom>

The steps to accomplish this will be the topic of the next post in this series, I promise - I'll keep the title the same for the sake of consistency, that'll teach me for prematurely solution-izing.

Tufte has arrived... Book 4

|

The fourth and final instalment arrived today, Tufte's very first book; my collection is now complete and my bedtime reading can resume - after nearly a weeks worth of wait:

TufteBook1

I'm sure it'll be worth it.


A slight departure from the regular program:

For those of you who might be interested in buying the books I've been talking about over the last few weeks, I recommend buying them directly from the Tufte Web site. On-line outlets, such as Amazon, do not appear to stock all the books and of the ones that they do they tend to only marginally be cheaper  (< £2), add the fact that each book has a $20 surcharge for postage and packaging coming from the Graphics Press directly in USA, buying from places like Amazon include about £10 markup... but the choice of where to spend that £10 is obviously yours, dear Reader.

I'm not having a go at Amazon per se, but more generally about buying this kind of material in UK - it is disproportionately more expensive compared to buying directly from the USA, even when including P&P!

With the Tufte books there is little to be saved, but this is not an isolated issue, I can actually save money by buying from Amazon.COM instead of Amazon.CO.UK. By way of an example:

WPF Programming: (according to Amazon)
UK: £19.99 + £2.75 (p&p) = £22.74
US: $31.49 + $3.99 (p&p) = $35.48 (£18.14 according to XE)

The savings here are not huge but also not insignificant, even if I took the FREEPOST offer for the Amazon UK option; then the book only costs me £19.99, I still save money shipping from the USA and I'll probably not have to wait any longer for it (from my experience of buy the Tufte books, 2 working days from ordering to reaching my grubby little mitts).

Considering that all it really boils down to, when buying goods online, is the address you type into your browser's address bar to start with, I think with a little quick comparison we might all be able to save a little money.

WPF - The Zoom Decorator: Part1

|

Adding a "zoom" slider and other required paraphernalia to create a simple "zooming" experience in your WPF applications is the point of the next couple of posts.

This one, the first, will deal with solving the "zooming" problem; the next post will then explore how to make the solution reusable by turning it in to a Decorator much like the Border or Viewbox controls shipped with WPF.

Zoom 
View a live version or download the XAML from here.

One of my goals with the zooming solution was to make it simple and if possible a zero code effort (not that I'm adverse to code if needs be, I'm not a XAML zealot, I just want to keep the solution as simple as possible). First I looked at the Viewbox control as that appeared to offer "zooming" out-of-the-box; however I abandoned that approach pretty quickly, Viewbox does not appear to be designed for this kind of thing. Next I turned to a ScaleTransform, which is perfect for our needs:

<Grid ...
      Height="200"
      Width="200">

    <Border ClipToBounds="True" ...>
        <ContentPresenter RenderTransformOrigin="0.5,0.5">
            <ContentPresenter.RenderTransform>
                <ScaleTransform
                    ScaleX="{Binding Path=Value,
                                ElementName=zoomSlider}"
                    ScaleY="{Binding Path=Value,
                                ElementName=zoomSlider}"
/>    
            </ContentPresenter.RenderTransform>
            <ContentPresenter.Content>
                <!-- CONTENT TO BE ZOOMED GOES HERE -->
            </ContentPresenter.Content>
        </ContentPresenter>       
    </Border>

    <Slider x:Name="zoomSlider"
            Maximum="2"
            Minimum="0"
 
            Value="1.0" ... />
</Grid>

There are four controls shown here with the important values highlighted.

A Grid is used to house the controls as this is simplest layout control for our needs. Placed directly within the Grid is a Border control and a Slider.

The Border acts as container for the content and is therefore clipped, to stop any zoomed content from "leaking".

The Slider is used for changing the zoom level, the interesting thing to note here is that it's value can only be a value between 0 and 2; this is for the ScaleTranform, a value of 1 for the ScaleX and ScaleY of transform equals 100 percent, i.e. no scale, but a value of 2 would be 200 percent and value of 0 would be zero percent and so on. These values therefore map nicely onto the transform without requiring any conversion code, this was not the case with the Viewbox solution and that was the main reason I abandoned the Viewbox approach. Also note where the Slider appears in the control hierarchy, it is last so that it will always be on top of any content being zoomed, this is important as you would loose the slider as the content grows bigger than the container.

Finally, inside the Border I use a ContentPresenter to apply the transform to and to act as the home for the actual content. This might seem like an interesting approach, why not just put the transform on the Border and the ClipToBounds on the Grid? The reason is if we zoom the Border the lines that make-up the borders visual appearance would also zoom, giving quite a strange effect, as shown below - zoom chrome without any content:

ZoomBorder 
View a live version or download the XAML from here.

Also by using a ContentPresenter the next phase, of making a Decorator out of this XAML, should be easier(?); I don't know yet as I have not done it, but I'm sure we'll learn something on the way. Happy zooming...