WPF Ribbon RTW now available for download

0

Microsoft just made available the July release of the Microsoft Ribbon for WPF in MSDN. This is the RTW release of the Ribbon control, compatible with WPF 3.5sp1 and WPF 4.

This release is a managed implementation of the Ribbon for WPF. The Ribbon is a command bar that organizes the features of an application into a series of tabs at the top of the application window, is designed to help you quickly find the commands that you need to complete a task. The Ribbon user interface (UI) increases discoverability of features and functions, enables quicker learning of the application, and helps users feel more in control of their experience with the application. The Ribbon replaces the traditional menu bar and toolbars.

WindowsLiveWriter_MicrosoftRibbonforWPF_F221_image_3[1]

Besides the Ribbon download itself, there’s also a sample installer available. These samples include:

  • RibbonWindow Wordpad Sample This sample illustrates a Ribbon control hosted within a RibbonWindow that emulates the Wordpad appearance.
  • RibbonWindow MVVM Sample This sample illustrates a Ribbon control hosted within a RibbonWindow that is completely populated from a view-model collection.
  • RibbonBrowser Wordpad sample This sample illustrates a Ribbon control hosted within a browser window that emulates the Wordpad appearance.
  • RibbonBrowser MVVM sample This sample illustrates a Ribbon control hosted within a browser window that is completely populated from a view model collection.

You can download WPF Ribbon Control for WPF here.

Technorati Tags:

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

WPF ListView Styling Tutorial Part II

3

In the previous article I demonstrated how to fully style a GridView column header in a ListView. In this next article, I’ll be covering row styling and final wrap ups, focusing on maintaining every behavior that’s expected from a typical grid row.

This time around, I’ll create and customize a template for each column, thus overriding all the visual aspects of a single row. The first step is to change the GridView column declarations and set the CellTemplate attribute to a local resource instead of the previous simpler approach, that used DisplayMembershipBinding and simple TextBlock based data templates. So for starters, I’ll change the ListView xaml declaration to reference new DataTemplates in each column:

<ListView Name="ListView" ItemsSource="{Binding}" ItemContainerStyle="{DynamicResource ListViewItemContainerStyle}">
    <ListView.View>
        <GridView>
            <GridViewColumn CellTemplate="{StaticResource PersonItemTemplate}" Header="Name"/>
            <GridViewColumn CellTemplate="{StaticResource AgeItemTemplate}" Header="Age" />
            <GridViewColumn CellTemplate="{StaticResource MovieItemTemplate}" Header="Favorite Movie" />
        </GridView>
    </ListView.View>
</ListView>

Notice that I’ve also referenced an ItemContainerStyle resource. This will be used to define generic row behavior upon selection and mouse over.

Now, let’s define each column style separately:

<DataTemplate x:Key="AgeItemTemplate">
    <Border BorderThickness="0,0,0,0" BorderBrush="#6FBDE8">
        <TextBlock Margin="2" Text="{Binding Age}" VerticalAlignment="Center" Grid.Column="1" />
    </Border>
</DataTemplate>

<DataTemplate x:Key="PersonItemTemplate">
    <Border BorderThickness="0,0,0,0" BorderBrush="#6FBDE8">
        <Grid Margin="2">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="32" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Image Source="Images/person.png" Width="24" Height="24" Grid.Column="0" HorizontalAlignment="Center" />
            <TextBlock Text="{Binding Name}" VerticalAlignment="Center" Grid.Column="1" />
        </Grid>
    </Border>
</DataTemplate>

<DataTemplate x:Key="MovieItemTemplate">
    <Border BorderThickness="0,0,0,0" BorderBrush="#6FBDE8">
        <Grid Margin="2">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="32" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Image Source="Images/movie.png" Width="24" Height="24" Grid.Column="0" HorizontalAlignment="Center" />
            <TextBlock Text="{Binding FavoriteMovie}" VerticalAlignment="Center" Grid.Column="1" />
        </Grid>
    </Border>
</DataTemplate>

Each one of these visual structures will be nested within an item container, whose style we should define in order to provide visual responses to events like row selection, mouse over, like I mentioned earlier. I’ll then define the ItemContainerStyle resource named ListViewItemCongainerStyle like so:

<Style x:Key="ListViewItemContainerStyle" TargetType="{x:Type ListViewItem}">
    <Setter Property="Background" Value="#ffffff" />
    <Setter Property="HorizontalContentAlignment" Value="Left" />
    <Setter Property="VerticalContentAlignment" Value="Center" />
    <Setter Property="Foreground" Value="Black" />
    <Setter Property="Margin" Value="0,0,0,0" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListViewItem}">
                <Border x:Name="Bd" Background="{TemplateBinding Background}" SnapsToDevicePixels="true" BorderThickness="0,0,0,1" BorderBrush="#6FBDE8">
                    <GridViewRowPresenter VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsSelected"  Value="true">
                        <Setter TargetName="Bd" Property="BorderBrush" Value="#FF143c65" />
                        <Setter Property="Background" TargetName="Bd">
                            <Setter.Value>
                                <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
                                    <LinearGradientBrush.GradientStops>
                                        <GradientStopCollection>
                                            <GradientStop Color="#FF75aac7" Offset="0"/>
                                            <GradientStop Color="#FF143c65" Offset="1"/>
                                        </GradientStopCollection>
                                    </LinearGradientBrush.GradientStops>
                                </LinearGradientBrush>
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter TargetName="Bd" Property="Background" Value="#e0eff8" />
                    </Trigger>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsSelected" Value="true" />
                            <Condition Property="Selector.IsSelectionActive" Value="True" />
                        </MultiTrigger.Conditions>
                        <Setter Property="Background" TargetName="Bd">
                            <Setter.Value>
                                <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
                                    <LinearGradientBrush.GradientStops>
                                        <GradientStopCollection>
                                            <GradientStop Color="#FF75aac7" Offset="0"/>
                                            <GradientStop Color="#FF143c65" Offset="1"/>
                                        </GradientStopCollection>
                                    </LinearGradientBrush.GradientStops>
                                </LinearGradientBrush>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="BorderBrush" TargetName="Bd" Value="#FF143c65"/>
                        <Setter Property="Foreground" Value="White"/>
                    </MultiTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Notice that the GridViewRowPresenter container object marks the place where actual row data will appear and defines its layout. Header style template can be defined through the ColumnHeaderContainerStyle property, although in the current example, we’ve already defined a generic GridViewColumnHeader template in part I of this tutorial.

This is what we have so far:

Now if you notice closely, you can see that the ListView column header row has a slight left and right offset of about 2px. After inspecting this with Snoop, it becomes clear that the GridViewHeaderRowPresenter object, which is the object used to define the layout of our row of column headers, has a margin set to 2,0,2,0.

