Visual Studio 2008 + .Net 3.5 SP1 is out now

I’ve been counting the seconds for this to happen… It is finally here, Visual Studio 2008 SP1 and .Net 3.5 SP1 is out now. Get it from here.

Before installing this I would suggest that you have a look at this post. Quote from here “When installing Visual Studio 2008 Sp1 Beta1, you may encounter an error that you must first remove KB944899 before setup can continue. This message can be displayed if you have installed any KB for Visual Studio 2008, not just KB944899.”

There could be some issue if you had the SP1 Beta installed so better to have a look instead of crying like a baby after 😀

Do read the Read me file!!!!! It is very important… I had a problem with the following but thanks to the readme file I knew what to do

2.1.9 Windows Automatic Update notification appears during Visual Studio 2008 SP1 installation on Windows Vista

Windows Automatic Update notification to restart the computer may appear when Visual Studio 2008 SP1 is being installed on a Windows Vista computer that does not have .NET Framework 2.0 SP2 and .NET Framework 3.0 SP2 installed. Allowing Windows Update to restart immediately will cause Visual Studio Setup to fail.

To resolve this issue:

Postpone the restart until Visual Studio SP1 installation is finished.

 

And yes it does take a long time, so be patient… it’s worth every second 😀

success

 

Have a nice evening with the brand new SP1… I love you Microsoft…. I LOVE YOU

My wish came true…. I can now use DataBinding in a ConverterParameter

WARNING: This solution uses reflection so it cannot be used in XBAP or applications running with Partial Trust.

One of the things I hear often in forums and also lately on the WPF Disciples mailing list is, “How come I cannot use binding in ConverterParameters?” or “My personal pet peeve is the ConverterParameter. Ah if I could only bind it to something in my ViewModel!!”

So let’s start by seeing why you cannot use binding for a ConverterParameter. The simple answer to that would be, a ConverterParameter is not a DependencyProperty thus you cannot use Binding. Yet the following question would be, WHY isn’t it a DependencyProperty?? Well there are a few things we must have a look at here. First of all the Binding class is not a DependencyObject. Secondly the BindingBase class seals itself when the binding activates, this means that once the Binding is activated you cannot change any properties. If you try to do so you get a nice InvalidOperationException saying “Binding cannot be changed after it has been used”.

Yet, the WPF platform is very flexible so I decided to start digging into it and see what I can come up with (obviously always consulting the WPF KING OF KINGS, Dr.WPF).

The first idea…

My first idea was to create a MarkupExtension that spits out an instance of an object that has a Dependency Property that you can bind with (some sort of Proxy that can update the Binding and specify a new value). So your XAML would look like this

{Binding ElementName=checkbox1, Path=IsChecked, Converter={StaticResource conv}, ConverterParameter={code:BindableParameter {Binding ElementName=checkbox2, Path=IsChecked}} }

Yet this failed miserably because of a simple yet hard problem in the design I had. You cannot get the BindingExpression of that binding because the BindingExpression is not constructed yet. I could get the Binding instance but the Binding instance alone is nothing without the BindingExpression since you can update a binding by calling the UpdateSource method of the Binding expression.

Back to the drawing boards…. and finally the Solution

So let’s have a look at what we want to achieve. We want to

1. Let the User Specify a Binding for a ConverterParameter somewhere in the XAML
2. Make sure that when a value of the ConverterParameter changes the original Binding gets updated.

In order to solve problem 1, I decided to go to my best friend, AttachedProperties. Basically the idea is that you set an attached property that specifies the value of a ConverterParameter of a specific binding. So the XAML would look something like this

   1: <ToggleButton Content="I am bound to the checkbox" x:Name="toggle"
   2:      code:BindableParameter.BindParameter="{code:BindableParameter ToggleButton.IsChecked, Binding={Binding ElementName=checkbox2, Path=IsChecked}}"
   3:      IsChecked="{Binding Converter={StaticResource conv}, ElementName=checkbox1, Path=IsChecked}"/>

In the attached property you specify what Binding you want to target by supplying the DependencyProperty to which the original Binding is applied. In this case the original Binding is for the IsChecked property of the ToggleButton. Then you can simple specify the Binding you want for the ConverterParameter by setting the Binding property of the BindableParameter markup extension.

