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)

Silverlight tip: Transparent application background

1

A question a lot of developers ask when starting to develop in Silverlight is how do we set a transparent background in the silverlight application? This can be useful if you intend to provide a seamless integration with your website and run the Silverlight application object over html content that you want displayed.

This can easily be done by setting background and IsWindowless properties on the silverlight object, like so:

<param name="background" value="#00FFFFFF" />
<param name="windowless" value="true" />

Notice that the background color value sets the transparency by setting the alpha channel to 00 (first two characters of the ARGB hex code).

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)

Silverlight tip: Add an hyperlink

0

You can create Hyperlinks in Silverlight by using the HyperlinkButton control.

Here is a usage example in XAML:

<HyperlinkButton TargetName="_blank" Content=".Net Brainwork Hyperlink example" NavigateUri="http://blog.vascooliveira.com"></HyperlinkButton>

Some notes in this example:

  1. The TargetName property sets the name of the target window or frame that the Web page should open in, or the name of the object within the Silverlight application to navigate to. Possible values are:
    • _blank, _media, or _search: Loads the linked document into a new blank window.
    • _parent, _self, _top, or “”: Loads the page into the window in which the link was clicked (the active window).
  2. The NavigateUri is the link to navigate to.
  3. Content is the actual link text.

You can then, as usual, style the control to best fit your needs. See the following base style and start from there:

<Style x:Key="Hyperlink" TargetType="HyperlinkButton">
   <Setter Property="Padding" Value="2,0,2,0"/>
   <Setter Property="Cursor" Value="Hand"/>
   <Setter Property="HorizontalContentAlignment" Value="Left"/>
   <Setter Property="VerticalContentAlignment" Value="Top"/>
   <Setter Property="Template">
    <Setter.Value>
     <ControlTemplate TargetType="HyperlinkButton">
      <Grid Cursor="{TemplateBinding Cursor}">
       <ContentPresenter x:Name="contentPresenter" HorizontalAlignment="Center" Margin="{TemplateBinding Padding}" VerticalAlignment="Center" ContentTemplate="{TemplateBinding ContentTemplate}"/>
      </Grid>
     </ControlTemplate>
    </Setter.Value>
   </Setter>
  </Style>

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 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)

Design-time width and height in WPF/Silverlight

0

When designing UI’s in WPF and Silverlight, you may wish to make your layout fluid and auto-expandable in order to take the most out changing UI context. For instance, when data quantity and quality changes, available space may also change and objects in the layout need to adapt to these changes. When an auto layout is needed, no width nor height are specified which can be troublesome since the design view tends to collapse available space. For instance, a variable size user control with a data-binded listbox has no child items in design time, so you’ll see nothing but a small dot. This is because Cider, the Visual Studio Designer, and Blend designer, have no reason to show it otherwise since there’s no content and, as such, the ability to publish and preview isn’t possible.

In expression blend however, there’s a nice feature that solves this issue, and it’s only enabled at design time. When you create a new visual object in Blend, you’ll notice the following xml namespace declaration:

...
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
...

 This enabled a “d” keyword that can be attached to a visual object in order to set its size only at design time. At runtime, the regular sizing settings are considered. So, if we had the following User Control, with data items applied at runtime through databinding:

This is what you would see in Blend:

So you see that testing background coloring, for instance, isn’t very practical with this view. So the solution lies in the two Blend design-time attached properties: DesignWidth and DesignHeight, available in the namespace specified above. Notice the two right and bottom rectangular adorners in the previous picture: they’re Blend’s way of settings these values. If you resize your control with those rectangles you’ll be setting your desired design-time size. The XAML output would be something like this:

And this is what you’d see:

Like I said earlier, at runtime this setting isn’t considered, and auto layout is applied.

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.