To counter this, we must also override the ScrollViewer style for the ListView, exposing all the layout attributes and customize them at our will. In this style I’ll set margin to zero and fine tune column header offset:

<Style x:Key="{x:Static GridView.GridViewScrollViewerStyleKey}" TargetType="ScrollViewer">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ScrollViewer">
                <Grid Background="{TemplateBinding Background}">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>
                    <DockPanel Margin="{TemplateBinding Padding}">
                        <ScrollViewer DockPanel.Dock="Top" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" Focusable="false">
                            <GridViewHeaderRowPresenter Margin="0,0,0,0" Columns="{Binding Path=TemplatedParent.View.Columns,
                                RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderContainerStyle="{Binding Path=TemplatedParent.View.ColumnHeaderContainerStyle, RelativeSource={RelativeSource TemplatedParent}}"
                                ColumnHeaderTemplate="{Binding Path=TemplatedParent.View.ColumnHeaderTemplate,RelativeSource={RelativeSource TemplatedParent}}"
                                ColumnHeaderTemplateSelector="{Binding Path=TemplatedParent.View.ColumnHeaderTemplateSelector, RelativeSource={RelativeSource TemplatedParent}}"
                                AllowsColumnReorder="{Binding Path=TemplatedParent.View.AllowsColumnReorder, RelativeSource={RelativeSource TemplatedParent}}"
                                ColumnHeaderContextMenu="{Binding Path=TemplatedParent.View.ColumnHeaderContextMenu, RelativeSource={RelativeSource TemplatedParent}}"
                                ColumnHeaderToolTip="{Binding Path=TemplatedParent.View.ColumnHeaderToolTip, RelativeSource={RelativeSource TemplatedParent}}"
                                SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                        </ScrollViewer>
                        <ScrollContentPresenter Name="PART_ScrollContentPresenter"
                                KeyboardNavigation.DirectionalNavigation="Local"
                                CanContentScroll="True" CanHorizontallyScroll="False"
                                CanVerticallyScroll="False"/>
                    </DockPanel>
                    <ScrollBar Name="PART_HorizontalScrollBar" Orientation="Horizontal" Grid.Row="1" Maximum="{TemplateBinding ScrollableWidth}" ViewportSize="{TemplateBinding ViewportWidth}" Value="{TemplateBinding HorizontalOffset}" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/>
                    <ScrollBar Name="PART_VerticalScrollBar" Grid.Column="1" Maximum="{TemplateBinding ScrollableHeight}" ViewportSize="{TemplateBinding ViewportHeight}" Value="{TemplateBinding VerticalOffset}" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"/>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Now to complete styling I will customize the style for the ListView itself, adding a custom background and border. You can then extend this as you wish:

<Style x:Key="{x:Type ListView}" TargetType="ListView">
    <Setter Property="SnapsToDevicePixels" Value="true"/>
    <Setter Property="OverridesDefaultStyle" Value="true"/>
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
    <Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListView">
                <Border Name="Border" BorderThickness="1" BorderBrush="#999999" Background="#DFDFDF">
                    <ScrollViewer Style="{DynamicResource {x:Static GridView.GridViewScrollViewerStyleKey}}">
                        <ItemsPresenter />
                    </ScrollViewer>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsGrouping" Value="true">
                        <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter TargetName="Border" Property="Background" Value="#BBBBBB"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

And this is the final result:

You now have full control over the ListView visual template. Extend it, play with it but most of all, have fun.

You can download the sample solution here straight from our web host. And here’s the summary of all tutorial articles:

WPF ListView Styling Tutorial Part I

WPF ListView Styling Tutorial Part II

Technorati Tags: , ,

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

I’ve recently developed with my team a new UI for setting application preferences. Before we got started, it was important to define not only how we were going to do both technically and visually but also what we would be doing. For such an important piece of UI It was important to define the actual look and feel of the interface we were about to create. So, besides Blend, we found the occasion appropriate SketchFlow, and soon created a new work methodology with it, that served both our team and curtomers.

I thought of sharing three resources I read at the time in order to learn SketchFlow essencials:

Technorati Tags: , ,

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

WPF ListView Styling Tutorial Part I

7

This quick article will enable you to take full advantage of the ListView control by creating a simple data model and through a step-by-step incremental approach. I will try to be concise and direct in order for you to keep this article as future development reference.

Lets start by creating a new WPF Window and define a base data model for our sample. We’ll create a ListView control named “ListView”:

<ListView Name="ListView" ItemsSource="{Binding}" />

Window and data context setup:

public partial class ListViewStylingWindow : Window
{
    public ListViewStylingWindow()
    {
        InitializeComponent();
        ListView.DataContext = new ObservableCollection<Person>()
                            {
                                new Person() {Name = "Peter", Age = 22, FavoriteMovie = "Transformers"},
                                new Person() {Name = "Anne", Age = 19, FavoriteMovie = "Lord of the Rings"},
                                new Person() {Name = "John", Age = 25, FavoriteMovie = "Titanic"}
                            };
    }
}

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string FavoriteMovie { get; set; }
}

I’ve added an ObservableCollection with initialized 3 Person class objects to the Data Context of the control. Now let’s configure the ListView layout to accommodate the data structure we’re passing into the control’s DataContext. For this example, the GridView view mode of the ListView will be used.

<ListView Name="ListView" ItemsSource="{Binding}">
    <ListView.View>
        <GridView>
            <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
            <GridViewColumn Header="Age">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Path=Age}" />
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
            <GridViewColumn Header="Favorite Movie">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Path=FavoriteMovie}" />
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
        </GridView>
    </ListView.View>
</ListView>

Notice that in the Age and Movie columns, I’ve purposefully used a CellTemplate definition to show you cell data templating. This is what we have so far:

Capture

So this will be the base from which we will start styling. We will follow a step-by-step styling procedure for easier reference.

Step #1: ListView Column Header styling (GridViewColumn)

We’ll start by adding a few brush styles to the resources collection and then reference it in the column style. Remember that GridView columns are derived from ButtonBase, so you have access to all the behaviors derived from it.

<LinearGradientBrush x:Key="BackgroundBrush" StartPoint="0,0" EndPoint="0,1">
    <LinearGradientBrush.GradientStops>
        <GradientStopCollection>
            <GradientStop Color="#FF6FBDE8" Offset="0"/>
            <GradientStop Color="#FF4385BE" Offset="1"/>
        </GradientStopCollection>
    </LinearGradientBrush.GradientStops>
</LinearGradientBrush>

