[WPF] The Power of Converters

Converters Sample

WPF converters provide a way to apply custom logic to a binding. In this article, we will make use of WPF converters to demonstrate its usefulness. Our sample application is a firewall controller which lets us switch on and off the firewall by clicking a button, changing the ellipse colour accordingly.

Let's start by creating a new WPF Application project. Then we will create a simple Firewall class. The code is pretty straightforward:

 

public class Firewall : INotifyPropertyChanged
{
    /// <summary>
    /// Posible states of the firewall.
    /// </summary>
    public enum States
    {
        On,
        Off
    }

    /// <summary>
    /// Default constructor sets firewall state to off.
    /// </summary>
    public Firewall()
    {
        State = States.Off;
    }

    /// <summary>
    /// Required event for the INotifyPropertyChanged interface.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// The current state of the firewall.
    /// </summary>
    private States _state;

    /// <summary>
    /// Gets or sets the state of the firewall.
    /// </summary>
    public States State
    {
        get { return _state; }
        set
        {
            if (value != _state)
            {
                _state = value;

                // Notifiy that the firewall state has changed.
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("State"));
                }
            }
        }
    }
}

 

Notice that we implement the INotifyPropertyChange interface. This interface is used by the WPF data binding engine to know when a property has changed so it can be updated.

Now we are going to design our sample application via XAML. Again, the code is pretty simple. We will add it inside the default Grid that Visual Studio adds for us when creating a new WPF Application project:

 

<Window.Resources>
    <my:StateToColorConverter x:Key="stateToColorConverter" />
</Window.Resources>

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition  />
        <RowDefinition  />
        <RowDefinition  />
    </Grid.RowDefinitions>
    
    <StackPanel 
        Grid.Column="0" 
        Grid.Row="0" 
        Orientation="Horizontal" 
        HorizontalAlignment="Center">
        <Ellipse 
            Width="60" 
            Height="60" 
            Fill="{Binding State, Converter={StaticResource stateToColorConverter}, ConverterParameter=Green}" />
    </StackPanel>
    <StackPanel 
        Grid.Column="0" 
        Grid.Row="1" 
        Orientation="Horizontal" 
        HorizontalAlignment="Center">
        <Ellipse 
            Width="60" 
            Height="60" 
            Fill="{Binding State, Converter={StaticResource stateToColorConverter}, ConverterParameter=Red}" />
    </StackPanel>
    <StackPanel Grid.Column="1" Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center">
        <Button
            x:Name="btnOn"
            Width="100" 
            Height="25" 
            Margin="5,5,5,5" 
            Content="On" 
            Click="OnClicked"/>
        <Button 
            x:Name="btnOff"
            Width="100" 
            Height="25" 
            Margin="5,5,5,5"
            Content="Off"
            Click="OffClicked" />
    </StackPanel>
</Grid>

 

Let's explain a couple of things about this code: As you can see, we have added a StateToColorConverter declaration. This is our custom converter that we will create in a moment. For this declaration to work, we need to add our custom my namespace, so our application knows where to find that resource:

 

xmlns:my="clr-namespace:ConvertersSample"

The next interesting thing about our XAML code is the Ellipse Fill property. We make use of binding, telling that it is the State property of our firewall class the property we want to bind. Since the State property is just a simple Enum and not a SolidColorBrush, our application simply won't work. Here's where converters play their role. As you can see in the code, we have added a StateToColorConverter converter passing a parameter, depending on the firewall state and the colour we want to associate to it.

Let's now write our converter:

 

public class StateToColorConverter : IValueConverter
{
    public enum StateColor
    {
        Green,
        Red
    }

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Firewall.States state = (Firewall.States)value;
        StateColor stateColor = (StateColor)Enum.Parse(typeof(StateColor), (string)parameter);

        switch (state)
        {
            case Firewall.States.On:
                if (stateColor == StateColor.Green)
                {
                    return new SolidColorBrush(Colors.Green);   
                }
                break;
            case Firewall.States.Off:
                if (stateColor == StateColor.Red)
                {
                    return new SolidColorBrush(Colors.Red);   
                }
                break;
        }

        return new SolidColorBrush(Colors.Gray);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }
}

First of all, we have added a StateColor Enum with the values of green and red. This will be use to convert our parameter (see Ellipse Fill property in previous code snippet) to a SolidColorBrush depending on the state of the firewall.

The Convert method has a value parameter. This value is the State parameter we bind the Ellipse Fill property to in our XAML. This parameter will let us know wether the firewall state is on or off. Then, depending of it and the colour we want to apply to each of the states, we will return the correct colour back to the Ellipse Fill property.