Now that you have supplied this information, the BindableParameter can do some tricks for you. Basically once you specify the BindParameter attached property the BindableParameter will get a BindingExpression for the original binding and make sure to set the ConverterParameter when ever needed. Have a look at the PropertyChanged event handler of the BindParameter Attached property.

   1: private static void OnBindParameterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
   2: {
   3:     FrameworkElement element = d as FrameworkElement;
   4:     if (element == null)
   5:         throw new InvalidOperationException("BindableParameter can be applied to a FrameworkElement only");
   6:
   7:     BindableParameter parameter = (BindableParameter)e.NewValue;
   8:     element.Initialized += delegate
   9:     {
  10:         parameter.TargetExpression = BindingOperations.GetBindingExpression(element, parameter.TargetProperty);
  11:         parameter.TargetBinding = BindingOperations.GetBinding(element, parameter.TargetProperty);
  12:
  13:         //update the converter parameter 
  14:         InvalidateBinding(parameter);
  15:     };
  16: }

As you can see, in the above code, all we are doing is get the instance of the BindingExpression and storing it in an instance variable(TargetExpression). Same goes for the Binding, storing it in the TargetBinding. Now that we have all this information we can do Step 2 (Make sure that when a value of the ConverterParameter changes the original Binding gets updated)

In the Property Changed event handler of the Binding we must force the BindingExpression to update and change the value of the converter parameter. This can be done quite easily one would say but there are 2 main problems.

Problem 1. How to make the binding work for the BindableParamater?? The BindableParameter is not in the LogicalTree because it is just a DependencyObject thus the Binding that you set will not be valid. In order to overcome this issue we can do a little trick with the Freezable class. If we make the BindableParameter inherit from the Freezable it gets the inheritance context thus Binding is now valid. For more info on this technique visit Dr. WPF blog

Problem 2. How can we change the value of ConverterParameter if the Binding is sealed (remember? the Binding class will throw an InvalidOperationException if we try to change a property of the Binding). This problem required me to do some hard core disassembling of the Binding class and I found out that each Property Setter of the Binding class has a call to a method CheckSealed. This method looks like this

   1: internal void CheckSealed()
   2: {
   3:     if (this._isSealed)
   4:     {
   5:         throw new InvalidOperationException(SR.Get("ChangeSealedBinding"));
   6:     }
   7: }
   8:

So what we must do is to get the _isSealed Field info by reflection and change it’s value to false, then change the ConverterParameter and finally put the _isSealed value back to true so that WPF does not notice us playing tricks on him 🙂
Once we do that we are free to change the value of the ConverterParameter and we can Refresh the Binding

Something like this

   1: private static void InvalidateBinding(BindableParameter param)
   2: {
   3:     if (param.TargetBinding != null && param.TargetExpression != null)
   4:     {
   5:         //this is a hack to trick the WPF platform in thining that the binding is not sealed yet and then change the value of the converter parameter
   6:         bool isSealed = (bool)isSealedFieldInfo.GetValue(param.TargetBinding);
   7:
   8:         if (isSealed)//change the is sealed value
   9:             isSealedFieldInfo.SetValue(param.TargetBinding, false);
  10:
  11:         param.TargetBinding.ConverterParameter = param.ConverterParameterValue;
  12:
  13:         if (isSealed)//put the is sealed value back as it was...
  14:             isSealedFieldInfo.SetValue(param.TargetBinding, true);
  15:
  16:         //force an update to the binding
  17:         param.TargetExpression.UpdateTarget();
  18:     }
  19: }

And there it is …. I can now use binding for a ConverterParameter and the XAML looks like this

   1: <Window.Resources>
   2:    <code:DummyConverter x:Key="conv"/>
   3: </Window.Resources>
   4: <StackPanel>
   5:    <CheckBox x:Name="checkbox2" Content="I am the parameter for the converter"/>
   6:    <CheckBox x:Name="checkbox1" Content="I am bound directly"/>
   7:
   8:    <ToggleButton Content="I am bound to the checkbox" x:Name="toggle"
   9:                  code:BindableParameter.BindParameter="{code:BindableParameter ToggleButton.IsChecked, Binding={Binding ElementName=checkbox2, Path=IsChecked}}"
  10:                  IsChecked="{Binding Converter={StaticResource conv}, ElementName=checkbox1, Path=IsChecked}"/>
  11: </StackPanel>

