Andrej Tozon's blog

In the Attic

NAVIGATION - SEARCH

Visual Studio 2008 and Business Intelligence Projects

If you're tempted to uninstall Visual Studio 2005 after installing Visual Studio 2008 (I've done that immediately), a word of caution... There is currently no support for SQL Server 2005 BI projects in Visual Studio 2008. This means that with uninstalling VS2005 you'll lose the ability to, for example, edit Reporting Services 2005 Reports. Support for RS Reports in VS2008 are planned with the SQL Server 2008 release (due next year), but currently there's no plan to support RS 2005 Reports, only 2008.

So... to continue working with SQL Server 2005 projects, you'll have to have Visual Studio 2005 installed, but... not necessarily the whole thing. If you already uninstalled VS2005, but need it just for SQL2005 BI projects, you can now install the VS2005 shell only. Bring out your SQL2005 installation, look for the file vs_install.msi and run it. After a minute or two of silence, the installer should report that installation was successful. SQL Server Business Intelligence Development Studio, together with VS BI templates, is now back [Without all the clutter that "regular" VS2005 installation brings along].

I can't figure out why Microsoft didn't include SQL2005 BI Projects support in VS2008. I mean - with VS2008 you get all these new and improved designers for wide range of technologies, but for BI projects you'll still have to use the old VS2005 shell. I Hope that changes soon.

How many...

... of those "Visual Studio 2008 has RTM'd" posts have you read today? ;)image

Yes, it's been a busy day... Installed VS2008 this morning, uninstalled VS2005, and life is good. But are we done? Not quite; apparently we'll have to wait a couple of weeks for second-wave bits to hit our disks -  Silverlight tools for RTM, Web Deployment Project Add-in, perhaps Expression Blend 2, ... One of those is of course also the BCL source code for the debugger - I've already configured debugger settings to download and cache the library symbols and this is now the piece that's missing.

Otherwise, the installation went smooth, tested it on Windows XP and Windows Vista. System reboot wasn't required during until the end of the installation.

I couldn't spot much Beta 2 => RTM changes, except perhaps a bit more polished WPF designer, which now includes a property search box for quicker access to properties. Handy, but I kinda preferred my properties being sorted alphabetically instead of categorized. Couldn't find any setting to change that, guess I'll have to get used to it.

More VS2008 posts coming soon...

Windows Live Messenger IM Control

See the icon next to my name on the top-right of my blog page?

WLM presence icon

Green means I'm online, reachable by Windows Live Messenger. Click on the icon and WLM web control will fire up in your browser, ready to use and contact me. Nice and easy, no local WLM installation required. I'll try this presence icon thingy out and leave it right there for some time and see how that turns out. If you want to use it for your site, head this way.

There's also the Windows Live Messenger Presence API, which can be queried programmatically to return user's status. Huh!

More info here.

It's a-Live

This post was written with final version of Windows Live Writer (version 12.0.1366.1026), which was released today, along with other Live products, combined in a single installer:

liveinstaller

[This screenshot was taken on my beta/test laptop, which is... slooow - note the text in yellow. Nice]

I'm happy to announce that my MessengerQuote WLW Plugin continues to work with the release version too.

Get your Live here.

WPF/WinForms Binding Pt.2: Value converters

In previous WPF vs Windows Forms binding post, we left off with pretty useless text binding example - we made the form's title reflect whatever user writes in the textbox:

<Window x:Class="BindingSample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="{Binding ElementName=textBox1, Path=Text}" Height="300" 
Width="300" Loaded="Window_Loaded"> ...
</Window>

public Form1()
{
    InitializeComponent();
    DataBindings.Add("Text", textBox1, "Text");
}

We'll extend this example to make it more flexible about outputting text. How about specifying a text template like "This form now belongs to {0}", where {0} would be replaced with whatever user writes in her textbox? We'll do that with the help of value converters.

To create a value converter in Windows Presentation Foundation, all you have to do is implement the IValueConverter interface:

[ValueConversion(typeof(string), typeof(string))]

public
class TextFormatter:
IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (targetType != typeof(string)) { throw new ArgumentException("Target type must be string", "parameter"); } return string.Format(parameter.ToString(), value.ToString()); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } }

The Convert method takes a couple of parameters: value is the actual value, being passed in by binding, targetType is the type we're binding to, parameter in our case will serve for passing in the text template. We'll ignore culture as we don't need to support different locales at this time. Since we're not supporting converting the text back to initial value, we'll leave ConvertBack method unimplemented.

