WPF Nested ScrollViewer / ListBox Scrolling

Here’s a quickie. I had an issue where I have a ListBox that will (should) never scroll but I need its item selection capability. It is inside of another ScrollViewer (along with some other controls) and that outer ScrollViewer should be what scrolls. Unfortunately ListBox was eating the MouseWheel events, preventing the outer ScrollViewer from scrolling.

A quick Google search didn’t turn up much. I didn’t want to set IsHitTestVisible=False because like I said, I need the selection ability. I also thought changing the template or subclassing ScrollViewer was a bit drastic.

So instead I came up with the following IgnoreMouseWheelBehavior. Technically it’s not ignoring the MouseWheel, but it is "forwarding" the event back up and out of the ListBox. Check it.

/// <summary>
/// Captures and eats MouseWheel events so that a nested ListBox does not
/// prevent an outer scrollable control from scrolling.
/// </summary>
public sealed class IgnoreMouseWheelBehavior : Behavior<UIElement>
{

  protected override void OnAttached( )
  {
      base.OnAttached( );
      AssociatedObject.PreviewMouseWheel += AssociatedObject_PreviewMouseWheel ;
  }

  protected override void OnDetaching( )
  {
      AssociatedObject.PreviewMouseWheel -= AssociatedObject_PreviewMouseWheel;
      base.OnDetaching( );
  }

  void AssociatedObject_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
  {

      e.Handled = true;

      var e2 = new MouseWheelEventArgs(e.MouseDevice,e.Timestamp,e.Delta);
      e2.RoutedEvent = UIElement.MouseWheelEvent;

      AssociatedObject.RaiseEvent(e2);

  }

}

And here’s how you would use it in XAML.

<ScrollViewer Name="IScroll">
    <ListBox Name="IDont">
        <i:Interaction.Behaviors>
            <local:IgnoreMouseWheelBehavior />
        </i:Interaction.Behaviors>
    </ListBox>
</ScrollViewer>

Quick Tip – Troubleshoot broken OData response using Notepad

Ran into a bit of an issue today when an application I developed stopped working. Fortunately I built a pretty awesome tracing framework that I often drop into all my applications that lets me get at important runtime information from within the application. In this case I was able to see the WCF Data Services query that was being sent. It looked fine. The problem was that the response couldn’t be deserialized.

So I pasted the query into IE and saw this.

2010-07-16_1101

Ahh great so the XML is malformed. That explains why the WCF Data Services client library can’t give me any useful information. Now I could go to the trouble of using Fiddler or FiddlerCap but in this case there’s a much simpler way.

Start Notepad » File » Open » Paste the URL

2010-07-16_1027

I admit I only found this out recently that our old friend Notepad could be used to open HTTP URL’s.

In this case the error was due to the fact that the database I am working with is a train wreck that lacks any constraints so the integrity of the data was violated. That’s a different issue altogether and one that’s out of my hands, unfortunately.

Another multi-purpose value converter for WPF

Colin Eberhardt has posted a neat multi-purpose value converter that tries various conventional conversion methods to convert from one type to another. This overcomes a frustrating limitation in WPF/Silverlight data binding where the XAML parser is seemingly more intelligent at converting literal values to target types than values sourced from binding expressions.

Unfortunately, the TypeConverter usage will not work in Silverlight but perhaps using the XamlReader technique there’s something that could be done?

Also, a couple of the readers in the comments had a great suggestion to derive the converter from MarkupExtension to simplify the XAML. I think I’m going to have to go back and do that with all of my converters now.

Very cool Visual Studio extension – VS10x Code Map

imageI have been using this Visual Studio extension called VS10x Code Map by Michael Kiss and I love it. It sits on the left or right of the Visual Studio text editor and provides an attractive outline view of the properties, methods, regions, etc in the current code file and lets you quickly navigate to a particular member.

I have tried other add-ins in the past that provided a code outline but they were usually slow, unattractive, or used a tree view style interface that I found to be more cumbersome than scrolling. The other nice thing about this one is that if you use regions (sorry Jeff, but to each his own) it will group your members by those regions.

It’s probably only useful if you have a wide-screen monitor since it does take up valuable screen real-estate. But according to the Visual Studio Extension Manager (Tools -> Extension Manager) it’s pretty popular.

Windows 7 Style "Aero" ChildWindow Template