Finally, we will add some logic to code behind of our sample application:

 

public Firewall Firewall {get; set;}

public Window1()
{
    InitializeComponent();

    Firewall = new Firewall();
    // Set the DataContext to our Firewall object.
    DataContext = Firewall;
}

private void OnClicked(object sender, RoutedEventArgs e)
{
    Firewall.State = Firewall.States.On;
}

private void OffClicked(object sender, RoutedEventArgs e)
{
    Firewall.State = Firewall.States.Off;
}

Here, we create a public Firewall property, then we assign it to our application DataContext. This means that our Firewall object and its properties will be available for binding in our application context(The Ellipse Fill property uses its State property). Also, we added a couple of methods attached to the On and Off buttons Click event. Those methods will simply change the firewall State property accordingly. After one of those buttons are clicked, the INotifyPropertyChange interface together with the data binding engine will do its magic, then our converter will be called to get the correct colour for our ellipses.

If everything has been done correctly, you should be able to run the sample application and change the state of the firewall. Enjoy!

[WPF] Cool effects with Styles & Triggers

Final Result

Today we will learn how to apply cool effects to our application making use of Styles and Triggers. In a previous article, I introduced WPF Styles and explained one of its main uses. Please read it if you still haven’t.

Let’s start by creating a new WPF Application project in Visual Studio. We are going to edit some default properties, so our XAML will look like this:

<Window x:Class="TriggersSample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Cool effects with styles and triggers" Height="300" Width="400" Background="CadetBlue">

We are going to start from the interesting part in this article. So now, before adding any controls to our application, let’s open App.xaml. We will add the styles that our controls will use.

Let’s start by creating a new style for a title label. This label’s size will be bigger than default and will have an outer glow effect, similar to the text over glass in Windows Vista. The style will be as follows:

<Style x:Key="TitleLabelStyle" TargetType="{x:Type Label}">
            <Setter Property="FontSize" Value="24" />
            <Setter Property="HorizontalAlignment" Value="Center" />
            <Setter Property="BitmapEffect">
                <Setter.Value>
                    <OuterGlowBitmapEffect GlowColor="White" GlowSize="7"/>
                </Setter.Value>
            </Setter>
        </Style>

As you can see, styles are pretty straightforward and self-explaining. Notice, however, that for the OuterGlowBitmapEffect we have to explicitly declare its Value since it is a more complex property than, for instance, FontSize.

Let’s now add another style for a label. This time the label will be similar to the default one except for the font size and the glow effect:

<Style x:Key="LabelStyle" TargetType="{x:Type Label}">
            <Setter Property="FontSize" Value="14" />
            <Setter Property="Height" Value="30" />
            <Setter Property="Width" Value="120" />
            <Setter Property="BitmapEffect">
                <Setter.Value>
                    <OuterGlowBitmapEffect GlowColor="White" GlowSize="5"/>
                </Setter.Value>
            </Setter>
        </Style>

There isn't too much to explain here since it is almost the same style as the title label uses. In a future article I will show you how to “inherit” styles so you don't have to repeat properties for controls of the same type.

Finally, we will add a new style for a textbox. This style will make use of Triggers. This let us change the control’s appearance when a specific event or condition takes place:

<Style x:Key="TextBoxStyle" TargetType="{x:Type TextBox}">
            <Setter Property="FontSize" Value="14" />
            <Setter Property="Width" Value="180" />
            <Setter Property="Height" Value="30" />
            <Setter Property="VerticalContentAlignment" Value="Center" />
            <Style.Triggers>
                <Trigger Property="IsFocused" Value="True">
                    <Setter Property="BitmapEffect">
                        <Setter.Value>
                            <OuterGlowBitmapEffect GlowColor="Purple" GlowSize="8"/>
                        </Setter.Value>
                    </Setter>
                </Trigger>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="BitmapEffect">
                        <Setter.Value>
                            <OuterGlowBitmapEffect GlowColor="Gold" GlowSize="8"/>
                        </Setter.Value>
                    </Setter>
                </Trigger>
            </Style.Triggers>
        </Style>

Notice here the use of Triggers. When the textbox’s IsFocused property is true it will show a purple glow effect; when the IsMouseOver property is true, it will show a gold glow effect. This gives us a wide array of possibilities to play with, getting cool effects as the ones shown in this article.

Now let’s back to our Window1.xaml XAML code. We will now add the controls and their Style properties. Add a StackPanel whose Orientation property is set to Vertical and its Margin property to 10,10,10,10. The rest of controls will be declared inside this StackPanel.