<LinearGradientBrush x:Key="HighlightBackgroundBrush" StartPoint="0,0" EndPoint="0,1">
    <LinearGradientBrush.GradientStops>
        <GradientStopCollection>
            <GradientStop Color="#FF97d3f3" Offset="0"/>
            <GradientStop Color="#FF4385BE" Offset="1"/>
        </GradientStopCollection>
    </LinearGradientBrush.GradientStops>
</LinearGradientBrush>

<LinearGradientBrush x:Key="BorderBrush" StartPoint="0,0" EndPoint="0,1">
    <LinearGradientBrush.GradientStops>
        <GradientStopCollection>
            <GradientStop Color="#FFAFDDF6" Offset="0"/>
            <GradientStop Color="#FF2969AA" Offset="1"/>
        </GradientStopCollection>
    </LinearGradientBrush.GradientStops>
</LinearGradientBrush>

<LinearGradientBrush x:Key="PressedBorderBrush" StartPoint="0,0" EndPoint="0,1">
    <LinearGradientBrush.GradientStops>
        <GradientStopCollection>
            <GradientStop Color="#FF75aac7" Offset="0"/>
            <GradientStop Color="#FF143c65" Offset="1"/>
        </GradientStopCollection>
    </LinearGradientBrush.GradientStops>
</LinearGradientBrush>

Before we add the final header style, we’ll first add the gripper style. This will allow us to visually define the portion of the header that will respond to column resize and dragging operations.

<Style x:Key="GridViewColumnHeaderGripper" TargetType="Thumb">
    <Setter Property="Width" Value="18"/>
    <Setter Property="Background" Value="#2e566b"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Thumb}">
                <Border Padding="{TemplateBinding Padding}" Background="Transparent">
                    <Rectangle HorizontalAlignment="Center" Width="1" Fill="{TemplateBinding Background}"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

This will add a nice touch to the UI. Now well add the style for the GridViewColumn. This style will aggregate previous resources and provide visual responses for mouse over, press and drag events:

<Style x:Key="{x:Type GridViewColumnHeader}" TargetType="GridViewColumnHeader">
    <Setter Property="HorizontalContentAlignment" Value="Center"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="Foreground" Value="#FFFFFF" />
    <Setter Property="Padding" Value="8"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="GridViewColumnHeader">
                <Grid>
                    <Border Name="HeaderBorder" Padding="{TemplateBinding Padding}" BorderThickness="0,1,0,1" BorderBrush="{StaticResource BorderBrush}" Background="{StaticResource BackgroundBrush}">
                        <ContentPresenter Name="HeaderContent" Margin="0,0,0,1" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                    </Border>
                    <Thumb x:Name="PART_HeaderGripper" HorizontalAlignment="Right" Margin="0,0,-9,0" Style="{StaticResource GridViewColumnHeaderGripper}"/>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="true">
                        <Setter TargetName="HeaderBorder" Property="Background" Value="{StaticResource HighlightBackgroundBrush}"/>
                    </Trigger>
                    <Trigger Property="IsPressed" Value="true">
                        <Setter TargetName="HeaderBorder" Property="Background" Value="{StaticResource PressedBorderBrush}"/>
                        <Setter TargetName="HeaderContent" Property="Margin" Value="1,1,0,0"/>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <Trigger Property="Role" Value="Floating">
            <Setter Property="Opacity" Value="0.7"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="GridViewColumnHeader">
                        <Canvas Name="PART_FloatingHeaderCanvas">
                            <Rectangle Fill="#60000000" Width="{TemplateBinding ActualWidth}" Height="{TemplateBinding ActualHeight}"/>
                        </Canvas>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Trigger>
        <Trigger Property="Role" Value="Padding">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="GridViewColumnHeader">
                        <Border Name="HeaderBorder" BorderThickness="0,1,0,1" BorderBrush="{StaticResource BorderBrush}" Background="{StaticResource BackgroundBrush}"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Trigger>
    </Style.Triggers>
</Style>

And this is the outcome:

This sums up the first part of this ListView styling tutorial. In the next article, I’ll be covering in-depth styling on ListView items. For now, you can download the full sample solution here.

Technorati Tags: ,

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

Perf Tools for WPF 4 now available

0

The perf tools for WPF 4.0 are now available for download, and you can use them for profiling both 3.5 and 4.0 applications.

The tools are included in the Windows SDK 7.1 for Windows 7 and .NET Framework 4.

Technorati Tags: ,

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

iPhone UI Templates and Vector Elements

2

Here are three useful resources for those who are prototyping iPhone apps. To give your demos a realistic look, you can download these iPhone UI elements, available in three different formats:

Adobe Illustrator Vector Elements (.ai) – Mercury Intermedia Blog

Download iPhone UI Vector Elements Now (2.6MB)

Adobe Photoshop (.psd)- teehan-lax Blog

Download The iPhone GUI PSD Here (9MB)

OmniGraffle – Graffletopia

http://graffletopia.com/stencils/413

  

You can also get them in XAML format through Mike Swanson’s Adobe Illustrator to XAML Export plugin.

Technorati Tags: ,

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

Listing an Element’s Attached Properties

1

I was recently confronted with a scenario in witch a xaml element needed to be dynamically replaced and nested in a container control. There’s nothing unusual about this except for the fact that when this happens the element being replaced might have attached dependency properties set on it. Needless to say that in this scenario such operation might have significant impact. Imagine if your element is inside a Canvas panel and has some of its attached properties set, like Canvas.Top or Canvas.Left.

My first approach was to go through reflection on the parent and get all DependencyProperties, then invoke GetValue() on the element for each one. It worked but it got me thinking that there had to be a cleaner way, since Attached Property values collection is internal and not directly accessible. Then I got to know a primitive called MarkupWriter. In fact, I’ve crossed with it before on a previous project but never got to actually use it. This time around I’ll make it official, so I’m sharing a little snippet that checks an element for Attached Properties, followed by an example:

public static IDictionary GetAttachedProperties(DependencyObject element)
{
    var attachedPropertyList = new Dictionary();
    var markupObject = MarkupWriter.GetMarkupObjectFor(element);

    foreach (var prop in markupObject.Properties)
    {
        if (prop.IsAttached)
            attachedPropertyList.Add(prop.DependencyProperty, prop.Value);
    }
    return attachedPropertyList;
}

Here’s a simple usage example:

var border = new Border()
             {
                 Width = 200, Height = 200,
                 BorderBrush = Brushes.Blue,
                 BorderThickness = new Thickness(1)
             };

border.SetValue(Canvas.TopProperty, 10d);
border.SetValue(Canvas.LeftProperty, 50d);

var list = GetAttachedProperties(border);