Silverlight 3 introduced a very useful control called a ChildWindow. This is a "modal" dialog box that can contain whatever content you give it and it floats above the rest of the application inside a Popup control. I say "modal" because unlike ShowDialog in WPF or Windows Forms, showing a ChildWindow via the Show method returns immediately, but it does disable the application’s RootVisual which prevents the user from interacting with the rest of the application while the window is showing.

As cool as this control is, I have always been pretty disappointed in the default behavior and look and feel of the ChildWindow class. For example, the animation as it opens and closes is very unnatural and distracting. The overlay that "dims" the rest of the application successfully indicates the modal nature of the control, but it’s too strong I think. In fact I’m fine with just the normal "grey out" that happens when the RootVisual is disabled.

ChildWindow-Normal

A while back I had created a pretty lame ChildWindow template that kinda sorta looked like a Windows 7 Aero window. It was a half-hearted attempt but it looked a lot better than the above. But then I saw a question on StackOverflow asking about creating an Aero glass style window and I decided to revisit the problem and try to come up with something decent.

The first thing to note when trying to customize the ChildWindow template is that you probably ought to start from scratch. The default template is like an onion of nested grids and borders and panels, none of which have any particular significance to the control other than the border named Chrome. This is what ChildWindow uses to handle dragging. Although as I’ll discuss shortly, I think there’s some bugs there.

ChildWindow-Windows7Aero

My ChildWindow template looks like the one in the above screen shot. I tried very hard to make the template "cooperate" with the style. That is whenever possible, I use values from the style or directly applied to the control instead of hard coding colors, paddings, etc in the template which are hard to tweak.

For example, if you want to create more glass area around the white content area, just increase the Padding of the ChildWindow. Padding, of course, does not have to be uniform. You could give it a larger padding on the bottom to make room for Windows Media Player-style controls.

There’s a couple of caveats though…

  • There is no blur! I originally wanted to blur the elements underneath the "glass" areas but I found this to be a lot more difficult than I thought. A blur effect only applies the blur to its associated element and visual children. Since the stuff I want it to blur is only showing through as a result of opacity, the blur has no effect. I suspect there’s a way to do this using a WritableBitmap but I haven’t gone down that rabbit hole just yet.
  • It doesn’t have any open/close transition animations. I took those out on purpose but now I think a very subtle transition is needed to look more natural than the jarring animation from the default style.
  • It doesn’t currently have any visual states defined on the close button which I took out for the sake of keeping the XAML clean for the example. But you can pretty much drop in the transitions from the default template to get that back.
  • Dragging the ChildWindow appears to be jerky for some reason. I think this is a bug in the way ChildWindow handles dragging because Jeff Wilcox’s customized template has the same problem when one of his readers enabled dragging on his Zune style template.

Finally, there are a number of blog posts out there about how to hack the ChildWindow to be non-modal. Tim Huer has an excellent post about this. I have not tried but I don’t see any reason why my template could not also be applied in conjunction with those methods.