Hope you enjoy this …..

DOWNLOAD SOURCE CODE

kick it on DotNetKicks.com

NameScope, my name is Marlon you know….

Introduction

Did you ever wonder why you can have the same name registered for different parts of your XAML? Here is an example (notice the name “border” in different parts of the XAML)

   1: <ContentControl Content="Hello world" x:Name="border">
   2:     <ContentControl.ContentTemplate>
   3:         <DataTemplate>
   4:             <Border BorderBrush="Silver" BorderThickness="1" CornerRadius="5" Margin="20" x:Name="border">
   5:                 <StackPanel>
   6:                     <TextBlock Text="I am a DataTemplate" HorizontalAlignment="Center"/>
   7:                     <ContentPresenter Content="{Binding}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
   8:                 </StackPanel>
   9:             </Border>
  10:         </DataTemplate>
  11:     </ContentControl.ContentTemplate>
  12:
  13:     <ContentControl.Template>
  14:         <ControlTemplate TargetType="ContentControl">
  15:             <Border BorderBrush="Silver" BorderThickness="1" CornerRadius="5" x:Name="border" >
  16:                 <StackPanel>
  17:                     <TextBlock Text="I am a ControlTemplate" HorizontalAlignment="Center"/>
  18:                     <ContentPresenter />
  19:                 </StackPanel>
  20:             </Border>
  21:         </ControlTemplate>
  22:     </ContentControl.Template>
  23: </ContentControl>

As you can see the XAML above border is registered 3 times. This is possible because of WPF Namescopes. Basically the Window(that I am using to put the ContentControl in) has it’s own NameScope the DataTemplate also has it’s own and also the ControlTemplate (some actually implement the INameScope interface themselves).

Namescopes are a very important concept that one must understand. Why? Let me give you an example.

   1: <StackPanel>
   2:     <ContentControl Content="Hello world" x:Name="border">
   3:         <ContentControl.ContentTemplate>
   4:             <DataTemplate>
   5:                 <Border BorderBrush="Silver" BorderThickness="1" CornerRadius="5" Margin="20" x:Name="border">
   6:                     <StackPanel>
   7:                         <TextBlock Text="I am a DataTemplate" HorizontalAlignment="Center"/>
   8:                     <ContentPresenter Content="{Binding}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
   9:                     <CheckBox x:Name="checkbox" Content="Checkbox here" />
  10:                 </StackPanel>
  11:                 </Border>
  12:             </DataTemplate>
  13:         </ContentControl.ContentTemplate>
  14:     </ContentControl>
  15:
  16:     <ToggleButton Content="Toggle button bound to checkbox" IsChecked="{Binding ElementName=checkbox, Path=IsChecked}"/>
  17: </StackPanel>

The XAML above has a ContentControl that has a ContentTemplate with a CheckBox and a Toggle button that is trying to bind to that checkbox. The binding is using ElementName to try to find the checkbox yet that will NOT be successful because the “checkbox” is registered in a different NameScope (remember a DataTemplate has it’s own NameScope!)

Namescope and Animations

Another scenario where NameScopes are heavily used are animation. When you create a Storyboard you specify a Storyboard.TargetName attached property to specify which element you want to animate. Something like this….

   1: <Window.Resources>
   2:     <Storyboard x:Key="animation" >
   3:         <DoubleAnimation To="50" AutoReverse="True" RepeatBehavior="Forever"
   4:                        Storyboard.TargetName="button"  Storyboard.TargetProperty="Height"/>
   5:     </Storyboard>
   6: </Window.Resources>
   7:
   8: <Window.Triggers>
   9:     <EventTrigger RoutedEvent="FrameworkElement.Loaded">
  10:         <BeginStoryboard Storyboard="{StaticResource animation}"/>
  11:     </EventTrigger>
  12: </Window.Triggers>
  13:
  14: <StackPanel>
  15:     <ContentControl Content="Hello world" x:Name="border">
  16:         <ContentControl.ContentTemplate>
  17:             <DataTemplate>
  18:                 <Border BorderBrush="Silver" BorderThickness="1" CornerRadius="5" Margin="20" x:Name="border">
  19:                     <StackPanel>
  20:                         <TextBlock Text="I am a DataTemplate" HorizontalAlignment="Center"/>
  21:                     <ContentPresenter Content="{Binding}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
  22:                     <CheckBox x:Name="checkbox" Content="Checkbox here" />
  23:                 </StackPanel>
  24:                 </Border>
  25:             </DataTemplate>
  26:         </ContentControl.ContentTemplate>
  27:     </ContentControl>
  28:
  29:     <ToggleButton Content="Toggle button bound to checkbox" Height="25" x:Name="button"/>
  30: </StackPanel>