// Beware that ForEach is a Unity enumerable extension.
list.ForEach(prop => Console.WriteLine("Attached property Name: {0}", prop)); 

/*
Outputs:
Attached property Name: [Left, 50]
Attached property Name: [Top, 10]
*/

 Hope it helps.

Technorati Tags: ,

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

WPF Input Validation Part 3: Markup Extensions

2

In the previous article we took a step further on input validation over WPF controls by means of an attached property. The attached property’s owner would then have the required programming to add validation logic to the control’s target dependency property binding.

Keeping optimization in mind we can go, once again, a step further on this and reduce the code required by implementing our own Binding object, with it’s own validation mechanism, that could be configured by the developer in design time. An example of this methodology would be going from this:

<TextBox x:Name="ValidatedTextBox" Width="200"
    Rules:MandatoryRule.TargetProperty="{x:Static TextBox.TextProperty}"
    Style="{DynamicResource EditableTextBox}" Text="{Binding MyProperty}" />

To this:

<TextBox x:Name="ValidatedTextBox" Width="200"
    Style="{DynamicResource EditableTextBox}"
    Text="{validation:ValidationBinding MandatoryInputRule, MyProperty}" />

So what’s the trick when we wish to replace the good old Binding class by a custom one? The Binding class, like many others also familiar to you like StaticResource, DynamicResource, RelativeSource or Templatebinding, is a MarkupExtension. You can detect MarkupExtensions in XAML by the curly braces. They are the actual indicator of a markup to the XAML parser. So the idea here is to create a new binding-like MarkupExtension and extend it to accommodate binding functionality with built in validation.

Before we dig into the code, I believe a brief explanation on MarkupExtensions is needed.

MarkupExtensions are a XAML concept and can be described as a behavior that the XAML parser acquires when going through the XAML to discard the general treatment of attribute values as either a literal string or a directly string-convertible value and, instead, “pass the ball” to a handling class perform its own logic in the visual tree buildup. In attribute syntax, curly braces ({ and }) indicate a markup extension usage. Its a good alternative when the requirement is more ambitious a type converters implementation on types or properties.

So why a MarkupExtension and not just use nested property element syntax? – you ask. Well, for two reasons. It reduces the amount of code required to perform the task, and also because when using property element syntax, a new instance is created, while a markup extension usage can potentially return an existing instance, and thus can be more versatile or might incur less object overhead. But there’s a disadvantage though, and that’s collections. You can’t define collection elements in attribute syntax, unlike property element syntax. Take the x:Array MarkupExtension for instance:

<x:Array Type="sys:String">
    <sys:String>dot</sys:String>
    <sys:String>Net</sys:String>
    <sys:String>Brainwork</sys:String>
    <sys:String>Rocks!</sys:String>
</x:Array>

Each markup extension identifies itself to a XAML parser by means of a class that derives from MarkupExtension, and provides an implementation of the ProvideValue method. This method defines what object is returned once the markup extension is evaluated. The returned object is typically instantiated or set by using the various string tokens passed to the markup extension.

Finally, with this in mind, lets dig into the code. The following ValidationBinding class is a MarkupExtension that aggregates a validation mechanism and allows its definition in the attribute syntax binding declaration.

[MarkupExtensionReturnType(typeof (object))]
[Localizability(LocalizationCategory.None, Modifiability = Modifiability.Unmodifiable,
    Readability = Readability.Unreadable)]
public class ValidationBinding : MarkupExtension
{
    #region Private Fields

    // Rule collection
    private readonly List rules = new List();

    // Our binding object, pre-initialized with PropertyChanged trigger.
    private Binding binding = new Binding {UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged};

    private ValidationRule rule;

    // Convert string to rule instance.
    private readonly StringToValidationRuleConverter ruleConverter = new StringToValidationRuleConverter();

    #endregion

    #region Public properties

    [DefaultValue(null)]
    public object AsyncState
    {
        get { return binding.AsyncState; }
        set { binding.AsyncState = value; }
    }

    [Browsable(false)]
    public Binding Binding
    {
        get { return binding; }
        set { binding = value; }
    }

    // ...

    [DefaultValue(null)]
    public string XPath
    {
        get { return binding.XPath; }
        set { binding.XPath = value; }
    }

    [DefaultValue(null)]
    public Collection ValidationRules
    {
        get { return binding.ValidationRules; }
    }

    [DefaultValue(null)]
    [EditorBrowsable(EditorBrowsableState.Always)]
    [TypeConverter(typeof (StringToValidationRuleConverter))]
    [ConstructorArgument("ruleName")]
    public ValidationRule Rule
    {
        get { return rule; }
        set
        {
            rule = value;
            rules.Add(rule);
        }
    }

    #endregion

    #region Constructor

    public ValidationBinding()
    {
    }

    public ValidationBinding(string ruleName)
    {
        AddRule(ruleName);
    }

    public ValidationBinding(string ruleName, string path)
        : this(ruleName)
    {
        Path = new PropertyPath(path);
    }

    public ValidationBinding(string ruleName1, string ruleName2, string path)
        : this(ruleName1, path)
    {
        AddRule(ruleName2);
    }

    public ValidationBinding(string ruleName1, string ruleName2, string ruleName3, string path)
        : this(ruleName1, ruleName2, path)
    {
        AddRule(ruleName3);
    }

    #endregion

    #region Implementation

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        if (serviceProvider == null)
            return this;

        var provideValueTarget = serviceProvider.GetService(typeof (IProvideValueTarget)) as IProvideValueTarget;

        DependencyObject targetDependencyObject;
        DependencyProperty targetDependencyProperty;

        CheckCanReceiveMarkupExtension(this, provideValueTarget, out targetDependencyObject,
                                       out targetDependencyProperty);

        if (targetDependencyObject == null || targetDependencyProperty == null)
        {
            return this;
        }

        // Fetch metadata - unused, just for your reference
        var metadata =
            targetDependencyProperty.GetMetadata(targetDependencyObject.DependencyObjectType) as
            FrameworkPropertyMetadata;

        if ((metadata != null && !metadata.IsDataBindingAllowed) || targetDependencyProperty.ReadOnly)
            throw new ArgumentException("");

        // Two-way binding requires a path
        if (
            (binding.Mode == BindingMode.TwoWay || binding.Mode == BindingMode.Default) &&
            binding.XPath == null &&
            (binding.Path == null || String.IsNullOrEmpty(binding.Path.Path))
            )
            throw new InvalidOperationException("Two way binding has no Path.");

        if (rules.Count > 0)
            foreach (var r in rules)
                binding.ValidationRules.Add(r);