Then add the title label setting its Style property to the one we have previously declared. Add whatever text as its content.

Add a new StackPanel whose Orientation property is set to Horizontal and its margin property to 10,10,10,10. Inside this StackPanel, let’s add a Label and a TextBox control. Set their Style property accordingly.

Now copy and paste the previous StackPanel and its contents so we end up with 3 labels and 3 textboxes. This is not crucial, but this way we can better test the IsFocused and IsMouseOver glow effects with multiple textboxes. The code should look like this:

<StackPanel Orientation="Vertical" Margin="10,10,10,10">
        <Label Style="{DynamicResource TitleLabelStyle}">Outer glow text</Label>
        <StackPanel Orientation="Horizontal" Margin="10,10,10,10">
            <Label Style="{DynamicResource LabelStyle}">Option 1</Label>
            <TextBox Style="{DynamicResource TextBoxStyle}"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Margin="10,10,10,10">
            <Label Style="{DynamicResource LabelStyle}">Option 2</Label>
            <TextBox Style="{DynamicResource TextBoxStyle}"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Margin="10,10,10,10">
            <Label Style="{DynamicResource LabelStyle}">Option 3</Label>
            <TextBox Style="{DynamicResource TextBoxStyle}"/>
        </StackPanel>
    </StackPanel>

It’s time to run the application. If everything is right, you should be able to test the effects we have just added to our controls using Styles and Triggers. Enjoy!

[WPF] Binding to a Control

Final

 

WPF provides powerful data-binding capabilities, yet easy to implement and understand that let you develop applications by writing a few lines of code. In this article I will show you how to bind control properties to other control properties without writing any code-behind. The sample application contains to Slider controls and one Button. The sliders will modify both the Height and the Width properties of the button in real-time. In order to achieve this, we bind the sliders' Value property to the Height and the Width properties of the button.

 

Let's start by firing up Visual Studio and creating a new WPF Application project. After that, we will change the size of our application so the contents that we will be adding later can fit. Use 400 for the Height and 500 for the Width properties of the Window.

Next we are going to replace the default Grid for a StackPanel. So our XAML should look like this so far:

<Window x:Class="BasicBinding.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Basic Binding" Height="400" Width="500">
    <StackPanel>

    </StackPanel>
</Window>

Now we are going to start adding controls to our application. Let's start by adding two Label and two Slider controls:

<Label>Button's Height:</Label>
<Slider x:Name="sliderHeight" Margin="5,5,5,5" Height="50" Maximum="150" Minimum="20" Value="50"></Slider>
<Label>Button's Width:</Label>
<Slider x:Name="sliderWidth" Margin="5,5,5,5" Height="50" Maximum="150" Minimum="20" Value="50"></Slider>

 

The sliders' properties are self-explanatory: we have set a maximum of 150, a minimum of 20 and a start value of 50. This way, the button will be always visible even though the sliders' value is set to its minimum.

Now it's time to add the button, which is the interesting part of this article:

<Button x:Name="button" Width="{Binding ElementName=sliderWidth, Path=Value}" Height="{Binding ElementName=sliderHeight, Path=Value}">Button</Button>

As you can see, we are binding the sliders' Value property to both the Height and the Width properties of the button. Let's explain some concepts used here:

  • The ElementName property is one of the ways you can explicitly set the source of a Binding and override the inherited data context. More info.
  • Use the Path property to specify the source value you want to bind to (normally the name of the property of the source object to use for the binding, such as Path=PropertyName). More info.

It's time to test the application. If everything is right, you should be able to resize the button using the sliders.

As we have seen, WPF data-binding is very powerful and easy to implement. It saves you a lot of code and is quite flexible. Now it is your turn to play with it. Enjoy.

[WPF] Uniform look and maintainability using Styles

Styles are very common concept in web and application development. A button's height, width, font color or font style are considered part of that button's style. In this article I will show you how to make use of the WPF styles to achieve a high level of maintainability, uniform look and cleaner code in your application.

 

Let's start by firing up Visual Studio and creating a new WPF Application project. Once the project has been created, we will create a Button with some basic but new features:

<Button Content="Button" 
                Width="200" 
                Height="100" 
                FontSize="34" 
                Foreground="White" 
                Background="DarkGreen" />

The button should look like this:

 

Green Button

 

Now imagine you have around 10 buttons in your application that have the same style. It is not hard to guess that your code will become quite repetitive and messy. This is one of the reasons WPF Styles exist. Let's move all those properties to a better place so we can reuse them easily with little or no effort.

 

Let's open the App.xaml file in Visual Studio. We will add all the button custom properties into a  Style. The syntax is pretty basic and the result will be this:

