Archive for the 'Development' Category

HookLib on Git Hub

For anyone that follows me for the technical stuff I do, I thought I’d mention I’ve put up a mouse and keyboard hook library on GitHub. It allows a developer to build an app that subscribes to global mouse and keyboard events, process them, optionally cancel them, or potentially record them (Disclaimer: I take no responsibility for the use, misuse, legal or otherwise of this code.)

For those of you interested, the project is publicly available here: http://github.com/codelogic/HookLib

-Paul

Configuring Outlook 2010 on BPOS to work with multiple exchange accounts

Instructions are modified from http://blog.migrationwiz.com/2009/06/manually-configure-outlook-for-exchange.html

I’ve been looking around all over for a way to configure multiple exchange accounts to work with Outlook 2010. The official word is that “Outlook 2010″ isn’t supported by BPOS yet, and it’s left at that. One of the fortunate things about working for a company like InterKnowlogy is that we often have the liberty to experiment with and use non-standard or un-supported technology on a regular basis. Here’s the exact steps to setup Outlook 2010 on Windows 7.

Note that you will no longer be using the BPOS client to start outlook, and these instructions are for Outlook 2010 on Windows 7 only.

Server Information (Do this for each BPOS email account)

  1. Login to Outlook Web Access.
  2. Click on Options in the top right hand corner.
  3. Click on About in the navigation bar on the left.
  4. Find the entry for Mailbox server name and write it down or record it as you will be using it later.
  5. Log out of Outlook Web Access.

Create an Outlook Profile

  1. Make sure you have Outlook 2010 installed.
  2. Open the Control Panel.
  3. Click User Accounts
  4. Click Mail.
  5. In the window that pops up, click Show Profiles.
  6. Click Add.
  7. Enter a new name for the profile. i.e. Your email address
  8. Click OK.
  9. Click Manually configure server settings or additional server types.
  10. Click Next.
  11. Select Microsoft Exchange.
  12. Click Next.
  13. Enter the mailbox server name (that you wrote down or copied from the previous section) in the field Microsoft Exchange server.
  14. Enter your full name in the field User Name.
  15. Click More Settings.
  16. If you are prompted with an error that the action cannot be completed, click OK.
  17. Click Cancel.
  18. Click on the Connection tab.
  19. Select Connect to Microsoft Exchange using HTTP.
  20. Click Exchange Proxy Settings.
  21. Enter the mobile device URL for your region.
  22. Make sure the On fast networks, connect using HTTP first, then connect using TCP/IP is checked.
  23. Click OK.
  24. Click OK.
  25. Click Check Name.
  26. Enter your User Name and Password.
  27. Click OK.
    1. IF THERE IS AN ERROR:
    2. Click More Settings.
    3. Click the Security tab.
    4. Make sure Always prompt for logon credentials is checked.
  28. Your profile should now have resolved and the correct Microsoft Exchange server should be displayed.
  29. Click Next.
  30. Click Finish.

Add an Account to Your Outlook Profile

  1. If the mail dialog is not open, repeat steps 2-5 under Create an Outlook Profile
  2. Select the profile that you want to add an account too.
  3. Click Properties.
  4. Click E-mail Accounts.
  5. Under the E-mail tab, click New.
  6. Repeat steps 9-30 under Create an Outlook Profile.
  7. Repeat steps 5-6 for each e-mail account you want to add.
  8. Open Outlook 2010.
  9. Enter credentials for each account and check the remember option(make sure that the Username and password are correct for the account it is asking you for. THEY ARE DIFFERENT)
  10. Once Outlook is started…
  11. Click File in the top left corner.
  12. Click Account Settings.
  13. Click Account Settings in the dropdown.
  14. For each account under e-mail:
    1. Select the Account.
    2. Click Change.
    3. Click More Settings…
    4. Click the Security tab.
    5. Un-check Always prompt for logon credentials.
    6. Click Ok.
    7. Click Next
    8. Click Finish
  15. Click Close

Known Issues

  • If you are NOT using the BPOS client anymore you may not get notifications to change your password.
  • Calendars will show up with an error of “No Connection” you will have to send a sharing request to see their calendar.

Thoughts on Amazon S3 with WordPress