        return binding.ProvideValue(serviceProvider);
    }

    ///
    /// This static method validates the holder of the current extension, where it is being defined. It detects the various scenarios
    /// where a MarkupExtension is allowed to be set and tests their candidacy for the assignment.
    ///
    public static void CheckCanReceiveMarkupExtension(MarkupExtension markupExtension,
                                                      IProvideValueTarget provideValueTarget,
                                                      out DependencyObject targetDependencyObject,
                                                      out DependencyProperty targetDependencyProperty)
    {
        targetDependencyObject = null;
        targetDependencyProperty = null;

        if (provideValueTarget == null)
            return;

        var targetObject = provideValueTarget.TargetObject;

        if (targetObject == null)
            return;

        var targetType = targetObject.GetType();
        var targetProperty = provideValueTarget.TargetProperty;

        if (targetProperty != null)
        {
            targetDependencyProperty = targetProperty as DependencyProperty;
            if (targetDependencyProperty != null)
            {
                targetDependencyObject = targetObject as DependencyObject;
                Debug.Assert(targetDependencyObject != null,
                             "DependencyProperties can only be set on DependencyObjects");
            }
            else
            {
                // For the implementation at hand we should do this, because nothing else matters.
                // throw new XamlParseException("Type not assignable.");

                // Moving on with all possible cases...
                var targetMember = targetProperty as MemberInfo;
                if (targetMember != null)
                {
                    // If targetMember is a MemberInfo, then its the CLR Property case.
                    // Setters, Triggers, DataTriggers & Conditions are the special cases of
                    // CLR properties in which DynamicResource and Bindings are allowed.
                    // Since StyleHelper.ProcessSharedPropertyValue prevents calls to ProvideValue
                    // in such cases, there is no need for special code to handle them here. 

                    Debug.Assert(targetMember is PropertyInfo || targetMember is MethodInfo,
                                 "TargetMember is either a CLR property or an attached static setter method");

                    Type memberType;

                    var propertyInfo = targetMember as PropertyInfo;
                    if (propertyInfo != null)
                        memberType = propertyInfo.PropertyType;
                    else
                    {
                        var methodInfo = (MethodInfo) targetMember;
                        var parameterInfos = methodInfo.GetParameters();
                        Debug.Assert(parameterInfos.Length == 2,
                                     "The signature of a static settor must contain two parameters");
                        memberType = parameterInfos[1].ParameterType;
                    }

                    // Check if the MarkupExtensionType is assignable to the given MemberType
                    // This checking allows properties like DataTrigger.Binding, Condition.Binding
                    // HierarchicalDataTemplate.ItemsSource, GridViewColumn.DisplayMemberBinding
                    if (!typeof (MarkupExtension).IsAssignableFrom(memberType) ||
                        !memberType.IsAssignableFrom(markupExtension.GetType()))
                    {
                        throw new XamlParseException("Type not assignable.");
                    }
                }
                else
                {
                    throw new XamlParseException("Type not assignable.");
                }
            }
        }
        else
        {
            throw new XamlParseException("Type not assignable.");
        }
    }

    private void AddRule(string ruleName)
    {
        var validationRule =
            new StringToValidationRuleConverter().ConvertFrom(null, null, ruleName) as ValidationRule;

        if (validationRule != null)
            rules.Add(validationRule);
    }

    #endregion
}

The above code is purposely expanded to better understanding. You can refactor on your implementation afterwards.

Lets start by explaining the two attributes defined for the class. MarkupExtensionReturnType specifies type information for the type returned in the ProvideValue method. We’ve specified object for this example. Localizability specifies the localization attributes for the class. This has to to with the Localization features in WPF. Checkout the LocBaml tool for more info on this. For now the class is being defined as not modifiable by localizers and also not readable.

Next come some private field declarations. The rules list will hold every ValidationRule objects defined in the class declaration in XAML. There’s also a Binding object, which is the foundation of the ValidationBinding class. Everything the extension does is meant with the purpose of configuring and defining this binding instance. That’s why the extension exposes a set of properties that are typical of the binding class, to allow the extension to expose binding behavior to the outside. You are already familiar with all of those, except for the last one, which is:

[DefaultValue(null)]
[EditorBrowsable(EditorBrowsableState.Always)]
[TypeConverter(typeof (StringToValidationRuleConverter))]
[ConstructorArgument("ruleName")]
public ValidationRule Rule
{
    get { return rule; }
    set
    {
        rule = value;
        rules.Add(rule);
    }
}

This property serves the purpose of direct rule definition in the attribute. Like so:

Text="{val:ValidationBinding Rule=MyCustomRule, Path=MyProperty}"

 There are a couple of attributes defined on this class member:

- DefaultValueAtribute: The default attribute the property will have once the class is initialized. This is typically used by designers to reset the member’s value, or even code generators, to determine whether code should be generated for the member or other reflection tasks.

- EditorBrowsableAttribute tells the designer to display this property. This type can be used in a visual designer or text editor to determine what properties or methods are visible to the user when in design mode. The IntelliSense engine in Visual Studio is an example of such usage, because it uses this attribute to determine whether or not to show a property or method.

- TypeConverterAttribute specified the value converter to use when the user specifies the property in attribute syntax. This is typically a string converter.

- ConstructorArgumentAttribute specifies that this property is set by a constructor parameter with the given name. In the ValidationBinding class example, the first parameter in two overloads is “ruleName” and it sets the Rule property afterwards.

That said, It’s time to explain the purpose of the several constructor overloads. In case you don’t know, when dealing with attribute syntax attributes a lot is considered and assumed by the XAML processor. Consider the following example:

Since we are assigning values to properties (hence the “equals” = sign), the XAML parser will assume commas as delimiters for each property set operation. On the other hand, if no assignments are made the processor assumes commas are constructor parameter delimiters:

The text property of this TextBox control is being set to a Binding MarkupExtension object, with the target property as its parameter. Underneath, a one parameter constructor is being called to process the given property name.

So in the ValidationBinding class we define several constructor overloads in order to be able to define more than one ValidationBinding at a time. This is only required for the sake of attribute syntax comfort. It wouldn’t be necessary if you consider property element syntax in your implementation, but then that would be more troublesome wouldn’t it? ;)

Then there’s the ProvideValue method implementation that is responsible for making all the pieces come together. It starts by getting a reference to a IProvideValueTarget object through the IServiceProvider argument provided. It then calls the CheckCanReceiveMarkupExtension method to analyze this extension’s owner characteristics and see if it meets the requirements of our MarkupExtension to be able to execute its purpose, which is data binding validation. Several scenarios are considered and evaluated for this, but the present case targets only DependencyProperties. You should take into account all possible MarkupExtension usages in XAML when validating your own logic. That way you can filter all the scenarios where your code might be used and react accordingly.