Next, we'll include our value converter in the binding definition.

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="BindingSample.Window1"
    Height="300" Width="300">
    <Window.Resources>
        <local:TextFormatter x:Key="TextFormatter" />
    </Window.Resources>
    <Window.Title>
        <Binding Path="Text" Converter="{StaticResource TextFormatter}" 
            ConverterParameter="This form now belongs to {0}" 
            ElementName="textBox1" Mode="Default"/>
    </Window.Title>

WPF binding with value converter 

Windows Forms, however, doesn't have something like value converters built in, but you can achieve similar result by using custom classes, which implements similar functionality:

public class SimpleTextFormatter: INotifyPropertyChanged
{
    public string parameter;
    private string value;

    public string Parameter
    {
        get { return parameter; }
        set { parameter = value; }
    }

    public string Value
    {
        get { return value; }
        set
        { 
            this.value = value; 
            OnPropertyChanged("Value"); 
        }
    }

    [Bindable(true)]
    public string FormattedText
    {
        get { return string.Format(Parameter, Value); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}

Using this formatter class is again, very simple. First you have to bind form's Text property to formatter's FormattedText property, then bind the input textbox to it's Value property:

public partial class Form1 : Form
{
    private SimpleTextFormatter formatter = new SimpleTextFormatter();

    public Form1()
    {
        InitializeComponent();
       
        formatter.Parameter = "This form now belongs to {0}";
        DataBindings.Add("Text", formatter, "FormattedText");
        textBox1.DataBindings.Add("Text", formatter, "Value", true, DataSourceUpdateMode.OnPropertyChanged);
    }
        ...
}

Again, no events had to be implemented for this to work, it's just the power of data binding, even when used with Windows Forms.

WPF: When's a Button not a Button

This is a button:

<Button Name="button">Button</Button>

This is a button too:

<ToolBar>
    <Button Name="toolbarButton">Toolbar button</Button>
</ToolBar>

Or is it?

Let's declare a style, targeting a Button type:

<Style TargetType="{x:Type Button}">
    <Setter Property="Background" Value="Green" />
    <Setter Property="Foreground" Value="White" />
</Style>

The result might not be exactly what you expected:

image

Standalone button gets painted according to the declared style, while the button in the ToolBar doesn't. Setting the style explicitly helps:

<ToolBar>
    <Button Name="toolbarButton" 
Style
="{StaticResource ButtonStyle}">Toolbar button</Button
> </ToolBar>

... but that's probably not something we want as we need to apply this style to all the buttons in the given scope.

So what's going on? Well, a ToolBar is a special beast of a control, liking things to be exactly its way, ignoring most of non-direct calls to changing its looks and behavior. It defines and uses some specific resource keys to style its children, and we need to plug into ButtonStyleKey to push our Button style through:

<Style TargetType="{x:Type Button}" x:Key="{x:Static ToolBar.ButtonStyleKey}">
<Setter Property="Background" Value
="Green" />
<Setter Property="Foreground" Value
="White" />
</Style>

Finally, to apply the same style to both common and ToolBar Buttons, we're going to use some of that style inheritance magic:

<Style TargetType="{x:Type Button}" >
    <Setter Property="Background" Value="Green" />
    <Setter Property="Foreground" Value="White" />
</Style>
<Style x:Key="{x:Static ToolBar.ButtonStyleKey}" 
TargetType="{x:Type Button}"
BasedOn="{StaticResource {x:Type Button}}" />
image 
<ToolBar>
    <Button Name="toolbarButton">Toolbar button</Button>
</ToolBar>
<Button Name="button">Button</Button>

Three ways to make your WPF images pop out on MouseOver

There are a couple of ways in WPF to make an image pop out when moving mouse over it. Of course we want the image to pop out smoothly, so in this quick rundown we're going to use the following animation storyboards:

<!-- This storyboard will make the image grow to double its size in 0.2 seconds -->
<Storyboard x:Key
="expandStoryboard">
    <DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleX"
        To="2" Duration
="0:0:0.2" />
    <DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleY"
        To="2" Duration
="0:0:0.2" />
</Storyboard
>
<!-- This storyboard will make the image revert to its original size -->
<Storyboard x:Key
="shrinkStoryboard">
    <DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleX"
        To="1" Duration
="0:0:0.2" />
    <DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleY"
        To="1" Duration
="0:0:0.2" />
</Storyboard
>

One thing worth noticing here is the lack of "From" attribute in animation elements. That's because we want the animation pick up from whatever animation state the image is in to make it smoother. Specifying the beginning value of animation (with e.g. "From='1'" in expandStoryboard) would mean the image growing would always start at its original, not current size.

Triggering storyboards with event handlers

If you like imperative coding, you'll probably rush to implement image's MouseEnter and MouseLeave event handlers to trigger the animations. Image declaration would in Xaml look somewhat like this:

<Image Name="image1" Source="Image1.png" 
UIElement.MouseEnter="image_MouseEnter"
UIElement.MouseLeave="image_MouseLeave">
<Image.RenderTransform>
<!-- Initial values we're going to animate -->
<ScaleTransform ScaleX="1" ScaleY="1"/> </Image.RenderTransform> </Image>

... complemented with a couple of event handlers:

private void image_MouseEnter(object sender, MouseEventArgs e)
{
    Storyboard story = (Storyboard)FindResource("expandStoryboard");
    Image image = sender as Image;
    image.BeginStoryboard(story);
}

private void image_MouseLeave(object sender, MouseEventArgs e)
{
    Storyboard story = (Storyboard)FindResource("shrinkStoryboard");
    Image image = sender as Image;
    image.BeginStoryboard(story);
}

[Both storyboards are declared as resources, hence the use of FindResource method for retrieving them.]

Using Event triggers instead of event handlers

Although there's nothing wrong with the previous method, why not do it all in Xaml? Enter EventTriggers:

<Image Name="image2" Source="Image2.png">
    <Image.Triggers>
        <EventTrigger RoutedEvent="Image.MouseEnter">
            <BeginStoryboard Storyboard="{StaticResource expandStoryboard}" />
        </EventTrigger>
        <EventTrigger RoutedEvent="Image.MouseLeave">
            <BeginStoryboard Storyboard="{StaticResource shrinkStoryboard}" />
        </EventTrigger>
    </Image.Triggers>
    <Image.RenderTransform>
       <ScaleTransform ScaleX="1" ScaleY="1"/>
    </Image.RenderTransform>
</Image>

Looks better, doesn't it?

Finishing with Property triggers

The third method is very similar to the second, except it uses Property triggers instead of Event triggers. Currently, Property triggers have to be declared within a style:

<Style TargetType ="{x:Type Image}">
    <Setter Property="RenderTransform">
       
<Setter.Value>
           
<ScaleTransform ScaleX="1" ScaleY="1"/>
       
</Setter.Value>
   
</Setter>
    <Style.Triggers>
        <Trigger Property="IsMouseOver" Value
="True">
            <Trigger.EnterActions
>
                <BeginStoryboard Storyboard="{StaticResource expandStoryboard
}" />
            </Trigger.EnterActions
>
            <Trigger.ExitActions
>
                <BeginStoryboard Storyboard="{StaticResource shrinkStoryboard
}" />
            </Trigger.ExitActions