Recently, I’ve been looking for a way to reduce my bandwidth and storage bill for this site. I’m currently hosted through a company called Nearly Free Speech which is a fantastic hosting company for small static or PHP / MySql based sites, and it’s been great to have a hosting provider that I’ve literally never had to worry about. However, given that I regularly upload and distribute a large amount of media around this site I tend to eat through storage and bandwidth pretty quickly, especially now that my site has been around for about 4 – 5 years. As a super cheep hosting provider for small sites, NFS if fantastic for those small start up sites, but prices do increase quite a bit as the site grows. A few months ago I signed up for Amazon S3 (Simple Storage Solution or S3), which is a simple, flat, ‘blob’ storage system. Amazon itself originally built this system to power the media distribution for its own site, and then opened it up for others to use as well.

The basic concept is quite simple, instead of worrying about complex structures or directories the core service simply assigns a file a huge unique number and a title to the blob of data your uploading. It doesn’t matter what the data is, it could be anything from an image, to a zip file, to an 3GB text document. It doesn’t matter. It’s then possible to distribute that blob around the world so that the data is physically closer to whoever is requesting it. Because it doesn’t matter, most of the programs that use it choose to use the title as a path, which means that it uses the “/” character, making the file appears to be in a directory. In essence, Amazon S3 is a simple flat file server with a simple HTTP layer on top of the storage system for easy access to these objects in web applications. Assuming you’ve allowed public access to the particular file you can request it by performing a get request on your account followed by the title of the file.

However, the biggest original draw was the incredibly cheap storage and bandwidth costs, NearlyFreeSpeech weighs in at around $1.00 / GB down to $0.20 / GB based on the total bandwidth over the life of the account and storage is at $0.01 / MB per month ($10.24 / GB per month). Now, for a super small site, it’s a non-issue and you can’t beat the low end tier for pricing and ease of setup (You can see the full pricing here on the Nearly Free Speech pricing page). Now, consider Amazon’s S3: $0.150 / GB for storage (Until your storing more than 50TB of stuff, when it goes down a cent per GB), and $0.150 / GB of bandwidth. (You can see the full pricing tiers at the amazon web services simple storage page.).

Now, my current bandwidth for the site is about 1.5GB a month and my storage is about 400mb at the moment, for all intents and purposes its not a huge site, but enough that I wanted to see if there was a way I could take down the pricing. I’ve tried several things in the past such as offloading my photos to Flickr (Which I don’t like because it gets blocked occasionally) or SmugMug (Which doesn’t have a good plug-in for inserting photos into a wordpress site, but interestingly they also uses Amazon S3 to host their content). After tinkering around with it for a few months and using it as a host for large downloads, I went looking for and found a plug-in that replaces the core upload / media storage and retrieval functionality with calls to S3, and now that I’ve pushed my uploads folder to be hosted through S3 plus a quick switch in the blog settings and everything is now pulling from Amazon S3. Much cleaner, much nicer, a much less out of my pocket each month.

Sweet!

- Paul Rohde

The Evolution of Generics in C# 4.0

Before I begin, let me point out that I'm primarily writing this post to solidify my own understanding of the new generic structures and put it into my own words, there are already some great posts that already explain this in much greater depth and detail: (Generic Variance in C# 4.0 by Discord & Rhyme, What's the difference between covariance and assignment compatibility? By Eric Lippert)