To grab the ResourceDictionary that contains the template, click the Show Source link below.

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:s="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">

  <Style x:Key="AeroWindowCloseButton" TargetType="Button">
    <Setter Property="Background">
      <Setter.Value>
        <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
          <GradientStop Color="#FFEEB3AC" Offset="0.009"/>
          <GradientStop Color="#FFDA8578" Offset="0.402"/>
          <GradientStop Color="#FFC64D38" Offset="0.459"/>
          <GradientStop Color="#FFC84934" Offset="0.598"/>
          <GradientStop Color="#FFD48671" Offset="0.885"/>
          <GradientStop Color="#FFE8BBAE" Offset="0.943"/>
        </LinearGradientBrush>
      </Setter.Value>
    </Setter>
    <Setter Property="BorderBrush" Value="#FF5E5E5E"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Foreground" Value="White"/>
    <Setter Property="Padding" Value="3"/>
    <Setter Property="Width" Value="45"/>
    <Setter Property="Height" Value="20"/>
    <Setter Property="IsTabStop" Value="False"/>
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="Button">
          <Border
            Background="{TemplateBinding Background}"
            BorderBrush="{TemplateBinding BorderBrush}"
            BorderThickness="{TemplateBinding BorderThickness}"
            CornerRadius="0,0,3,3">
            <Path
              Fill="{TemplateBinding Foreground}"
              Width="11"
              Height="10"
              Stretch="Fill"
              Data="F1 M 6.742,3.852 L 9.110,1.559 L 8.910,0.500 L 6.838,0.500 L 4.902,2.435 L 2.967,0.500 L 0.895,0.500 L 0.694,1.559 L 3.062,3.852 L 0.527,6.351 L 0.689,7.600 L 2.967,7.600 L 4.897,5.575 L 6.854,7.600 L 9.115,7.600 L 9.277,6.351 L 6.742,3.852 Z">
              <Path.Stroke>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                  <GradientStop Color="#FF313131" Offset="1"/>
                  <GradientStop Color="#FF8E9092" Offset="0"/>
                </LinearGradientBrush>
              </Path.Stroke>
            </Path>
          </Border>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
  <Style x:Key="AeroWindow" TargetType="s:ChildWindow">
    <Setter Property="Background" Value="White"/>
    <Setter Property="BorderBrush" Value="#FF5E5E5E"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="OverlayBrush" Value="Transparent"/>
    <Setter Property="OverlayOpacity" Value="0"/>
    <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
    <Setter Property="VerticalContentAlignment" Value="Stretch"/>
    <Setter Property="Padding" Value="5"/>
    <Setter Property="IsTabStop" Value="false"/>
    <Setter Property="TabNavigation" Value="Cycle"/>
    <Setter Property="UseLayoutRounding" Value="True"/>
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="s:ChildWindow">
          <Grid x:Name="Root">

            <!-- OVERLAY BEHIND CHILDWINDOW -->
            <Grid
              x:Name="Overlay"
              Background="{TemplateBinding OverlayBrush}"
              Opacity="{TemplateBinding OverlayOpacity}"
              HorizontalAlignment="Stretch"
              VerticalAlignment="Top"/>

            <!-- WINDOW CONTAINER -->
            <Grid x:Name="ContentRoot" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">

              <!-- GLASS BACKGROUND AND BORDER -->
              <!--
              NOTE: This border should not physically contain the rest of the
              window contents because it has an opacity setting that would
              affect all of its children. Instead, a second border is directly
              above it in the z-order and contains the child elements.
              -->
              <Border
                x:Name="Chrome"
                BorderBrush="{TemplateBinding BorderBrush}"
                BorderThickness="{TemplateBinding BorderThickness}"
                CornerRadius="4"
                Opacity="0.9">
                <Border.Background>
                  <LinearGradientBrush MappingMode="Absolute" StartPoint="0,0" EndPoint="1920,0">
                    <GradientStop Color="#FFADC9E5" Offset="0.010"/>
                    <GradientStop Color="#FFA7C2DC" Offset="0.069"/>
                    <GradientStop Color="#FFB7D2EC" Offset="0.084"/>
                    <GradientStop Color="#FFB7D2EC" Offset="0.146"/>
                    <GradientStop Color="#FFA8C4DE" Offset="0.168"/>
                    <GradientStop Color="#FFB8D3ED" Offset="0.455"/>
                    <GradientStop Color="#FFA6C1DB" Offset="0.518"/>
                    <GradientStop Color="#FFB6D1EB" Offset="0.543"/>
                    <GradientStop Color="#FFA7C2DC" Offset="0.604"/>
                    <GradientStop Color="#FFB7D2EC" Offset="0.618"/>
                    <GradientStop Color="#FFB7D2EC" Offset="0.700"/>
                    <GradientStop Color="#FFABC6E1" Offset="0.722"/>
                    <GradientStop Color="#FFB1CEEA" Offset="0.778"/>
                  </LinearGradientBrush>
                </Border.Background>
              </Border>

              <!-- WINDOW CONTENTS -->
              <!--
              NOTE: This element will not have a visible border. The Chrome element
              provides the visible border but this element needs to have a matching
              thickness and corner radius so that the contents of the window are
              "pushed in" by the same amount.
              -->
              <Border BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="4">

                <Grid>

                  <Grid.RowDefinitions>
                    <RowDefinition Height="25"/>
                    <RowDefinition/>
                  </Grid.RowDefinitions>
                  <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition Width="Auto"/>
                  </Grid.ColumnDefinitions>

                  <ContentControl
                    Content="{TemplateBinding Title}"
                    Foreground="#FF393939"
                    FontWeight="Bold"
                    VerticalAlignment="Center"
                    Margin="6,0,6,0"
                    Grid.Row="0"
                    Grid.Column="0"/>

                  <Button
                    x:Name="CloseButton"
                    Style="{StaticResource AeroWindowCloseButton}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="1,0,1,1"
                    VerticalAlignment="Top"
                    Margin="0,0,5,0"
                    Grid.Row="0"
                    Grid.Column="1"/>

                  <Border
                    Background="{TemplateBinding Background}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}"
                    Margin="{TemplateBinding Padding}"
                    Grid.Row="1"
                    Grid.ColumnSpan="2">

                    <ContentPresenter
                      x:Name="ContentPresenter"
                      Content="{TemplateBinding Content}"
                      ContentTemplate="{TemplateBinding ContentTemplate}"
                      HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                      VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>

                  </Border>

                </Grid>
              </Border>
            </Grid>
          </Grid>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</ResourceDictionary>