The above code would execute as expected, the ToggleButton named “button” would start animating it’s height when the window is Loaded. But what if you want to animate something in the DataTemplate? If you try to create a Storyboard in the Resources section of the window to animate the Checkbox  named “checkbox” you would get an InvalidOperationException saying ‘checkbox’ name cannot be found in the name scope of ‘NamescopeExample.Window1’. This is because the checkbox lives in a different NameScope from the storyboard. One thing you can do is to move the Storyboard in the DataTemplate.Resources so that the storyboard would be created in the same Namescope of the checkbox. Something like this

   1: <DataTemplate>
   2:     <DataTemplate.Resources>
   3:         <Storyboard x:Key="checkboxAnimation" RepeatBehavior="Forever">
   4:             <ColorAnimation To="Red" AutoReverse="True"
   5:                 Storyboard.TargetName="checkbox" Storyboard.TargetProperty="(Control.Background).(SolidColorBrush.Color)"/>
   6:         </Storyboard>
   7:     </DataTemplate.Resources>
   8:     <Border BorderBrush="Silver" BorderThickness="1" CornerRadius="5" Margin="20" x:Name="border">
   9:         <StackPanel>
  10:             <TextBlock Text="I am a DataTemplate" HorizontalAlignment="Center"/>
  11:         <ContentPresenter Content="{Binding}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
  12:         <CheckBox x:Name="checkbox" Content="Checkbox here" Background="Black" />
  13:     </StackPanel>
  14:     </Border>
  15:     <DataTemplate.Triggers>
  16:         <EventTrigger RoutedEvent="FrameworkElement.Loaded">
  17:             <BeginStoryboard Storyboard="{StaticResource checkboxAnimation}"/>
  18:         </EventTrigger>
  19:     </DataTemplate.Triggers>
  20: </DataTemplate>

Namescope and C# code

But what if you are creating elements in code… One would say out “Easy… Just set the name property” like so….

   1: ToggleButton button = new ToggleButton();
   2: button.Height = 25;
   3: button.Content = "Toggle Button";
   4: button.Name = "button";
   5: container.Children.Add(button);

No no no and NO…. This does not work! Setting the Name property of the control will not register that Control to the NameScope. So how to do it? Easy.. have a look

   1: ToggleButton button = new ToggleButton();
   2: button.Height = 25;
   3: button.Content = "Toggle Button";
   4: NameScope.GetNameScope(this).RegisterName("button", button);
   5: container.Children.Add(button);

All you have to do is, first find in which NameScope you want to register the element (in this case I want to add it to the Window NameScope), secondly register the element to that NameScope by using the RegisterName method of the INameScope interface.

You can even use the RegisterName method of the FrameworkElement. For example if I want to add a Button to a StackPanel, you can ask the StackPanel to register the name of the Button. In my case I could have done like this

   1: ToggleButton button = new ToggleButton();
   2: button.Height = 25;
   3: button.Content = "Toggle Button";
   4: container.RegisterName("button", button);
   5: container.Children.Add(button);

Some other tips and related articles…

If you have an element in the Resources section you will not be allowed to set a name for that element. One way of enabling that element with a name is by using the RegisterName method of the NameScope class as explained above (you might want to set the name for animations for example).

You might want to also implement your own NameScope by implementing the INameScope interface. I saw a very clever solution by doing such a thing, by WPF super hero Andrew Smith.

Josh Smith the WPF Rock star and his Element Spy is also a brilliant article that must be read..

kick it on DotNetKicks.com