So that being said, let start off with the problem that generics solve in the first place. (If you have a good understanding, you can jump to the new features in C# 4.0)

C# Prior to 2.0

Lets say I have the following class hierarchy:

    public abstract class Fruit { }
 
    public class Apple : Fruit { }
 
    public class Orange : Fruit { }
 
    public class FruitBasket
    {
        public Fruit[] Fruit { get; set; }
    }
 
    public class Tree
    {
        public Fruit[] PickFruit()
        {
            Fruit[] daFruit = new Fruit[2];
            daFruit[0] = new Apple();
            daFruit[1] = new Orange();
            return daFruit;
        }
    }

We have a hierarchy of objects, a base Fruit class, an Apple class, which is a Fruit, and an Orange class, which is also a Fruit. In addition, we have a FruitBasket which has an enumerable of Fruit, and a Tree which I can "PickFruit()" from.

Now, lets say I want to have an instance of a fruit basket, however, I also want another one that deals with only Oranges (I don't want it to even be possible to put apples in the basket) so that I can make orange juice, apples just ruin a good glass of orange juice. I have two possibilities, I can create another fruit basket and ASSUME that I only put oranges in, or I create another classes that only allows oranges to be inserted in. Because I decide that I want the compiler to absolutely not allow apples in with the oranges, I now have to create a new class:

    public class OrangeBasket
    {
        public Oranges[] Oranges { get; set; }
    }

Or if I now want to have a basket that holds potatoes, I have to build another class:

    public class PotatoBasket
    {
        public Potato[] Potatos { get; set; }
    }

Right. Pattern. We are repeatedly creating virtually identical objects that simply contain other objects or that apply some sort of processing to those specific elements, all because we want the consumer (the person that is using this object) to be able to put an specifically typed object in and get a specifically typed object out, without having to cast it.

C# 2.0 - 3.5

With the release of C# 2.0 Microsoft introduced this concept of "generics" in programming. It allows programmers to create generalized algorithms that take and receive specific objects, store or process them, and return them, without knowing the creator of the object being worked on or knowing specific type. C# 2.0 also included a number of generic collections and interfaces that implemented these features, the most useful in my mind being the generic IEnumerable<T> interface. This now allows us to rewrite our basket class like follows:

    public class Basket<T>
    {
        IEnumerable<T> Contents{ get; set; }
    }

Now, instead of having a PotatoBasket, a FruitBasket, and a OrangeBasket we can replace it like so while still using the same class:

    Basket<Potato>
    Basket<Fruit>
    Basket<Orange>

And our Tree class now becomes:

    public class Tree
    {
        public IEnumerable<Fruit> PickFruit()
        {
            yield return new Apple();
            yield return new Orange();
        }
    }

So now, we have a Basket of Potatos, a Basket of Fruit, and a Basket of Oranges. Yet, we didn't have to duplicate the classes, and any the implementations still preserves type safety.

This is where it gets… Interesting.

Lets say I have an instance of a Tree class, and an instance of my Basket<Fruit> class. Now, it’s simple to do an assignment like this:

    var fruitBasket = new Basket<Fruit>();
    var Tree = new Tree();
    fruitBasket.Contents = tree.PickFruit();

BUT if I have a tree that has a PickApples() method like this:

    public IEnumerable<Apples> PickApples()
    {
        yield return new Apple();
        yield return new Apple();
        yield return new Apple();
    }

And I attempt to do the same assignment as before but with the PickApples() method instead, C# 3.5 will not compile it because the generic parameters are not the same:

    var fruitBasket = new Basket<Fruit>();
    var Tree = new Tree();
    fruitBasket.Contents = tree.PickApples();

That sucks. Why?

The reason has to do with the relationships of types, covariance / contra-variance / invariance (Erick Lipperts post on the difference between covariance and assignment compatibility is a much better source for it's relation with mathematics and type hierarchies). With versions prior to 4.0 the C# compiler does NOT allow generics of one type to be assigned to generics of another type. Thus, an IEnumerable<Apple> cannot be assigned to a variable of IEnumerable<Fruit>. But lets say we were allowed to do this, why would it be a problem? Lets say I have an IList<Fruit> and an IList<Apple>; it seems to make perfect sense that I could so the following assignment:

    var fruitList = new List<Fruit>();
    var appleList = new List<Apple>();
    fruitList = appleList;

Right?

Wrong.

This assignment would actually be plausable for IEnumerable<T> because IEnumerable<T> is immutable, it can not change, there's no way to "Insert" a new element into an IEnumerable. However, with an IList<T> it defines an Add(T item) method. An IList can be altered. In the previous example, if I were to take fruitList and look at the Add method in intellisense, it would show that I can insert any object that is a fruit into the add method of the fruitList, however, fruitlist isn't technically a list of fruits anymore given this senario, its a pointer to a List<Apple>. So in this flawed example, I could now call fruitList.Add(new Orange()); which would now be a runtime error because I can't insert an Orange into a List<Apple>. Bad. (In C# however, there is an edge case where this sort of error can occur with arrays. For instance, if you have a object[] objarray = new string[10]; you can then assign a fruit to one of the slots and cause a runtime exception. For more detail on this, see Erick Lipperts post on Covariance and Contravariance in C# arrays) So we have two things that should be solved. We know that there are certain situations where IEnumerable<X> should be assignable to IEnumerable<T>, specifically when X is a subclass of T, but we also realize that something like IList<X> should not be assignable to a variable of IList<T>.

C# 4.0

Enter variance modifiers for generic types that have now been introduced in C# 4.0.

out and in.

First, these can only be applied to generic type parameters of interfaces and delegates, in can only be applied to generic parameters that are contra-variant or invariant valid, and out can only be applied to generic parameters that are co-variant or invariant valid.

Gulp.

First, invariance, contra-variance, and covariance. In terms of types, if I have T1 and T2, those types are Invariant if they are the same type. For instance, a Fruit and a Fruit are invariant, a Fruit and an Apple is not invariant even though a Fruit variable can hold an Apple object.

Co-variant is where the inheritance chains are kept, if I have T1 and T2, the projection of T1 to T2 is covariant if T2 is lower in the inheritance chain than T1. For instance, a Fruit to Apple is Co-variant because Apple is an instance of Fruit.

Contra-variant is where the inheritance chain is reversed, if I have T1 and T2, the projection of T1 to T2 is contra-variant if T2 is higher up the inheritance chain than T1. For instance, an Apple to Fruit is contra-variant because Apple is an instance of Fruit, the relationship is reversed, flipped.

So, it allows me to do the following in C# 4.0 with the new variant structure:

    var fruitBasket = new Basket<Fruit>();
    var Tree = new Tree();
    fruitBasket.Contents = tree.PickApples();

Because IEnumerable is defined as follows:

    IEnumerable<out T> { /* .. */ }

Remembering that out is co-variant because it can return the item or a subclass of that item, in this case PickApples() is returning an IEnumerable that is lower in the inheritance chain than the variable it's being assigned to (by lower, I mean that its a subclass, or sub-sub..n class of the other object)

To demonstrate a class with contra-variance with an in parameter, lets say we have an interface and classes like so:

    IPieMaker<in T> where T : Fruit
    {
        Pie MakePie(IEnumerable<T> fruits);
    }
 
    ApplePieMaker : IPieMaker<Apple> { /* ... Some implementation ...*/ }
    FruitPieMaker : IPieMaker<Fruit> { /* ... Some implementation ...*/ }

Now, because the input parameter is contra-variant, I can have a variable declaration like so:

    IPieMaker<Apple> applePieMaker = new FruitPieMaker();

Wait. Seem odd? Because T is not specifying what Pie we are making only what is put IN to make the pie, I can put apples into a FruitPieMaker. It’s contra-variant.

Try and wrap you head around that :)

Note: There's a good possibility that I didn't accurately describe the terms covariance and contra-variance in relation to mathematical projection and ordering, corrections and better descriptions are greatly appreciated.

Additional Links:

Native Glass Windows with WPF in Windows 7 / Vista

One of the awesome benefits of working at InterKnowlogy is that we get time to do what we call RECESS: Research and Experimental Coding to Enhance Software Skills. It’s a 4 hour time span where we can work on interesting technologies to enhance, grow, and keep up on the latest technologies and methodologies. It keeps us sharp, interested, and many of our demos have come from these short code jams.

Over the past few weeks I’ve wanted to figure out how to add or extend glass into my application like you see in Word (2010 preview):

Glass

As you can see, the whole title bar area is seamlessly integrated into the look and feel of windows, it feels native, its got that cool semi-transparent blur-the-background effect and everything. So come RECESS I did some research and pieced together what you’d need to get an effect like this.

DesktopWindowManagerAPI.cs
 
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using Codelogic.Windows.Native.APIManagedExceptions;
 
namespace Codelogic.Windows.Native
{
    public static class DesktopWindowManagerAPI
    {
        public static void AllGlassWindow(this Window window)
        {
            ExtendFrameIntoClientArea(window, new Thickness(-1), false);
        }
 
        public static void ExtendFrameIntoClientArea(Window window, Thickness thickness)
        {
            ExtendFrameIntoClientArea(window, thickness, false);
        }
 
        public static void ExtendFrameIntoClientArea(Window window, Thickness thickness, bool exceptionOnFail)
        {
            var compEnabled = IsCompositionEnabled();
            if (exceptionOnFail && !compEnabled)
                throw new DWMNotEnabledException();
 
            if (exceptionOnFail && !window.IsInitialized)
                throw new WindowNotLoadedException();
 
            if (!compEnabled) return;
 
            var margins = thickness.ToDWMMargins();
            var windowPointer = new WindowInteropHelper(window).Handle;
 
            //convert the background to nondrawing
            var mainWindowHwnd = HwndSource.FromHwnd(windowPointer);
            if (mainWindowHwnd != null)
                mainWindowHwnd.CompositionTarget.BackgroundColor = Color.FromArgb(0, 0, 0, 0);
 
            try
            {
                DwmExtendFrameIntoClientArea(windowPointer, ref margins);
            }
            catch (DllNotFoundException)
            {
                window.Background = Brushes.White;
            }
        }
 
        public static bool IsCompositionEnabled()
        {
            try
            {
                return DwmIsCompositionEnabled();
            }
            catch (DllNotFoundException)
            {
                return false;
            }
        }
 
        #region WPF to Native
 
        private static DWMMargins ToDWMMargins(this Thickness t)
        {
            var rtrn = new DWMMargins();
 
            rtrn.Top = (int)t.Top;
            rtrn.Bottom = (int)t.Bottom;
            rtrn.Left = (int)t.Left;
            rtrn.Right = (int)t.Right;
 
            return rtrn;
        }
 
        #endregion
 
        #region Native Interop
 
        [StructLayout(LayoutKind.Sequential)]
        private struct DWMMargins
        {
            public int Left;
            public int Right;
            public int Top;
            public int Bottom;
        }
 
        /// <summary>
        /// Extends an hwind's frame into the client area by the specified margins.
        /// </summary>
        /// <param name="hwnd">Integer pointer to the window to change the glass area on.</param>
        /// <param name="margins">Margins, what to set each side to</param>
        [DllImport("dwmapi.dll", PreserveSig = false)]
        private static extern void DwmExtendFrameIntoClientArea(IntPtr hwnd, ref DWMMargins margins);
 
        /// <summary>
        /// Checks to see if the Desktop window manager is enabled.
        /// </summary>
        [DllImport("dwmapi.dll", PreserveSig = false)]
        private static extern bool DwmIsCompositionEnabled();
 
        #endregion
    }
}
 

Alright, lets begin breaking this down.

DesktopWindowManagerAPI.cs
 
        [StructLayout(LayoutKind.Sequential)]
        private struct DWMMargins
        {
            public int Left;
            public int Right;
            public int Top;
            public int Bottom;
        }
 
        [DllImport("dwmapi.dll", PreserveSig = false)]
        private static extern void DwmExtendFrameIntoClientArea(IntPtr hwnd, ref DWMMargins margins);
 
        [DllImport("dwmapi.dll", PreserveSig = false)]
        private static extern bool DwmIsCompositionEnabled();
 

First, Windows 7 and Vista provide us with the Desktop Window Manager which was first included in Vista and continues on into Windows 7, it manages all the cool graphical windowing and effects you see in those operating systems. It also gives us an API dll to access these all the features, including many that are unavailable in WPF.

The first declaration you see sets up the data type that the DLL uses internally to represent Left, Right, Top, and Bottom glass margins. The others are pointers to unmanaged (non .NET) methods in the DLL. DwmExtendFrameIntoClientArea is the method that allows me to adjust how far in the glass extends in to the client drawable area, and DwmIsCompositionEnabled tells me if Aero Glass is enabled.

DesktopWindowManagerAPI.cs
 
        private static DWMMargins ToDWMMargins(this Thickness t)
        {
            var rtrn = new DWMMargins();
 
            rtrn.Top = (int)t.Top;
            rtrn.Bottom = (int)t.Bottom;
            rtrn.Left = (int)t.Left;
            rtrn.Right = (int)t.Right;
 
            return rtrn;
        }
 

A simple extension method (denoted by the ‘this’ in front of the Thickness t, it allows me to write the declaration as though the method were part of the Thickness class, so if I have a thickness variable thick I could convert it to a DWMMargins type by writing var margins = thick.ToDWMMargins();) it converts a WPF Thickness object to the internal DWMMargins struct.

DesktopWindowManagerAPI.cs
 
        public static void ExtendFrameIntoClientArea(this Window window, Thickness thickness)
        {
            ExtendFrameIntoClientArea(window, thickness, false);
        }
 
        public static void ExtendFrameIntoClientArea(this Window window, Thickness thickness, bool exceptionOnFail)
        {
            var compEnabled = IsCompositionEnabled();
            if (exceptionOnFail && !compEnabled)
                throw new DWMNotEnabledException();
 
            if (exceptionOnFail && !window.IsInitialized)
                throw new WindowNotLoadedException();
 
            if (!compEnabled) return;
 
            var margins = thickness.ToDWMMargins();
            var windowPointer = new WindowInteropHelper(window).Handle;
 
            //convert the background to nondrawing
            var mainWindowHwnd = HwndSource.FromHwnd(windowPointer);
            if (mainWindowHwnd != null)
                mainWindowHwnd.CompositionTarget.BackgroundColor = Color.FromArgb(0, 0, 0, 0);
 
            try
            {
                DwmExtendFrameIntoClientArea(windowPointer, ref margins);
            }
            catch (DllNotFoundException)
            {
                window.Background = Brushes.White;
            }
        }
 
        public static bool IsCompositionEnabled()
        {
            try
            {
                return DwmIsCompositionEnabled();
            }
            catch (DllNotFoundException)
            {
                return false;
            }
        }
 

Finally I wrapped native methods with .NET versions that take a more useful WPF Window class and WPF Thickness class for the ExtendFrameIntoClientArea method. Internally it checks to make sure the window is initialized and that Desktop Composition is enabled, gets the integer pointer to the window, resets the background, and then calls the native method to extend the glass into the drawable (client) area of the window. Two custom classes not shown are the DWMNotEnabledException class and the WindowNotLoadedException class, which are thrown if something goes wrong.

That’s all well and good, but wouldn’t it be nice if we didn’t have to worry about all these calls to this custom DesktopWindowManagerAPI class and could just set how much we wanted the glass to extend into the client area? Or bind it to something so that the glass area expands or contracts when a value changes?

I thought so:

GlassWindow.cs
 
using System.Windows;
using Codelogic.Windows.Native;
 
namespace Codelogic.Controls.WPF
{
    public class GlassWindow : Window
    {
         #region Glass Thickness Dependency Property
 
        public static readonly DependencyProperty GlassThicknessProperty = DependencyProperty.Register(
            "GlassThickness", typeof(Thickness), typeof(GlassWindow), new PropertyMetadata(new Thickness(0, 0, 0, 0), GlassThicknessChanged));
 
        //when the thickness changes, apply the change to the window.
        private static void GlassThicknessChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((GlassWindow)d).UpdateGlassState();
 
        }
 
        /// <summary>
        /// Local property for Glass thickness.
        /// </summary>
        public Thickness GlassThickness
        {
            get { return (Thickness)GetValue(GlassThicknessProperty); }
            set { SetValue(GlassThicknessProperty, value); }
        }
 
        public static readonly DependencyProperty IsAllGlassProperty = DependencyProperty.Register("IsAllGlass",
                                                                                                   typeof(bool),
                                                                                                   typeof(GlassWindow),
                                                                                                   new PropertyMetadata(
                                                                                                       OnIsAllGlassChanged));
 
        private static void OnIsAllGlassChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((GlassWindow)d).UpdateGlassState();
        }
 
        public bool IsAllGlass
        {
            get { return (bool)GetValue(IsAllGlassProperty); }
            set { SetValue(IsAllGlassProperty, value); }
        }
 
        private void UpdateGlassState()
        {
            if (!IsInitialized) return;
 
            if (IsAllGlass)
                this.AllGlassWindow();
            else
                this.ExtendFrameIntoClientArea(GlassThickness);
        }
 
        static GlassWindow()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(GlassWindow), new FrameworkPropertyMetadata(typeof(GlassWindow)));
        }
 
        protected override void OnSourceInitialized(EventArgs e)
        {
            base.OnSourceInitialized(e);
            UpdateGlassState();
        }
    }
}
 