SwitchConverter – A "switch statement" for XAML

Download the example project which includes the source for SwitchConverter and SwitchedContent.

I figured I would write some more about value converters since I think there’s a lot of cool things you can do with them, especially when you put a little extra effort into generalizing them.

One thing I find I need to do often is to show content conditionally depending on a certain data binding condition. For example, let’s say we had a WeatherReport object that had a Condition property that had the following enumeration values: Sunny, Cloudy, Rain, Snow. We want to have a different image for each condition.

In WPF you can do this using a DataTrigger but even that is a bit verbose for my tastes. In Silverlight it’s a lot more difficult. The Expression Blend SDK gives you a behavior called a DataTrigger that can achieve this. But I think a value converter would do this job quite well and the markup will be the same for WPF and Silverlight. Check out the following snippet:

<Grid>
    <Grid.Resources>
        <e:SwitchConverter x:Key="WeatherIcons">
            <e:SwitchCase When="Sunny" Then="Sunny.png" />
            <e:SwitchCase When="Cloudy" Then="Cloudy.png" />
            <e:SwitchCase When="Rain" Then="Rain.png" />
            <e:SwitchCase When="Snow" Then="Snow.png" />
        </e:SwitchConverter>
    </Grid.Resources>
    <Image Source="{Binding Condition, Converter={StaticResource WeatherIcons}}" />
</Grid>

SwitchConverterDemo

The only thing that was a little bit tricky about this converter was making sure that the value being bound to could be compared against the strings in the When attribute. At first I naively just figured I could "ToString" the input value to the converter and compare that against the When values. But this is very fragile. For example, if the input were a DateTime, the values "6/25/2010" and "6/25/2010 12:00:00 AM" would not be considered equal. That’s not even considering the fact that regional settings would cause even bigger headaches.

So this implementation simply tries to use the IConvertible interface to normalize the values before comparing them. My actual implementation uses a very complex series of checks that take into account available Parse methods, TypeConverter, etc. But it’s a lot of code that I didn’t want to junk up the example with.

The only other thing worth mentioning is that the SwitchConverter has a ContentProperty attribute that allows us to specify the SwitchCase elements inline, making the resulting XAML pretty clean if you ask me. ContentPropertyAttribute is a little known and underused attribute that lets you specify which property will be set by content in between the element tags. There are a lot of places where this should probably be applied such as DataGrid.Columns, Setter.Value, etc. But now I’m going off on a tangent.

So while this solution is in no way a replacement for a good ViewModel, it does let you cleanly represent conditional content in XAML which really sits well with the OCD part of my brain that hates ugly markup.

As a bonus, I’ve also included a SwitchedContent control that makes it much easier to swap out entire elements based upon the conditional input. An example of that is shown below.

<Button Command="{Binding IncrementCommand}">
    <e:SwitchedContent Binding="{Binding Count}" Else="Overflow!">
        <e:SwitchCase When="0" Then="Zero" />
        <e:SwitchCase When="1" Then="One" />
        <e:SwitchCase When="2" Then="Two" />
        <e:SwitchCase When="3" Then="Three" />
        <e:SwitchCase When="4" Then="Four" />
        <e:SwitchCase When="5" Then="Five" />
        <e:SwitchCase When="6" Then="Six" />
        <e:SwitchCase When="7" Then="Seven" />
        <e:SwitchCase When="8" Then="Eight" />
        <e:SwitchCase When="9" Then="Nine" />
        <e:SwitchCase When="10" Then="Ten" />
    </e:SwitchedContent>
</Button>

Download the example project which includes the source for SwitchConverter and SwitchedContent.

A multi-purpose NegateConverter for WPF/Silverlight