To wrap things up, validations are added to the binding object, and the object that is to be set on the property the extension is applied on, is returned. The AddRule method actually adds validation rules to the binding instance. It does so by converting the rule name to the actual object, through reflection.

private void AddRule(string ruleName)
{
    var validationRule = ruleConverter.ConvertFrom(null, null, ruleName) as ValidationRule;

    if (validationRule != null)
        rules.Add(validationRule);
}

 When initialized, the converter checks for all ValidationRules in the executing assembly and collects them in order to hold all possible types and to be able to initialize them on demand, or shall I say, when a compatible rule name is passed onto the ConvertFrom method:

#region #using Directives

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Windows.Controls;

#endregion

namespace ValidationSample4
{
    public class StringToValidationRuleConverter : TypeConverter
    {
        private static readonly Dictionary Rules;

        static StringToValidationRuleConverter()
        {
            Rules = new Dictionary();

            var assembly = Assembly.GetExecutingAssembly();
            foreach (var type in assembly.GetTypes().Where(type => type.IsSubclassOf(typeof (ValidationRule))))
                Rules.Add(type.Name, type);
        }

        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType == typeof (string) || base.CanConvertFrom(context, sourceType);
        }

        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType == typeof (string))
                return true;

            return base.CanConvertTo(context, destinationType);
        }

        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            string text = value as string;

            if (text != null)
            {
                try
                {
                    if (Rules.Any(type => type.Key == text))
                    {
                        var instance = Activator.CreateInstance(Rules);
                        return instance;
                     }
                 }
                 catch (Exception e)
                 {
                     throw new Exception(String.Format("Cannot convert '{0}' ({1}) because {2}", value, value.GetType(), e.Message), e);
                 }
             }
              return base.ConvertFrom(context, culture, value);
        }

         public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
         {
             if (destinationType == null)
                 throw new ArgumentNullException("destinationType");
              var rule = value as ValidationRule;
              if (rule != null && CanConvertTo(context, destinationType))
                 return rule.GetType().Name;
              return base.ConvertTo(context, culture, value, destinationType);
         }
     }
 }

 I guess that wraps it up. But there’s nothing better than give it a go yourself. Take a good look at the example, mess around with it, and feel free to comment this implementation. I’ll continue to evolve this mechanism in following articles.

Here’s the sample with all the code:

Wpf Input Validation (WpfInputValidation.rar)

Includes:

- ValidationSample1 (Base implementation)

- ValidationSample2 (Attached property)

- ValidationSample3 (Attached property – no need for UpdatePropertyTrigger)

- ValidationSample4 (Markup Extension)

In case you missed them, here are the previous articles:

1) Wpf Input Validation Part I – Validation Rules

2) Wpf Input Validation Part II – Attached Properties

Technorati Tags: ,

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

WPF Input Validation Part 2: Attached property approach

3

 In the previous article I’ve shown how to apply Validation Rules to controls in order to prevent/access user input. In the process, user was warned through a visual change in the target control. It’s the simplistic and direct way of doing validation and works perfectly from the UX point of view. However, from the developer point of view, a better implementation is required to ease the quantity of code needed and to isolate concerns.

The idea is to apply validation rules by means of an attached property, in which the owner would have the reference to the control and its target Dependency Property, and the required logic to add the rule object implicitly.

We’ll assume the WPF window of the previous example and proceed from there. The biggest difference rests is the XAML. The TextBox no longer has a validation rule and, instead, an attached property was added. We’ll discuss it afterwards.

<Window x:Class="ValidationSample2.ValidationWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Rules="clr-namespace:ValidationSample2"
    Title="ValidationWindow" Height="200" Width="300">
    <Window.Resources>
        <Style x:Key="EditableTextBox" TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
            <Setter Property="Background" Value="#DDFFDD" />
            <Setter Property="Validation.ErrorTemplate">
                <Setter.Value>
                    <ControlTemplate>
                        <Border BorderBrush="Red" BorderThickness="2">
                            <AdornedElementPlaceholder />
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="true">
                    <Setter Property="Background" Value="#FFDDDD"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid VerticalAlignment="Center" HorizontalAlignment="Center">
        <StackPanel Name="ValidationPanel" >
            <Label>Validated Text Box:</Label>
            <!-- UpdateSourceTrigger is needed in order to raise property change event on input
            and not on focus, which is the default behavior -->
            <TextBox x:Name="ValidatedTextBox" Width="200"
                     Rules:MandatoryRule.TargetProperty="{x:Static TextBox.TextProperty}"
                     Style="{DynamicResource EditableTextBox}" Text="{Binding Path=MyProperty, UpdateSourceTrigger=PropertyChanged}" />
        </StackPanel>
    </Grid>
</Window>

As you can see, things got much simpler. A single property set is all there is in order to set my mandatory input rule. So how do we do this? It’s pretty simple, actually. I’ve created a static class called MandatoryInput and, as you can see in XAML, I’ve defined the TargetProperty attached property and I’m registering on the static constructor. The essence of this implementation happens when this property’s value changes. Check out the full blown implementation that follows:

#region #using Directives

using System;
using System.Windows;
using System.Windows.Controls;

#endregion

namespace ValidationSample2
{
    public static class MandatoryRule
    {
        #region Dependency Properties

        public static readonly DependencyProperty TargetProperty;

        #region Get/Sets

        public static DependencyProperty GetTargetProperty(UIElement target)
        {
            return target.GetValue(TargetProperty) as DependencyProperty;
        }

        public static void SetTargetProperty(UIElement target, DependencyProperty value)
        {
            target.SetValue(TargetProperty, value);
        }

        #endregion

        #endregion

        #region Constructor

        static MandatoryRule()
        {
            TargetProperty = DependencyProperty.RegisterAttached("Target",
                                                                 typeof (DependencyProperty), typeof (MandatoryRule),
                                                                 new UIPropertyMetadata(null, OnTargetPropertyChanged));
        }

        #endregion

        #region Event handlers

        private static void OnTargetPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            if (!(obj is UIElement))
                throw new InvalidOperationException("Object must be a UI element.");

            SetValidationRule(obj, args.NewValue as DependencyProperty);
        }

        #endregion

        #region Methods

        private static void SetValidationRule(DependencyObject obj, DependencyProperty property)
        {
            if (property == null)
                throw new InvalidOperationException("No Validation DependencyProperty attached.");

            GetRule(obj, property);
        }