Alright, this class creates a WPF Window subclass, adds a dependency property for GlassThickness and a change handler that internally calls the DesktopWindowManagerAPI.ExtendFrameIntoClientArea if the window is loaded or attaches an event handler if the window is not loaded. Now all you have to do is change your window class over to a GlassWindow class, set the thickness and you rock and roll!

GlassDemoWindow.cs
 
<WPF:GlassWindow x:Class="Codelogic.Controls.WPF.Demo.GlassDemoWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:WPF="clr-namespace:Codelogic.Controls.WPF;assembly=Codelogic.Controls.WPF"
    Title="Glass Window Demo"
    Height="300"
    Width="300"
    GlassThickness="10000">
    <Grid>
        <InkCanvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Transparent" />
    </Grid>
</WPF:GlassWindow>
 

Glass Ink

Something I have not yet done that I would like to do is figure out how to add functional buttons into the title-bar of an application. If you remember the Microsoft Word snippet from above there’s save / undo / redo buttons in the title bar. But that will have to be a later post.

Hope someone enjoyed my Glassy exploration,

Updates:

  • 2 Dec 2009
    • Changed ExtendFrameIntoClientArea to check to see if window.IsInitialized instead of window.IsLoaded
    • Updated GlassWindow to override OnSourceInitialized instead of adding an event handler for Loaded
    • Added in a method that turns the entire client area into glass by setting the margins to -1.
    • Changed Glass Window to have a Boolean Dependency property to turn it all glass.

- Paul Rohde