I came across a question on StackOverflow that is a very frequently asked question regarding data binding in XAML. Given a boolean, how do you bind the opposite value to the target? The answer of course is to use a value converter (a class implementing IValueConverter) and invert the boolean in code.

I do this a lot though so I have a NegateConverter in "Josh’s Toolbox". My NegateConverter can negate a lot of things, not just booleans. For example, numeric values, Visibility, Thickness, Point, etc. Now I’ll probably never need to negate a Point but I figured what the hell. The code isn’t very pretty and if you don’t like if statements, just stop reading. It’s utilitarian, get over it.

Can you think of anything else that can be easily negated? (Click Show Source below.)

/// <summary>
/// Produces an output value that is the negative of the input.
/// </summary>
/// <remarks>
/// The built-in signed types are supported as well as a handful of other
/// commonly used types such as <see cref="T:Point"/>, <see cref="T:TimeSpan"/>,
/// <see cref="T:Thickness"/>, etc.
/// </remarks>
public sealed class NegateConverter : IValueConverter
{

    #region Fields

    /// <summary>
    /// The default singleton instance of this converter.
    /// </summary>
    public static readonly NegateConverter Default = new NegateConverter( );

    #endregion

    #region Constructors

    /// <summary>
    /// Initializes a new instance of the <see cref="T:NegateConverter"/> class.
    /// </summary>
    public NegateConverter( )
    {
    }

    #endregion

    #region Methods

    /// <summary>
    /// Converts a value.
    /// </summary>
    /// <param name="value">The value produced by the binding source.</param>
    /// <param name="targetType">The type of the binding target property.</param>
    /// <param name="parameter">The converter parameter to use.</param>
    /// <param name="culture">The culture to use in the converter.</param>
    /// <returns>
    /// A converted value. If the method returns null, the valid null value is used.
    /// </returns>
    public object Convert( object value, Type targetType, object parameter, CultureInfo culture )
    {

        if ( value == null ) {
            return null;
        }

        if ( value is double ) {
            return Negate( (double)value );
        }

        if ( value is int ) {
            return Negate( (int)value );
        }

        if ( value is bool ) {
            return Negate( (bool)value );
        }

        if ( value is long ) {
            return Negate( (long)value );
        }

        if ( value is IConvertible ) {
            return Negate( (IConvertible)value, culture );
        }

        if ( value is TimeSpan ) {
            return Negate( (TimeSpan)value );
        }

        if ( value is Point ) {
            return Negate( (Point)value );
        }

        if ( value is Thickness ) {
            return Negate( (Thickness)value );
        }

        throw new ArgumentException( "Cannot negate " + value.GetType( ) + ".", "value" );

    }

    /// <summary>
    /// Converts a value.
    /// </summary>
    /// <param name="value">The value that is produced by the binding target.</param>
    /// <param name="targetType">The type to convert to.</param>
    /// <param name="parameter">The converter parameter to use.</param>
    /// <param name="culture">The culture to use in the converter.</param>
    /// <returns>
    /// A converted value. If the method returns null, the valid null value is used.
    /// </returns>
    public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture )
    {
        return Convert(value, targetType, parameter, culture);
    }

    /// <summary>
    /// Negates a <see cref="T:TimeSpan"/> value.
    /// </summary>
    /// <param name="value">The value to negate.</param>
    /// <returns>The negated value.</returns>
    private static TimeSpan Negate( TimeSpan value )
    {
        return value.Negate( );
    }

    /// <summary>
    /// Negates a <see cref="T:Point"/> value.
    /// </summary>
    /// <param name="value">The value to negate.</param>
    /// <returns>The negated value.</returns>
    private static Point Negate( Point value )
    {
        return new Point(
            -value.X,
            -value.Y
        );
    }

    /// <summary>
    /// Negates a <see cref="T:Thickness"/> value.
    /// </summary>
    /// <param name="value">The value to negate.</param>
    /// <returns>The negated value.</returns>
    private static Thickness Negate( Thickness value )
    {
        return new Thickness(
            -value.Left,
            -value.Top,
            -value.Right,
            -value.Bottom
        );
    }

    /// <summary>
    /// Negates a <see cref="T:Boolean"/> value.
    /// </summary>
    /// <param name="value">The value to negate.</param>
    /// <returns>The negated value.</returns>
    private static bool Negate( bool value )
    {
        return !value;
    }

    /// <summary>
    /// Negates a <see cref="T:Int32"/> value.
    /// </summary>
    /// <param name="value">The value to negate.</param>
    /// <returns>The negated value.</returns>
    private static int Negate( int value )
    {
        return -value;
    }

    /// <summary>
    /// Negates a <see cref="T:Int64"/> value.
    /// </summary>
    /// <param name="value">The value to negate.</param>
    /// <returns>The negated value.</returns>
    private static long Negate( long value )
    {
        return -value;
    }

    /// <summary>
    /// Negates a <see cref="T:Double"/> value.
    /// </summary>
    /// <param name="value">The value to negate.</param>
    /// <returns>The negated value.</returns>
    private static double Negate( double value )
    {
        return -value;
    }

    /// <summary>
    /// Negates a <see cref="T:IConvertible"/> value by round tripping through
    /// the System.Decimal type.
    /// </summary>
    /// <param name="value">The value to negate.</param>
    /// <param name="formatProvider">The culture information.</param>
    /// <returns>The negated value as the original input type.</returns>
    private static object Negate( IConvertible value, IFormatProvider formatProvider )
    {

        TypeCode inputType = value.GetTypeCode( );

        decimal input = value.ToDecimal( formatProvider );
        decimal output = Decimal.Negate( input );

        return System.Convert.ChangeType( output, inputType, formatProvider );

    }

    #endregion

}   // class