<Application.Resources>
        <Style x:Key="MyButtonStyle" TargetType="Button">
            <Setter Property="Background" Value="DarkGreen" />
            <Setter Property="Foreground" Value="White" />
            <Setter Property="FontSize" Value="34" />
            <Setter Property="Width" Value="200" />
            <Setter Property="Height" Value="100" />
        </Style>
 </Application.Resources>

Now its use will be:

 

<Button Content="Button" Style="{StaticResource MyButtonStyle}" />

As you can see, now the code is much cleaner, can be maintained easily and will provide an uniform look to your application by writing few lines of code. Let's explain some of the things we have seen in these code snippets:

  • The x:Key is the name by which that style will be referenced in our XAML using the Style property.
  • The TargetType tell us that this style will be applied only to Button objects.
  • For more information about why we have used StaticResource please visit MSDN Resources Overview.

 

As we have seen, the use of Styles in WPF is really easy and gives us lots of advantages over declaring properties in line. There is more advanced uses of Styles, but we will see that in future articles on this blog. Enjoy.

[WPF] Basic layout using the Grid

The final result

Your application layout is one of the first things you have to plan before starting the actual development. In this basic tutorial, I will show you how to design a basic layout for your applications using the Grid control.

 

First of all, we will need to create a new WPF Application project. To do so, fire up Visual Studio and select File > New > Project... Choose WPF Application and click OK. Once your project has been created, we will change the size of our application window so we can better see our progress as shown in the following code snippet:

<Window x:Class="WPFBasicLayout.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WPF Basic Layout" Height="350" Width="500">
    <Grid>

    </Grid>
</Window>

Notice that Visual Studio automatically places a Grid control for us. The Grid is the most complex layout control and probably the one we will use the most. Our next task is to declare columns and rows definitions inside our Grid. The idea is to have four parts in our application: the header, the footer, a sidebar and the main content.

<Grid.ColumnDefinitions>
    <ColumnDefinition />
    <ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
    <RowDefinition />
    <RowDefinition />
    <RowDefinition />
</Grid.RowDefinitions>

So far, our window should look like this in the Visual Studio designer:

Rows and columns definitions

To keep this tutorial simple, we will use Border and Label controls as the content of the four parts of our application. We will add one Border and a Label for each part of our application. Notice how we place them in the row and column we want using Grid.Row and Grid.Column properties respectively:

<Border Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" BorderBrush="LightBlue" BorderThickness="2,2,2,2" CornerRadius="10,10,10,10" Margin="05,05,05,05">
    <Label FontSize="24" VerticalAlignment="Center" HorizontalAlignment="Center">Header</Label>
</Border>
<Border Grid.Column="0" Grid.Row="1" BorderBrush="LightBlue" BorderThickness="2,2,2,2" CornerRadius="10,10,10,10" Margin="05,05,05,05">
    <Label FontSize="24" VerticalAlignment="Center" HorizontalAlignment="Center">Sidebar</Label>
</Border>
<Border Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="2" BorderBrush="LightBlue" BorderThickness="2,2,2,2" CornerRadius="10,10,10,10" Margin="05,05,05,05">
    <Label FontSize="24" VerticalAlignment="Center" HorizontalAlignment="Center">Footer</Label>
</Border>
<Border Grid.Column="1" Grid.Row="1" BorderBrush="LightBlue" BorderThickness="2,2,2,2" CornerRadius="10,10,10,10" Margin="05,05,05,05">
    <Label FontSize="24" VerticalAlignment="Center" HorizontalAlignment="Center">Main Content</Label>
</Border>

Notice also the Grid.ColumnSpan property. That means that that specific column will take two columns, beginning from the one it was placed. This happens with the header and the footer because we want then to take all the width they have available.

In future posts, I will show you how to move those repeated properties into Styles for cleaner code.

Our application is getting the look we are looking for, but as you can see we got some problems: the header and the footer are too big and the sidebar and the main content are taking the same space. What we want is a smaller header and footer and a thinner sidebar, so the room left is taken by the main content. In order to get the desired effect, we need to add Width and Height properties to some of the ColumnDefinition and RowDefinition elements respectively. We will set those properties to Auto for the the first column and for the first and third row. That way, the header, the footer and the sidebar will resize accordingly based on the size of their content. All the room left will be available for the main content.

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

Now it is time to run our application and check the final result. As you can see, the layout is pretty basic but quite common and useful. Notice how the different parts of our application are resized accordingly when the application is resized or maximized.

Now that you have this basic layout set up, it is up to you to add controls, images and text to improve the results.