        private static void GetRule(DependencyObject obj, DependencyProperty property)
        {
            var control = obj as Control;

            if (!control.IsInitialized)
            {
                RoutedEventHandler callback = null;
                callback = delegate
                               {
                                   control.Loaded -= callback;
                                   SetValidationRule(obj, property);
                               };
                control.Loaded += callback;
                return;
            }

            var expression = control.GetBindingExpression(property);
            if (expression == null)
                throw new InvalidOperationException(
                    "The control's validation property must be bound for the Validator to validate it.");

            var binding = expression.ParentBinding;
            if (binding == null)
                throw new ApplicationException("Property binding expression has no parent binding.");

            ValidationRule mandatoryRule = null;
            foreach (var rule in binding.ValidationRules)
            {
                if (rule is MandatoryInputRule)
                {
                    if (mandatoryRule == null)
                        mandatoryRule = rule as MandatoryInputRule;
                    else
                        throw new InvalidOperationException(
                            "There's more than one MandatoryInputRule in the Binding's ValidationRules.");
                }
            }

            if (mandatoryRule == null)
            {
                mandatoryRule = new MandatoryInputRule();
                binding.ValidationRules.Add(mandatoryRule);
            }
        }

        #endregion
    }
}

As an attached property, I had to create the usual Get[PropertyName] and Set[PropertyName] methods so that these could actually set the values in the control. The idea is for this property to hold the target control’s dependency property we are going to interact with, and upon property change notification, execute our logic.

However, this notification actually  comes in two distinct phases. The first one happens when the XAML is processed by the XAML parser and the last is when it’s actually initialized. As you can see in the code, the GetRule() method is called on such occasions, however, binding data will only be available when the affected control is initialized, so it is crucial to do our work only when. So, on the first phase, since the control isn’t yet initialized, we just set an event handler to execute when control is Loaded. This event handler will call the same SetValidationRule() method who attached it in the first place, but in that point in time, it will proceed all the way to the binding manipulation.

So the trick here is to fetch the BindingExpression on the target DependencyProperty of the affected control. Keep in mind that a BindingExpression is an underlying object that knows the connection between the binding source and the binding target. On the other hand, a Binding is merely a higher level object in the binding mechanism that contains all the information about the binding source and the nature of the binding, and can be shared across several BindingExpression objects.

Moving on, with our BindingExpression, we then get the Binding object and add our validation rule to it, validating duplicates in the process. And that’s all there is to it.

I know this already leverages the implementation and code required, and most people would be comfortable with this, but we still must set UpdateSourceTrigger on the Binding object, otherwise input validation only occurs when the textbox loses focus. Since others, and myself would have a “mission incomplete” kind of feeling, we’ll move on.

At this moment, you may be thinking in changing the value of UpdateSourceTrigger in the GetRule() method, where the binding object is exposed:

(...)
var binding = expression.ParentBinding;
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
(...)

 You could indeed to it, and the app would compile just fine. But at runtime you would get the following exception: “Binding cannot be changed after it has been used”. If you think about it, it makes sense, because when a binding is set, the event wiring is created in order for change notifications to go from source to target and vice-versa. So this means that a new binding object must be created, and then set on the target DependencyProperty. The following variant of the GetRule() method exposes this like of thinking:

static void GetRule(DependencyObject obj, DependencyProperty property)
{
    var control = obj as Control;

    if (!control.IsInitialized)
    {
        RoutedEventHandler callback = null;
        callback = delegate
                       {
                           control.Loaded -= callback;
                           SetValidationRule(obj, property);
                       };
        control.Loaded += callback;
        return;
    }

    var expression = control.GetBindingExpression(property);
    if (expression == null)
        throw new InvalidOperationException("The control's validation property must be bound for the Validator to validate it.");

    var binding = expression.ParentBinding;
    if (binding == null)
        throw new ApplicationException("Property binding expression has no parent binding.");

    /*
     * The TextBox.Text property has a default UpdateSourceTrigger value of LostFocus.
     * This means that the text you type into the TextBox does not update the source
     * until the TextBox loses focus. This causes a runtime exception 'Binding cannot
     * be changed after it has been used'. So we must reset the binding.
    */

    if (binding.UpdateSourceTrigger == UpdateSourceTrigger.Default)
    {
        var bind = new Binding() {
                                     Mode = binding.Mode,
                                     UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
                                     Path = binding.Path,
                                     BindsDirectlyToSource = binding.BindsDirectlyToSource,
                                     Converter = binding.Converter,
                                     ConverterCulture = binding.ConverterCulture,
                                     ConverterParameter = binding.ConverterParameter,
                                     FallbackValue = binding.FallbackValue,
                                     IsAsync = binding.IsAsync,
                                     NotifyOnSourceUpdated = binding.NotifyOnSourceUpdated,
                                     NotifyOnTargetUpdated = binding.NotifyOnTargetUpdated,
                                     NotifyOnValidationError = binding.NotifyOnValidationError,
                                     StringFormat = binding.StringFormat,
                                     TargetNullValue = binding.TargetNullValue,
                                     UpdateSourceExceptionFilter = binding.UpdateSourceExceptionFilter,
                                     ValidatesOnDataErrors = binding.ValidatesOnDataErrors,
                                     ValidatesOnExceptions = binding.ValidatesOnExceptions,
                                     XPath = binding.XPath
                                 };

        if (binding.ElementName == null && binding.RelativeSource == null)
            bind.Source = control.DataContext;
        else if (binding.Source == null && binding.RelativeSource == null)
            bind.ElementName = binding.ElementName;
        else
            bind.RelativeSource = binding.RelativeSource;

        binding = bind;
    }

    ValidationRule mandatoryRule = null;
    foreach (ValidationRule rule in binding.ValidationRules)
    {
        if (rule is MandatoryInputRule)
        {
            if (mandatoryRule == null)
                mandatoryRule = rule as MandatoryInputRule;
            else
                throw new InvalidOperationException("There's more than one MandatoryInputRule in the Binding's ValidationRules.");
        }
    }

    if (mandatoryRule == null)
    {
        mandatoryRule = new MandatoryInputRule();
        binding.ValidationRules.Add(mandatoryRule);
    }

    BindingOperations.ClearBinding(obj, property);
    BindingOperations.SetBinding(obj, TextBox.TextProperty, binding);
}

I’ve purposefully cloned a binding object and set its properties for better understanding and so that all the previous settings could be persisted, except for the origin of all this, the UpdateSourceTrigger property.

In the next article we’ll come out with an even better approach using a Markup Extension. It’s nothing new, but makes life a bit easier for the developer, and more clean and extensible from an architectural point of view.

In case you missed them, here is the previous article:

Wpf Input Validation Part I – Validation Rules

Technorati Tags: , , ,

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

WPF Input Validation Part 1: Tutorial and examples

5