Download the Visual Studio 2010 Pro Power Tools

I saw in my feed reader a posting that announced the release of the Visual Studio 2010 Pro Power Tools extension that was available in the Visual Studio 2010 Extension Manager. At first glance I thought it was the Power Tools extension that I’ve been using for a while. However, this is a totally separate extension that adds some very awesome features.

Note that they go into a lot of detail on the enhanced document tab feature but although this is neat and useful, it’s not really in my top 3 features. I’ve emphasized my 3 favorite features.

  • Document Well 2010 Plus
    • Tab Well UI
      • Scrollable tabs
      • Vertical tabs
      • Pinned tabs
      • Show close button in tab well
    • Tab Behavior
      • Remove tabs by usage order (LRU)
      • Show pinned tabs in a separate row/column
    • Sorting
      • Sort tabs by project
      • Sort tabs alphabetically
      • Sort tab well dropdown alphabetically
    • Tab UI
      • Color tabs according to their project or according to regular expressions
      • Miscellaneous options that modify tab UI
        • Show document/toolwindow icon in tab
        • Show close button in tab
        • Modify dirty indicator style
        • Modify minimum and maximum tab size
  • Searchable Add Reference Dialog
  • Highlight Current Line
  • HTML Copy
  • Triple Click
  • Fix Mixed Tabs
  • Ctrl + Click Go To Definition
  • Align Assignments
  • Colorized Parameter Help
  • Move Line Up/Down Commands
  • Column Guides

Never answer your phone, and other great productivity tips from Bob Parsons

I’ll be honest, this guy really grates on my nerves. Although my domains are registered with GoDaddy, I don’t even really like the company. I think their site is disgustingly bloated. The upsell is worse than a car dealership. And the tits and ass marketing makes absolutely no sense to me.

But… I happened to stumble on this video titled "Successful people NEVER answer their phone. Here’s why." If you know me at all, you know I can’t stand answering the phone and I rarely do. So I gave it a look. These are actually great productivity tips and I pretty much agree with every single one of them. Enjoy.

Trick WCF Data Services into supporting $format = json

In the OData specification, the $format parameter can be passed on the query string of the request to tell the server that you would like the response to be serialized as JSON. Normally, to get JSON-formatted data, you have to specify "application/json" in your "Accept" header. The query string feature is handy in situations when it’s not easy or possible to modify the request headers.

Unfortunately, if you try to pass $format on a WCF Data Services query, you will get a response that looks like:

<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
    <code />
    <message xml:lang="en-US">
        The query parameter '$format' begins with a system-reserved
        '$' character but is not recognized.
    </message>
</error>

Unfortunately, WCF Data Services doesn’t support this OData convention. But with a little bit of trickery, you can make it work by modifying the request in an ASP.NET HTTP module.

The trick is to check for the query string parameter before the request gets to WCF Data Services and modify the request headers accordingly. Normally, the Request.Headers collection is read-only. You’ll need to use some simple reflection to make it writable but once you do, it’s just a matter of setting the appropriate Accept header, then rewriting the URL to remove the $format parameter so WCF Data Services doesn’t bitch and moan.

