Andrej Tozon's blog

In the Attic

NAVIGATION - SEARCH

Gradient eyedropper in Expression Blend

Gradient eyedropper proved to be one of the fun features for presenting Windows Presentation Foundation/Expression Blend. While fun for presenting, its ability to capture the color spectrum of the mouse-crossed area is useful in real-time designing too.

Try this for example... Start up your Blend, create a new project and put a rectangle on a window. Select Gradient brush for rectangle's Fill property and click-select the Gradient eyedropper tool (next to the gradient/color selector):

Gradient eyedropper

With eyedropper selected, drag a mouse, holding the left button, vertically across the rainbow color scale (part of the color selector). And here comes the rainbow rectangle...

Rainbow rectangle

You can color swipe any area of the screen, as long as your eyedropper cursor stays inside Blend's main window. This is somehow different to using the "regular" Color eyedropper tools, which allows you to capture even colors outside Blend's bounds.

Now go color your life ;)

On a side note: Expression Blend 2 December Preview is out.

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?

Event handlers and VS2008-B2 WPF designer

Not being able to easily create event handlers for controls' events in Visual Studio's WPF designer posed as a potential turn off and a show stopper for less experienced developers, trying out the early bits of different incarnations of WPF designers. Beta 2 of Visual Studio 2008 (pka "Orcas") adds significant improvement with this issue: to begin with - double clicking on user control in the designer will create the default event handler for that control, as we're used with Windows Forms. Adding other event handlers is done through XAML part of the designer:

Adding event handler

Selecting <New Event Handler> in the above example would create the following code:

private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
{

}

And to later navigate to that event handler, there's a context menu navigation option right under your fingers:

Context menu

The best part is that event handler creation isn't limited to single (selected) event handler. If you're starting with pre-created XAML file, and event handler names are already there, but without any generated code, just select all necessary controls and choose "Navigate to Event Handler" from the context menu and all missing handlers will be created for you. Without the actual implementation, of course; this one is still up to you :)