I’ve recently set up a sample of a validation mechanism for WPF text input controls on the UI that I thought it would be of general interest due to the “Gokuu approach”* I’ve done with it, otherwise it just wouldn’t make my day :) The requirement is to create a UI control behavior that visually signals validation errors over user input, so when the user submits empty or invalid data on a mandatory field, the input control changes it’s appearance or some kind of action takes place, like a validation message box. Then, it should prevent data submission when a button is clicked or the Enter key is pressed, for instance.

I’m talking about WPF Validation Rules. Validation Rules are objects that apply validation over a data Binding operation, and they are added to the Binding.ValidationRules Collection. They can be created by deriving from the ValidationRule class and overriding its Validate method that should hold the validation logic. Then, normally, you would add the rule to the collection in your xaml code, through property element syntax, or in code.

Although not a part of this article, there’s another validation mechanism built into WPF. You can also test one’s input through an ExceptionValidationRule, which invalidates a value if there are exceptions during source updates of the binding source property. You can even provide custom logic to specify how the binding engine handles these exceptions by using a UpdateSourceExceptionFilterCallback.

These series of articles will focus on creating and applying custom validation rules the most effective way. I’ll discuss this in an incremental way, building up a structured thinking till an acceptable solution is reached.

Moving on… We should then start with a simple WPF application, with it’s main window as our demo canvas. Lets a text control to fetch some user input to validate, say, a TextBox control, and make it data bound to a property that lives on the Window control itself. We’ll set it as it’s own DataContext for that.

<Window x:Class="ValidationSample1.ValidationWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Rules="clr-namespace:ValidationSample1"
    Title="ValidationWindow" Height="200" Width="300">
    <Window.Resources>

    </Window.Resources>
    <Grid VerticalAlignment="Center" HorizontalAlignment="Center">
        <StackPanel Name="ValidationPanel" >
            <Label>Validated Text Box:</Label>
            <TextBox x:Name="ValidatedTextBox"
                     Width="200"/>
            </TextBox>
        </StackPanel>
    </Grid>
</Window>
#region #using Directives

using System.ComponentModel;
using System.Windows;

#endregion

namespace ValidationSample1
{
    /// <summary>
    /// Interaction logic for ValidationWindow.xaml
    /// </summary>
    public partial class ValidationWindow : Window, INotifyPropertyChanged
    {
        public string myProperty;

        public string MyProperty
        {
            get { return myProperty; }
            set
            {
                if (value == myProperty)
                    return;

                myProperty = value;
                OnNotifyPropertyChanged("myProperty");
            }
        }

        public ValidationWindow()
        {
            InitializeComponent();

            DataContext = this;
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnNotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion
    }
}

 Now we need to make sure the user doesn’t submit empty data and visually indicate him that same requirement. For that, we’re going to create a custom ValidationRule to prevent the user from submitting empty text. Like I said, this is done by extending the System.Windows.Controls.ValidationRule class:

#region #using Directives

using System.Globalization;
using System.Windows.Controls;

#endregion

namespace ValidationSample1
{
    public class MandatoryInputRule : ValidationRule
    {
        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            if (value != null)
            {
                string input = value as string;

                if (input.Length > 0)
                    return new ValidationResult(true, null);
            }

            return new ValidationResult(false, "Validation error. Field input required.");
        }
    }
}

The next step is to connect the Validation Rule to the binding target. To do so, you can go either the XAML way or in code. I’ll show you the first approach.

<TextBox x:Name="ValidatedTextBox"
         Width="200">
    <TextBox.Text>
        <!--  Textbox notifies changes when Text is changed, and not focus. -->
        <Binding Path="MyProperty" UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <!--  Validation rule set to run when binding target is updated. -->
                <Rules:MandatoryInputRule ValidatesOnTargetUpdated="True" />
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

Notice that our binding object sets the UpdateSourceTrigger property to PropertyChanged. This is needed because TextBox updates it’s source when it loses Focus and as such, the default value of UpdateSourceTrigger for the TextBox is LostFocus. In this example, this isn’t enough. We need to analyze the data as user writes. So the ideal update behavior is to trigger when data, or property changes, hence the UpdateSourceTrigger.PropertyChanged value in the preceding example.

For now, our binding is empty value-aware due to the validation rule we applied. But wait! If we run the app, nothing happens. It still doesn’t manifest visually when user submits no text. We must specify a style behavior for when validations errors occur, the user gets warned through visual changes in the control. So we’ll add a style to the Window Resources collection and set it on the TextBox. The XAML would go like this:

<Window x:Class="ValidationSample1.ValidationWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Rules="clr-namespace:ValidationSample1"
    Title="ValidationWindow" Height="200" Width="300">
    <Window.Resources>
        <Style x:Key="EditableTextBox" TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
            <Setter Property="Background" Value="#DDFFDD" />
            <Setter Property="Validation.ErrorTemplate">
                <Setter.Value>
                    <ControlTemplate>
                        <Border BorderBrush="Red" BorderThickness="2">
                            <AdornedElementPlaceholder />
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="true">
                    <Setter Property="Background" Value="#FFDDDD"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid VerticalAlignment="Center" HorizontalAlignment="Center">
        <StackPanel Name="ValidationPanel" >
            <Label>Validated Text Box:</Label>
            <TextBox x:Name="ValidatedTextBox"
                     Width="200"
                     Style="{DynamicResource EditableTextBox}">
                <TextBox.Text>
                    <!--  Textbox notifies changes when Text is changed, and not focus. -->
                    <Binding Path="MyProperty" UpdateSourceTrigger="PropertyChanged">
                        <Binding.ValidationRules>
                            <!--  Validation rule set to run when binding target is updated. -->
                            <Rules:MandatoryInputRule ValidatesOnTargetUpdated="True" />
                        </Binding.ValidationRules>
                    </Binding>
                </TextBox.Text>
            </TextBox>
        </StackPanel>
    </Grid>
</Window>

Now, the user sees a red border when no text is submitted. So the task is complete, but I can’t stop wondering the amount of code needed to add validation to a single control. Imagine an entire form…

The next article will present a new approach to this implementation and will require much less code.

* “Goku approach” is an analogy that means one’s accomplished the basic and most objective functional requirement, but then he can’t stop feeling an urge to improve the implementation whether performance, architectural or usability-wise. So that’s when code tends to get upgraded to the next level, shall we say a super level or “super-sayin”, like in the Dragon Ball anime. And after that, the same urge may arise again, and again, giving way to the typical Goku-powerup pattern that the main character faces along the series when needs to evolve to face his enemies :)

Technorati Tags: , ,

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)
Page 1 of 3123Next »

Note: Silverlight, C#, in fact any .NET web development projects is best used with windows hosting than Linux based hosting.