The entire HTTP module is shown below. Like it? Hate it? Let me know in the comments.

<!-- add to web.config -->
<system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
        <add name="ODataFormatModule" type="YourNamespace.ODataFormatModule, YourAssembly" />
    </modules>
</system.webServer>
/// <summary>
/// Intercepts WCF Data Services requests that include a $format parameter on the query
/// string and alters the request headers according to the OData specification.
/// </summary>
public sealed class ODataFormatModule : IHttpModule
{

    #region Constructors

    /// <summary>
    /// Initializes a new instance of the <see cref="T:ODataFormatModule"/> class.
    /// </summary>
    public ODataFormatModule( )
    {
    }

    #endregion

    #region Properties

    /// <summary>
    /// Gets the application instance.
    /// </summary>
    public HttpApplication Application
    {
        get;
        private set;
    }

    /// <summary>
    /// Gets the current HTTP context.
    /// </summary>
    public HttpContext Context
    {
        get
        {
            return HttpContext.Current;
        }
    }

    /// <summary>
    /// Gets the current request.
    /// </summary>
    public HttpRequest Request
    {
        get
        {
            return HttpContext.Current.Request;
        }
    }

    #endregion

    #region Methods

    /// <summary>
    /// Initializes a module and prepares it to handle requests.
    /// </summary>
    /// <param name="context">An <see cref="T:HttpApplication"/> that provides access to the methods,
    /// properties, and events common to all application objects within an ASP.NET application</param>
    public void Init( HttpApplication context )
    {

        Application = context;
        Application.BeginRequest += Application_BeginRequest;

    }

    /// <summary>
    /// Disposes of the resources (other than memory) used by the module that implements
    /// <see cref="T:IHttpModule"/>.
    /// </summary>
    public void Dispose( )
    {
        Application.BeginRequest -= Application_BeginRequest;
        Application = null;
    }

    /// <summary>
    /// Forces the <see cref="T:NameValueCollection"/> to allow modifications by using reflection to
    /// set the IsReadOnly property to false.
    /// </summary>
    /// <param name="collection">The collection to make writable.</param>
    /// <returns>The original collection after the IsReadOnly property has been hacked.</returns>
    private static NameValueCollection MakeWritable( NameValueCollection collection )
    {

        var collectionType = collection.GetType( );
        var isReadOnlyProperty = collectionType.GetProperty(
            "IsReadOnly",
            BindingFlags.Instance |
            BindingFlags.IgnoreCase |
            BindingFlags.NonPublic
        );

        isReadOnlyProperty.SetValue( collection, false, null );

        return collection;

    }

    /// <summary>
    /// Gets a content type for the corresponding format parameter according to the OData specification
    /// http://www.odata.org/developers/protocols/uri-conventions#FormatSystemQueryOption
    /// </summary>
    /// <param name="format">The value of the $format querystring parameter.</param>
    /// <returns>The corresponding Accept request header value.</returns>
    private static string MapToMediaType( string format )
    {

        Contract.Requires( format != null );

        switch ( format.ToLowerInvariant() ) {
            case "atom":
            return "application/atom+xml";
            case "xml":
            return "application/xml";
            case "json":
            return "application/json";
            default:
            return format;
        }   // switch

    }

    #endregion

    #region Event Handlers

    /// <summary>
    /// Handles the BeginRequest event of the Application.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="T:EventArgs"/> instance containing the event data.</param>
    private void Application_BeginRequest( object sender, EventArgs e )
    {

        var format = Request.QueryString["$format"];

        if ( !String.IsNullOrWhiteSpace(format) ) {

            // Ordinarily, Request.Headers is read-only so we need to
            // use some reflection to get around that. Ugly, I know.
            var requestQuery = MakeWritable( Request.QueryString );
            var requestHeaders = MakeWritable( Request.Headers );

            // Set the Accept header the way a well-behaved json client
            // would have done, which WCF Data Services does support
            requestHeaders["Accept"] = MapToMediaType( format );

            // Use URL-rewriting to remove the $format part of the querystring
            // Otherwise, if it gets to WCF Data Services, it barfs
            requestQuery.Remove( "$format" );
            Context.RewritePath( Request.FilePath, Request.PathInfo, requestQuery.ToString( ) );

        }   // if

    }

    #endregion

}   // class