>
        </Trigger
>
    </Style.Triggers
>
</Style
>

Additional benefit of using styles is the ability to reuse/apply them to all elements of specified type within the scope the style is declared in. For example, declaring the above style (together with both storyboards) on the application level would generally make all images within application behave the same way. Unless, of course, some images specify their own styles, overriding this behavior.
And the image?

<Image Name="image3" Source="Image3.png" />

[Note that specifying RenderTransform on this Image is no longer needed, because it's already set with the Style.]

WPF vs. Windows Forms (data) binding

When talking to people about (data) binding in Windows Presentation Foundation, I find that a lot of them are amazed with how easy it is to bind some control's property to another, and the first one being able to react to other's changes. I'm surprised how many people still use data binding in windows forms for just that - binding to data sources, mostly datasets. But, the data can be much more that just some information, contain in data carriers like datasets and other objects.

Let's say you have to write some code to control a control's size with a slider (trackbar). In WPF and XAML, this is trivial:

<Canvas>
    <Slider Height="21" Name="slider1" 
        Width="100" Canvas.Left="178" Canvas.Top="10" 
        Minimum="50" Maximum="200" />
    <Rectangle Canvas.Left="50" Canvas.Top="50" 
        Name="rectangle1" Fill="Red" 
        Height="{Binding ElementName=slider1, Path=Value}" 
        Width="{Binding ElementName=slider1, Path=Value}" />
</Canvas>

Rectangle's Width and Height properties are bound to the value of the slider so when the slider's position changes, the rectangle resizes accordingly. How would you do something like that in Windows Forms?

Event handlers?

private void trackBar1_Scroll(object sender, EventArgs e)
{
    panel1.Width = trackBar1.Value;
    panel1.Height = trackBar1.Value;
}

Sure, why not... [panel1 with Red background is used instead of a Rectangle, and TrackBar is a slider]

But, there's another way, using - you guessed it - binding. Instead of responding to every TrackBar's value change for yourself, you can let the framework do the job:

public Form1()
{
    InitializeComponent();
    panel1.DataBindings.Add("Width", trackBar1, "Value");
    panel1.DataBindings.Add("Height", trackBar1, "Value");
}

Another example: main Form's title should mirror whatever user enters in the TextBox. XAML code:

<Window x:Class="BindingSample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="{Binding ElementName=textBox1, Path=Text}" Height="300" 
Width="300" Loaded
="Window_Loaded"> ...
</Window>

And instead of doing this with Windows Forms:

private void textBox1_TextChanged(object sender, EventArgs e)
{
    Text = textBox1.Text;
}

You could simply do this:

public Form1()
{
    InitializeComponent();
    DataBindings.Add("Text", textBox1, "Text");
}

Now, how about binding to a custom object? For example, we want the size of our rectangle change randomly through time, and come up with a class like:

public class Randomizer
{
    private int number;
    private Timer timer;

    public Randomizer()
    {
        PickNumber();
        timer = new Timer();
        timer.Interval = 500;
        timer.Tick += new EventHandler(timer_Tick);
        timer.Enabled = true;
    }

    public int Value
    {
        get { return number; }
    }

    private void timer_Tick(object sender, EventArgs e)
    {
        PickNumber();
    }

    private void PickNumber()
    {
        number = new Random().Next(50, 201);
// Fixed for simplicity
    }
}

The Value property of this class will change twice per second, each time holding a number between 50 and 200.
Let's bind panel's Width and Height properties to the Value this class produces...

private Randomizer r = new Randomizer();
public Form1()
{
    InitializeComponent();
    panel1.DataBindings.Add("Width", r, "Value");
    panel1.DataBindings.Add("Height", r, "Value");
}

... and run the application... but... nothing happens, the panel doesn't change its size. That's because it doesn't know that Value property ever changes. To let panel's bindings be aware of Value changes, our Randomizer class has to send some notifications to any clients, bound to Value property. We'll do this by implementing INotifyPropertyChanged interface. Here's the whole class again:

public class Randomizer: INotifyPropertyChanged
{
    private int number;
    private Timer timer;

    public Randomizer()
    {
        PickNumber();
        timer = new Timer();
        timer.Interval = 500;
        timer.Tick += new EventHandler(timer_Tick);
        timer.Enabled = true;
    }

    public int Value 
    {
        get { return number; }
    }

    private void timer_Tick(object sender, EventArgs e)
    {
        PickNumber();
    }

    private void PickNumber()
    {
        number = new Random().Next(50, 201); // Fixed for simplicity
        OnPropertyChanged("Value");
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}

With INotifyPropertyChanged interface implemented, our rectangle finally starts animating. To conclude, here's how we would use the Randomizer class in WPF:

1. Declare the class as a resource:

<Window.Resources>
    <local:Randomizer x:Key="r" />
</Window.Resources>

2. Bind the rectangle to the Randomizer class, declared as a resource:

<Rectangle Canvas.Left="50" Canvas.Top="50" 
    Name="rectangle1" Fill="Red" 
    Height="{Binding Source={StaticResource r}, Path=Value}" 
    Width="{Binding Source={StaticResource r}, Path=Value}" />

One thing, worth observing here is that rectangle animates even at design time in Visual Studio's IDE, not only at runtime. Enjoy.

Slides from my WPF talks

This is the PowerPoint presentation [in Slovenian language] from my WPF talks I did yesterday and two weeks ago. This was my first time delivering full-day courses and not everything went as originally planned. The first talk suffered from some technical difficulties and classic demos trouble, and for the yesterday, some evil virus got me so there were some fever/sore throat issues, leaving me powerless at the end.

Anyway, I'm not posting any sample code this time, instead I'll be writing some more blog posts on the subject, OK?