Blog Archives

WPF: Using ListBox and StackPanel to Display Multiple Properties

Introduction

This blog builds on the previous one.  That earlier blog uses an ObjectDataProvider to access a collection of DrinkProduct objects and displays the ProductName property.

finished

It’ll be a rare day when you only need to access a single property of a collection like this.   Very often you’ll want to display some kind of key list, like the ProductName, first and then show users further details as they select individual items from the ListBox.  So that’s what we’ll look into here.

I’m going to use a very basic approach, putting everything inside a parent StackPanel.  So we can see what we’re aiming for, here’s the finished window:

DrinkProductStocks

You can see that the Instant Tea item is selected and that the correct Product ID and current stock figures for this item are shown.  As the user changes the selection, so the details on the right hand side will change to reflect the current choice.

The Document Outline Window

Because the XAML might take a bit of studying to see what goes where, one tool that you’ll often find useful is the Document Outline in the IDE.  You can select this with  Ctrl + Alt + T, or find it in the View menu.  It is very useful for getting an overview of the structure of the Window:

DocumentOutline

In this example, we’re interested in the first StackPanel and everything below that in the displayed list of controls (actually, to be totally accurate, they’re ‘elements’ in WPF, but old habits die hard!). 

The first StackPanel, which is named PanelOuter contains two children – a ListBox named lstDrinks, and another StackPanel, which  is named PanelRight.  PanelRight also has children – in this case two labels and two text blocks.  So, essentially, the outer StackPanel is split vertically, has a ListBox in the left half and a StackPanel with its own content in the right half.  The Document Outline is often most useful for working out the nesting pattern of elements when things get complicated.

Markup for the Window

Here’s all the markup for the window.  I’ll pick through it in the next few sections and highlight the parts you really need to home in on.

 

    1 <Window x:Class="MainWindow"

    2    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    3    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    4        xmlns:local="clr-namespace:ObjectDataProviderBlogDemo"

    5    Title="Drink Product Stocks" Height="350" Width="375">

    6 

    7     <Window.Resources>

    8         <ObjectDataProvider x:Key="DrinksInfo"

    9         ObjectType="{x:Type local:DrinkProduct}"

   10         MethodName="StockCheck"></ObjectDataProvider>

   11     </Window.Resources>

   12 

   13         <StackPanel Orientation="Horizontal" Name="PanelOuter"

   14                DataContext="{Binding Source={StaticResource DrinksInfo}}">

   15 

   16             <ListBox Name="lstDrinks" Margin="2,4,14,2" Padding="1,0,16,1"

   17            ItemsSource="{Binding}"   IsSynchronizedWithCurrentItem="True"/>

   18 

   19             <StackPanel Orientation="Vertical" Margin="15,3,3,3"

   20                        Name="PanelRight">

   21             <Label Content="Product ID" Foreground="MediumBlue" />

   22             <TextBlock Margin="3" Padding="3" HorizontalAlignment="Center"

   23                        Text="{Binding Path=ProductID}"></TextBlock>

   24             <Label Content="Quantity Available" Foreground="MediumBlue"

   25                   Margin="3,45,3,3" />

   26             <TextBlock Margin="3" Padding="3" HorizontalAlignment="Center"

   27                         Text="{Binding Path=Quantity}"></TextBlock>

   28             </StackPanel>

   29         </StackPanel>

   30 

   31 </Window>

   32 

Markup for the Window Opening Tag and Window Resources

This is exactly the same as I used in the previous blog item, so I won’t go over it again here.

Data Binding Markup for the Outer StackPanel

Bearing in mind that several of the elements inside the outer StackPanel need to be bound to the data source, it makes sense to set the data binding on this outer item. Here’s the opening tag for that StackPanel:

         <StackPanel Orientation="Horizontal" Name="PanelOuter"

                 DataContext="{Binding Source={StaticResource DrinksInfo}}">

This time I’ve created a DataContext that ensures that the DrinkProduct data from the ObjectDataProvider is available throughout the StackPanel. 

Data Binding Markup for the ListBox

Because the ListBox is a child of the StackPanel, there’s no longer any need to reference that DrinksInfo StaticResource directly.  But the ItemsSource still needs to know where its data is coming from, so a simple Binding which links to the default parent binding is used:

      <ListBox Name="lstDrinks" Margin="2,4,14,2" Padding="1,0,16,1"

          ItemsSource="{Binding}"   IsSynchronizedWithCurrentItem="True"/>

The other addition to the ListBox markup is the IsSynchronizedWithCurrentItem property. This is an important feature in these kinds of scenarios where the user clicks on a ListBox item and this is meant to update some other bound control(s).  It’s a very long-winded property name, but simply all it means is that all other elements that are bound to the same source listen for this, and are automatically updated when any changes happen.

Markup for the Right Hand Panel

There are several ways of creating the same finished layout.  This one is reasonably straightforward.  The labels have static content that describe what’s in the TextBlocks below them.  If you wanted to have the label and the TextBlock aligned horizontally, you could insert further sub StackPanels inside PanelRight.

I don’t know of a way to concatenate the static text and the bound result in a single control by using the XAML markup in the window (in other words to have something like “Quantity: 123” inside a single TextBlock).  But if you’re determined to get this result, you could use a ValueConverter.

The TextBlocks are both bound to the same data source – again channelled through the DataContext of the parent PanelOuter StackPanel.  Each of them has a path to a different field.  In the case of the first TextBlock, that path points to the ProductID field:

     <TextBlock Margin="3" Padding="3" HorizontalAlignment="Center"

             Text="{Binding Path=ProductID}"></TextBlock>

Summary

And that’s pretty much all there is to it.  I’ve attached the sample project if you want to experiment.

An introduction to dates and times in Visual Basic.NET (2)

What’s today’s date?
In the previous blog on this topic, I looked at the basics of the DateTime object. You saw some of the output formats and learnt about the Now and Today properties. I’m going to dig a bit deeper into those subjects this time.

Here’s a code snippet that creates a DateTime that has today’s date as its date value. It then pulls out just the value of the Day part

     Dim dt As New DateTime

    dt = Today

    Console.WriteLine(dt.Day)

As I’m writing this on the 25th August 2010, the value I see is 25.

you can apply the same kind of evaluation to get the month or the year:

    Dim dt As New DateTime

    dt = Today

    Console.WriteLine("Current month is " & dt.Month)

    Console.WriteLine("Current year is " & dt.Year)

 

 

The output for me today will be:

Current month is 8
Current year is 2010

What time is it, Mr Wolf?
Although you saw in the previous blog that you can isolate and display the time element of a DateTime, there might be an occasion when you want to extract just the value of the hour or minute, for example.  The way to do this is similar to that for the date:

    Dim dt As New DateTime

    dt = Now

    Console.WriteLine("Current hour is " & dt.Hour.ToString)

The result for me sat here at 11.33 in the morning is:

Current hour is 11

I could do the same thing for the minute or second if I needed that information.

If you read my previous blog on this topic, you’ll remember that I pointed out the subtle difference between Now and Today.  You’ll see that in this last snippet I used Now, and not Today.  If I hadn’t done this, the result would be zero.

What day is it?
Another useful property of the DateTime object is DayOfWeek.  Check out this snippet:

    Dim dt As New DateTime

    dt = Now

    Console.WriteLine("Today's day of the week is " & dt.DayOfWeek.ToString)

The result will be something like:

Today's day of the week is Wednesday

If you’re comparing dates, you might sometimes want to know if one date is earlier or later in the current year than another. Although there are other tools for date and time manipulation, you can do some of the basics by using the DayOfYear property. This next snippet shows how:

    Dim dt As New DateTime

    dt = Now

 

    Dim dt2 As New DateTime(2010, 12, 12)

    Console.WriteLine(dt2.DayOfYear – dt.DayOfYear)

It creates two DateTime instances, then subtracts the values of their DayOfYear properties to find how many days separate them.  In reality, you’ll probably use a TimeSpan object (which I’ll be coming on to soon), but this is an option anyway.

Comparatively Speaking
Using the comparison method above is a bit limited, so you may want to use the CompareTo method of DateTime instead, particularly if the two dates spread across more than one year. In a real world scenario, you wouldn’t generate known dates in the way I’ve done in the sample below.  You’d be taking them from users or grabbing them from data sources somewhere. But for the purposes of this demonstration, I’ll create the DateTime values in the snippet.

    Dim dt As New DateTime(2000, 12, 1)

    Console.WriteLine(dt.CompareTo(DateTime.Now))

A couple of points to note here.  You’ll see in the second line that I’ve used Now as one of the values, but I didn’t create a separate instance to hold the value. This can be a useful shortcut in these kind of situations. The second point is that the values that will be returned are either –1 if the dt date is earlier than the current date, 1, if the dt date is later than the current date or 0 if they are the same.

Don’t let my sample confuse you into thinking that you have to use Now.  You can use any date you like for the second date value.

Depending on what you’re doing with them, the returned values of –1, 0 or 1 may need to be translated into something a user can relate to.  The following approach will do this.

    Dim dt As New DateTime(2020, 1, 1)

 

    Dim infostring As String = String.Empty

    Select Case (dt.CompareTo(DateTime.Now))

      Case -1

        infostring = "earlier than"

      Case 1

        infostring = "later than"

      Case 0

        infostring = "the same as"

    End Select

    Console.WriteLine("The first date is {0} the second date", infostring)

The result will be something like :

The first date is later than the second date

WPF: Using a VirtualizingStackPanel to Improve ComboBox Performance

Introduction
In this earlier blog, I looked at how to use a ComboBox to display a list of all the system fonts, displaying each font name in its own font style.

I mentioned there that fonts are something of a special case, in that this collection of fonts is automatically cached for you after you first use it. The result is that when you run the application for the second and subsequent times there is minimal delay between the time the user clicks the ComboBox down arrow and the appearance of the list of fonts.

In this blog I want to look at the situation where you have a ComboBox that has a large number of other (possibly graphically complex) items to display.
Without the built-in caching that is available for fonts, you will often find that the display of large amounts of data in a ComboBox can be annoyingly slow. Furthermore, it will continue to be slow each time the ComboBox is recreated (although you can re-access the ComboBox and have shorter delays as long as you don't close the Window). However, if you close the Window that contains this ComboBox, then the whole display has to be rebuilt and the initial longer delay will reoccur.

The reason for the delay is that WPF creates the complete display for the ComboBox in advance,  regardless of the fact that it might only display a tiny proportion of the total number of items. It is this initial unnecessary creation of visual content that causes the problem. Let's create a sample project to demonstrate this.

Display of Large Amount of Text
First, I'll create some fairly uninspiring demo data in the code-behind: 

    Private Sub Window2_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Dim DemoList As New List(Of String)

        For i As Integer = 0 To 10000

            DemoList.Add("This is ItemCollection # " & i.ToString)

        Next

        Me.DataContext = DemoList

    End Sub 

This simply creates 10,000 Strings, stores them in a List (Of String) and sets this List as the DataContext for the Window.

Next, in the markup for the Window, create a ComboBox that will use those Strings for its display of items: 

    <ComboBox Height="23" Margin="27,10,10,0" Name="ComboBox1"

             VerticalAlignment="Top"

             ItemsSource="{Binding}">

    </ComboBox>  

When you run this application, there will be noticeable delay before the list appears. As I mentioned above, when you click for a second and subsequent times, the delay is shorter but still exists. If you close this Window and then subsequently show it again, the long delay will reoccur.

Improving the Display Time
The quick fix for this issue is to insert a VirtualizingStackPanel into the template for the ComboBox. This panel has the ability to assess how many items can be displayed, based on the measurements of the ComboBox, and automatically creates the visuals for that limited number of items only.

An easy way to implement this is to create an ItemsPanelTemplate as a Resource and reference it in the ComboBox markup.  

  <Window.Resources>

    <ItemsPanelTemplate x:Key="VSP">

      <VirtualizingStackPanel/>

    </ItemsPanelTemplate>

  </Window.Resources>

 

 

    <ComboBox Height="23" Margin="27,10,10,0" Name="ComboBox1"

             VerticalAlignment="Top"

             ItemsSource="{Binding}"

             ItemsPanel="{StaticResource VSP}">

    </ComboBox>  

Specifically, the ItemsPanel property of the ComboBox is set to that ItemsPanelTemplate Resource.

If you prefer, you can include the VirtualizingStackPanel right in the ComboBox creation markup: 

   <ComboBox Height="23" Margin="27,10,10,0" Name="ComboBox1"

             VerticalAlignment="Top"

             ItemsSource="{Binding}"

            >

      <ComboBox.ItemsPanel>

        <ItemsPanelTemplate>

          <VirtualizingStackPanel />

        </ItemsPanelTemplate>

      </ComboBox.ItemsPanel>

    </ComboBox>  

Personally, I like to try and keep as much of these kind of things as Resources as I can.

More Complex Items

  If your display is more complex – maybe using a DataTemplate and including nested panels and some images in each item:

    <DataTemplate x:Key="ImgAndText">

      <StackPanel Orientation="Horizontal">

        <Image Source="Timer.jpg" Height="89" Margin="3"></Image>

        <StackPanel>

          <Image Source="Stars.jpg" Width="152" Height="44" Stretch="None"></Image>

          <TextBlock Text="{Binding}" Margin="2,15,2,2" ></TextBlock>

        </StackPanel>

       </StackPanel>

    </DataTemplate>

 

then the delay can become very substantial indeed and you will certainly want to be sure to include a VirtualizingStackPanel in the markup for the ComboBox.

WPF: Using a VirtualizingStackPanel to Improve ComboBox Performance

Introduction
In this earlier blog, I looked at how to use a ComboBox to display a list of all the system fonts, displaying each font name in its own font style.

I mentioned there that fonts are something of a special case, in that this collection of fonts is automatically cached for you after you first use it. The result is that when you run the application for the second and subsequent times there is minimal delay between the time the user clicks the ComboBox down arrow and the appearance of the list of fonts.

In this blog I want to look at the situation where you have a ComboBox that has a large number of other (possibly graphically complex) items to display.
Without the built-in caching that is available for fonts, you will often find that the display of large amounts of data in a ComboBox can be annoyingly slow. Furthermore, it will continue to be slow each time the ComboBox is recreated (although you can re-access the ComboBox and have shorter delays as long as you don't close the Window). However, if you close the Window that contains this ComboBox, then the whole display has to be rebuilt and the initial longer delay will reoccur.

The reason for the delay is that WPF creates the complete display for the ComboBox in advance,  regardless of the fact that it might only display a tiny proportion of the total number of items. It is this initial unnecessary creation of visual content that causes the problem. Let's create a sample project to demonstrate this.

Display of Large Amount of Text
First, I'll create some fairly uninspiring demo data in the code-behind: 

    Private Sub Window2_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Dim DemoList As New List(Of String)

        For i As Integer = 0 To 10000

            DemoList.Add("This is ItemCollection # " & i.ToString)

        Next

        Me.DataContext = DemoList

    End Sub 

This simply creates 10,000 Strings, stores them in a List (Of String) and sets this List as the DataContext for the Window.

Next, in the markup for the Window, create a ComboBox that will use those Strings for its display of items: 

    <ComboBox Height="23" Margin="27,10,10,0" Name="ComboBox1"

             VerticalAlignment="Top"

             ItemsSource="{Binding}">

    </ComboBox>  

When you run this application, there will be noticeable delay before the list appears. As I mentioned above, when you click for a second and subsequent times, the delay is shorter but still exists. If you close this Window and then subsequently show it again, the long delay will reoccur.

Improving the Display Time
The quick fix for this issue is to insert a VirtualizingStackPanel into the template for the ComboBox. This panel has the ability to assess how many items can be displayed, based on the measurements of the ComboBox, and automatically creates the visuals for that limited number of items only.

An easy way to implement this is to create an ItemsPanelTemplate as a Resource and reference it in the ComboBox markup.  

  <Window.Resources>

    <ItemsPanelTemplate x:Key="VSP">

      <VirtualizingStackPanel/>

    </ItemsPanelTemplate>

  </Window.Resources>

 

 

    <ComboBox Height="23" Margin="27,10,10,0" Name="ComboBox1"

             VerticalAlignment="Top"

             ItemsSource="{Binding}"

             ItemsPanel="{StaticResource VSP}">

    </ComboBox>  

Specifically, the ItemsPanel property of the ComboBox is set to that ItemsPanelTemplate Resource.

If you prefer, you can include the VirtualizingStackPanel right in the ComboBox creation markup: 

   <ComboBox Height="23" Margin="27,10,10,0" Name="ComboBox1"

             VerticalAlignment="Top"

             ItemsSource="{Binding}"

            >

      <ComboBox.ItemsPanel>

        <ItemsPanelTemplate>

          <VirtualizingStackPanel />

        </ItemsPanelTemplate>

      </ComboBox.ItemsPanel>

    </ComboBox>  

Personally, I like to try and keep as much of these kind of things as Resources as I can.

More Complex Items

  If your display is more complex – maybe using a DataTemplate and including nested panels and some images in each item:

    <DataTemplate x:Key="ImgAndText">

      <StackPanel Orientation="Horizontal">

        <Image Source="Timer.jpg" Height="89" Margin="3"></Image>

        <StackPanel>

          <Image Source="Stars.jpg" Width="152" Height="44" Stretch="None"></Image>

          <TextBlock Text="{Binding}" Margin="2,15,2,2" ></TextBlock>

        </StackPanel>

       </StackPanel>

    </DataTemplate>

 

then the delay can become very substantial indeed and you will certainly want to be sure to include a VirtualizingStackPanel in the markup for the ComboBox.

WPF: ProgressBar With Marquee Text Display and TemplateBinding

 Introduction
In this blog I want to demonstrate several things. The first is how to reveal a text message in a ProgressBar. This is easy to do and you can get reasonably close to the moving marquee effect that you can see on some digital displays.
A more important topic that I'll cover is TemplateBinding in ControlTemplates. This makes it easy to use a core template, but allow individual instances of the control type that use the template to tweak selected properties. In this case I'll use the FontSize property.
Finally, you sometimes come across a situation where the control (in this case the ProgressBar) doesn't have a property that maps directly to a property that exists in the ControlTemplate. Although this might seem improbable, it actually happens quite often. We'll look at how we can work round this limitation and in the example I will show you can set a Content property on a ProgressBar control, even though the ProgressBar doesn't actually possess such a property.

If you've read my last three or four blogs you may be thinking that I'm a bit obsessed with ProgressBars! That's not the case and it's simply that they represent a good case study for ControlTemplates, they require named parts and I think they make a nice change from the demos that mostly seem to use Buttons.

The ControlTemplate
In the previous blogs on ProgressBars, you will have seen that I have stored the ControlTemplates in the Window.Resources collection. This time, the ControlTemplate is going to be stored in the Application.Resources collection. The thinking behind this is that this template is designed to be reused in several Windows across the application, with different values being placed on some properties in some instances. So having it in a central location clearly makes it available application-wide and makes sense.

Here is the markup for the initial version of the ControlTemplate: 

    <ControlTemplate x:Key="PBWordReveal" TargetType="{x:Type ProgressBar}">

      <Grid>

        <Border Name="PART_Track" 

          BorderThickness="2" CornerRadius="5"

          Background="LightSkyBlue" BorderBrush="Navy"  />

 

        <ContentControl Name="PART_Indicator"

           Content="  Loading   . . . .   Loading   . . . . .   Loading"

           Margin="4,0" FontSize="14"

           Foreground="Black" Background="LightSkyBlue"

           VerticalAlignment="Center"

           HorizontalAlignment="Left"/>

      </Grid>

    </ControlTemplate> 

If you are not familiar with the concept of named parts – specifically the PART_Track and PART_Indicator shown above – you get an explanation in my previous ProgressBar blogs.

The outer track is a Border element, while the Indicator uses a ContentControl. The key property is probably the Content property, which as you can see contains the text that will be displayed. The HorizontalAlignment property is also quite important to the look of the final effect.

ProgressBar Instance
To use this template, I will create a ProgressBar instance in a Window. 

    <ProgressBar Name="PBReveal"

     Template="{StaticResource PBWordReveal}"

            Width="200" Height="40"    /> 

To animate the ProgressBar in the code-behind of the Window (in this example, a Window named 'WordReveal': 

Imports System.Windows.Media.Animation

 

Partial Public Class WordReveal

 

    Private Sub WordReveal_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

         Dim a As New DoubleAnimation

        a.From = 0

        a.To = 100

        a.Duration = New TimeSpan(0, 0, 6)

 

        PBReveal.BeginAnimation(ProgressBar.ValueProperty, a)

    End Sub

End Class 

When you run this project, the text content in the ProgressBar will be revealed from left to right. The screenshot shows the bar with the animation approx 60% complete:

And this is the display when the animation has ended:

Effectively all that is happening is that the ContentControl, the PART_Indicator element of the template, is revealed over the period of the animation – the revelation commencing from left to right.

If you want more of a marquee type effect, you can change the HorizontalAlignment : 

  HorizontalAlignment="Right" 

This will make the text scroll from right to left:

Setting the HorizontalAlignment to either Center or Stretch will produce a different result again.

TemplateBinding
TemplateBinding allows you to hand back control of selected properties to the instance of the ProgressBar that is using this ControlTemplate. It is simple to implement and in this example only requires the change shown below to the PART_Indicator named part of the template:  

       <ContentControl Name="PART_Indicator"

           Content="  Loading   . . . .   Loading   . . . . .   Loading"

           Margin="4,0"

              FontSize="{TemplateBinding FontSize}"

           Foreground="Black" Background="LightSkyBlue"

           VerticalAlignment="Center"

           HorizontalAlignment="Right"

          /> 

The TemplateBinding points to a specific property – FontSize. This can now be set in an instance of the control that uses the template:  

    <ProgressBar Name="PBReveal"

     Template="{StaticResource PBWordReveal}"

     Width="200" Height="40"

        FontSize="22"/> 

Note that if you choose not to set a value on the FontSize property in the ProgressBar instance, the default value for that property will be used (12).

Mapping Between Properties
As you can see from the markup, the PART_Indicator uses a ContentPresenter. The ContentPresenter has a Content property and this is what is used to set the value of the text to be displayed. The basic ProgressBar however doesn't have such a property. So if you want to include TemplateBinding to allow different text to be used in different instances that use this template, you need to map the ContentPresenter property to some other property of the ProgressBar.

In most cases, if you have only one property that needs this kind of mapping, the solution is simple. You can use the Tag property: 

        <ContentControl Name="PART_Indicator"

             Content="{TemplateBinding Tag}"

           Margin="4,0"

           FontSize="{TemplateBinding FontSize}"

           Foreground="Black" Background="LightSkyBlue"

           VerticalAlignment="Center"

           HorizontalAlignment="Right"

          /> 

And you insert the required text in the markup for the ProgressBar instance : 

    <ProgressBar Name="PBReveal"

     Template="{StaticResource PBWordReveal}"

     Width="200" Height="40"

     FontSize="22"

       Tag="  Please Wait . . . . . . . . . ."/> 

These two templated changes result in the following display:

As you can see, both the FontSize and the Content have changed.

If you need to include more than one of these kind of cross property mappings, there is nothing (apart from common sense and experience) stopping you from hijacking other ProgressBar properties. You can identify a property that you absolutely, categorically know won't be used (and there's the start of the slippery slope right there) you can use this to map to.

The more professional alternative, of course, is to create a custom control of your own which contains all the properties you desire. I'll be looking at the steps involved in creating a custom control in a future blog.

WPF: How to Create a Reversing ProgressBar

 

 

In some of my earlier blogs – here, here and here, I looked at some rather colorful, non-rectangular versions of the ProgressBar. Although you probably wouldn't want to use some of those versions outside of a game environment, I hope it did show you how you can create and tweak non-rectangular versions. In this blog, I want to examine a less bizarre variation and along the way hopefully show you some more useful WPF basics.

Reversing the Default ProgressBar
The default ProgressBar is rectangular, has slightly rounded corners, a Gray Background, Linear Gradient Green Foreground and, most importantly, it traverses from left to right. I was wondering about how to change this and have a ProgressBar that traversed from right to left – a kind of a countdown effect instead of the usual fill-increasing effect. Because I was in ControlTemplate mode, I confess that I initially overlooked the obvious solution – total simplicity in WPF – and created a whole new template that did the job. I'll show you the obvious WPF solution shortly, but first let's just look at how this can be done as a ControlTemplate task.

ControlTemplate
I set about this by using a combination of Expression Blend and Visual Studio. I know I could have done it all in Blend using the Edit Template tools, but I came up this WPF route the hard way, from back in the early days when there were no tools and you had to become a XAML-head to get anywhere with this new-fangled thing called WPF. So I find that I still prefer to create my ControlTemplates in XAML in Visual Studio and use Blend when I want to do anything fancy with graphics or animation.

If you find it easier to do it all in Blend, I have no problem with that, but here's my way. First create a ControlTemplate, Key it as 'ReverseBasicPB' and set its TargetType to ProgressBar. The visual elements of the template will all be held inside a Grid. 

    <ControlTemplate x:Key="ReverseBasicPB" TargetType="{x:Type ProgressBar}">

      <Grid>

 

      </Grid>

    </ControlTemplate> 

As you will know from the earlier blogs, the ProgressBar requires two named parts – PART_Track and PART_Indicator. In this version, PART_Track will consist of a Rectangle inside a Border and PART_Indicator will be a Rectangle with a reasonable copy of the Green Linear Brush.
(As a side note, it is possible to dig into the WPF namespaces and get hold of the ProgressBarGlassyHighlight and ProgressBarTopHighlight Brushes, but I was content to go with my approximation.)

Here is the markup for the PART_Track: 

       <Border Name="PART_Track" BorderBrush="DarkGray"

               BorderThickness="2" CornerRadius="3" >

          <Rectangle Fill="LightGray"

               RadiusX="3" RadiusY="3"/>

        </Border> 

Note that to achieve the rounded corner effect, Border uses CornerRadius and Rectangle uses RadiusX and RadiusY.

The markup for the Indicator is just as simple: 

          <Rectangle Name="PART_Indicator" HorizontalAlignment="Right"

                    RadiusX="3" RadiusY="3" 

                    Margin="2,2,2,2">

          <Rectangle.Fill>

            <LinearGradientBrush EndPoint="0.5,0" StartPoint="0.5,1">

              <GradientStop Color="#FF5FBB23" Offset="0.525"/>

              <GradientStop Color="White"/>

              <GradientStop Color="#FF63BC28"/>

              <GradientStop Color="#FF95EDA5" Offset="0.542"/>

            </LinearGradientBrush>

          </Rectangle.Fill>

        </Rectangle> 

The key property here is the HorizontalAlignment. By setting it to Right we ensure that the ProgressBar Indicator will start at the right hand side and stretch out towards the left.

Demo
The following markup in a Window will create two ProgressBars, one default style and the other using this ControlTemplate: 

    <Grid>

    <Grid.RowDefinitions>

      <RowDefinition Height="87*" />

      <RowDefinition Height="175*" />

    </Grid.RowDefinitions>

 

    <ProgressBar x:Name="PBDefault" Width="150" Height="33">

 

    </ProgressBar>

    <ProgressBar Name="MyPB" Width="150" Height="33"

          Template="{StaticResource ReverseBasicPB}" Margin="22"

          Grid.Row="1"

          VerticalAlignment="Top" />

  </Grid> 

Add in the animation code-behind used in previous examples: 

    Private Sub ReverseBasic_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Dim a As New DoubleAnimation

        a.From = 0

        a.To = 100

        a.Duration = New TimeSpan(0, 0, 6)

 

        MyPB.BeginAnimation(ProgressBar.ValueProperty, a)

 

        a.From = 0

        a.To = 100

        a.Duration = New Duration(TimeSpan.Parse("0:0:6"))

 

        PBDefault.BeginAnimation(ProgressBar.ValueProperty, a)

    End Sub 

When you run this, completed ProgressBars are reasonably close in looks, the only major difference being that the templated one at the bottom runs right to left.

 

Although the creation of the ControlTemplate was only a few minutes work and opens the way for further visual changes (which I'll probably blog about later), if you just want the default ProgressBar reversed, the simple way is as follows:

Add a new ProgressBar to the Window, but this time include a LayoutTransform to rotate it 180 degrees. 

    <ProgressBar x:Name="PBDefaultReversed"

                 Width="150" Height="33"

                 Grid.Row="2" >

      <ProgressBar.LayoutTransform>

        <RotateTransform Angle="180" />

      </ProgressBar.LayoutTransform>

    </ProgressBar> 

(You'll also need to add the extra row to the Grid if you are following along and creating this sample yourself:) 

    <Grid.RowDefinitions>

      <RowDefinition Height="87*" />

      <RowDefinition Height="85*" />

      <RowDefinition Height="90*" />

    </Grid.RowDefinitions> 

And don't forget to animate it in the code-behind.

The final result, with the default ProgressBar at the top, the templated one in the middle and the transformed one at the bottom, looks like this:

I chose not to use a gradient for the background Gray, but of course you can implement this if you prefer.

WPF: Changing ProgressBar Appearance As Values Change

 

Introduction
In this earlier blog, I looked at how to create a non-rectangular ProgressBar. As the next step, I want to look at how you can change properties dynamically as the current Value of the ProgressBar changes.

I'll start with the easy (and fairly realistic) scenario where you want to tone down the ProgressBar once it has reached its maximum value.

Currently the ProgressBar coloring looks like this:

If you want to apply changes to the look of the ProgressBar as it is running, you can use a DataTrigger in XAML or you can simply use the ValueChanged event of the ProgressBar in the code-behind. I say "simply", but you do in fact have to understand how to dig into the ControlTemplate and drill down in order to make the code-behind approach work.

There's a trade-off between these two approaches – DataTrigger or code-behind. DataTrigger offers a slightly more concise syntax, but only as long as your requirements are very basic. Once you step beyond the absolute basics, the XAML becomes quite complex. And as you are no doubt more familiar with VB, what's the point in struggling just to prove the point that it can be created in XAML? Sometimes, common sense has to win over technical ego.

Overall, in most cases, code-behind is the easiest answer. But just to be sure you know what a DataTrigger is and how it works, let's run through it.

DataTrigger
A DataTrigger is fired (and as a result some predefined change happens) when a value is reached. In the scenario we are looking at here, a DataTrigger could be set to fire when the Value property of a ProgressBar reaches its maximum. So in the case of the ProgressBar defined below that would of course be when it reaches 100.  

    <ProgressBar x:Name="CurvyPB" Width="300" Height="60"

       Template="{StaticResource PBCurvy}"

       Foreground="{StaticResource BlueGreenRed}"

       Minimum="0" Maximum="100" /> 

The 'predefined change' might be to alter the color of the outside edge of the control and also to dim its Opacity, so that it can be more easily ignored now that its work is done.

The DataTrigger sits in a Triggers collection in the ControlTemplate for the ProgressBar. The syntax is as follows: 

      <ControlTemplate.Triggers>

        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Value}"

                    Value="100">

          <Setter TargetName="PART_Track" Property="Stroke" Value="DarkGray" />

          <Setter TargetName="PART_Track" Property="Opacity" Value="0.3" />

        </DataTrigger>

      </ControlTemplate.Triggers> 

(Note that this is only one section of the complete ControlTemplate.)

The DataTrigger Binding looks awkward and is one of those rather peculiar constructs that makes XAML hard to decipher (and create) sometimes. Essentially it translates to :
"Keep checking the Value property of the ProgressBar instance that is using this ControlTemplate. If and when it reaches a Value of 100, fire the trigger."

The Setters both target the Path named 'PART_Track'. The first changes the Stroke to DarkGray and the second one turns down the Opacity of that Path (which effectively reduces the Opacity of the templated ProgressBar).

Here is the full XAML for the Window which contains the ControlTemplate and the ProgressBar instance: 

<Window x:Class="CurvyWithTriggers"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:converter="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Luna"  

   Title="Curved ProgressBar" Height="200" Width="400">

  <Window.Resources>

    <ControlTemplate x:Key="PBCurvy" TargetType="{x:Type ProgressBar}">

      <Grid>

        <Path x:Name="PART_Track"

             Stroke="{StaticResource BlueGreenRed}"

             StrokeThickness="5"

             Data="F1 M46.802502,0.50000018 C59.803562,0.50000006 71.553123,3.7052743 79.942001,

              8.9014616 C88.330879,3.7052746 100.08044,0.5 113.0815,0.50000018 C125.92575,

              0.5 137.54851,3.6284194 145.9305,8.6908474 C154.3125,3.6284194 165.93524,

              0.50000006 178.7795,0.50000018 C204.35167,0.5 225.082,12.900593 225.082,

              28.1975 C225.082,43.494408 204.35167,55.895 178.7795,55.895 C165.93524,

              55.895 154.3125,52.766582 145.9305,47.704151 C137.54851,52.766582 125.92575,

              55.895 113.0815,55.895 C100.08044,55.895 88.330879,52.689728 79.942001,

              47.493538 C71.553123,52.689728 59.803562,55.895 46.802502,55.895 21.230335,

              55.895 0.5,43.494408 0.5,28.1975 0.5,12.900593 21.230335,0.5 46.802502,

              0.50000018 z"

             Stretch="Fill">

          <Path.Fill>

            <MultiBinding>

              <MultiBinding.Converter>

                <converter:ProgressBarBrushConverter />

 

              </MultiBinding.Converter>

              <Binding Path="Foreground" RelativeSource="{RelativeSource TemplatedParent}" />

              <Binding Path="IsIndeterminate" RelativeSource="{RelativeSource TemplatedParent}" />

              <Binding Path="ActualWidth" ElementName="PART_Indicator" />

              <Binding Path="ActualHeight" ElementName="PART_Indicator" />

              <Binding Path="ActualWidth" ElementName="PART_Track" />

 

            </MultiBinding>

          </Path.Fill>

        </Path>

        <Decorator x:Name="PART_Indicator" />

       </Grid>

 

      <ControlTemplate.Triggers>

        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Value}"

                    Value="100">

          <Setter TargetName="PART_Track" Property="Stroke" Value="DarkGray" />

          <Setter TargetName="PART_Track" Property="Opacity" Value="0.3" />

        </DataTrigger>

      </ControlTemplate.Triggers>

    </ControlTemplate>

 

  </Window.Resources>

  <Grid>

    <ProgressBar x:Name="CurvyPB" Width="300" Height="60"

       Template="{StaticResource PBCurvy}"

       Foreground="{StaticResource BlueGreenRed}"

       Minimum="0" Maximum="100" />

 

  </Grid>

</Window> 

This markup in the Application.xaml file creates the LinearGradientBrush: 

    <Application.Resources>

    <LinearGradientBrush x:Key="BlueGreenRed"

       EndPoint="1,0.5" StartPoint="0,0.5">

      <GradientStop Color="#FF2D3ADD" Offset="0"/>

      <GradientStop Color="#FFF13E14" Offset="1"/>

      <GradientStop Color="#FF9775D8" Offset="0.192"/>

      <GradientStop Color="#FF3F893B" Offset="0.481"/>

      <GradientStop Color="#FF2B9518" Offset="0.625"/>

      <GradientStop Color="#FECC7638" Offset="0.812"/>

    </LinearGradientBrush>

  </Application.Resources> 

The code-behind to animate the ProgressBar: 

Imports System.Windows.Media.Animation

 

Partial Public Class CurvyWithTriggers

 

    Private Sub CurvyWithTriggers_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Dim a As New DoubleAnimation

        a.From = 0

        a.To = 100

        a.Duration = New TimeSpan(0, 0, 8)

 

        CurvyPB.BeginAnimation(ProgressBar.ValueProperty, a)

    End Sub

End Class 

Apologies if you already have all that code and markup from the previous blog. Personally I hate it when someone says "I've used the same code as in my earlier blog", which means I then have to go and find that blog, dig through it and find the missing bits before I can test out what I'm working on now. So I much prefer to repeat it and make life easier for you, at the expense of a slightly longer blog entry.

After the ProgressBar completes its mission, it hits that Value of 100 and the look changes to this:

So if you're sat there saying to yourself that there's nothing there that you couldn't have easily done in code-behind, I almost agree with you. Certainly the Opacity change would be easy: 

        If progressBar1.Value = 100 Then

            progressBar1.Opacity = 0.3

        End If 

But what about changing the value of the Stroke property though? The ProgressBar doesn't have a Stroke property. That's tucked away inside the ControlTemplate and is a property of the Path named PART_Track. To get to that, we will need a way to access the ControlTemplate and then drill down into the Path.

Before we look at the code-behind approach, I just want to mention a problem with DataTriggers, especially as they relate to ProgressBars. The only arithmetic operator available to you in the DataTrigger in XAML is the equals operator. For fairly obvious reasons, the less-than and greater-then operator symbols have the potential to cause problems in a language that uses them as element delimiters.

The reason that this is a particular problem with the ProgressBar is that the algorithm that breaks the ProgressBar movement into its time chunks will rarely, if ever, space them across whole numbers. That is to say if the Minimum Value is 0 and the Maximum Value is 100 and the duration is 10 seconds, you might reasonably suppose that each new block will appear at intervals of 0, 10, 20, 30, etc. However it doesn't work that way and the values are more likely to be something like :
0
0.252538
0.299015
0.613981
: etc
: ending with
99.769844
99.890324
100

This makes it impossible for you to set a DataTrigger on a value that you can be certain will be matched exactly, except for the starting and ending values of 0 and 100. In theory, you could tweak the size settings of the PART_Track and PART_Indicator to ensure whole number partitions (these being the key factors in the breakdown), but none of my experimenting with this approach worked. An alternative approach, which I haven't tried, would be to create a ValueConverter which would then allow you to set value parameters, such as < 20 or > 40 and so on. However, I didn't really see any gain in going that route, as I can use the ValueChanged event of the ProgressBar directly, together with a bit of WPF delving, as we will now see.

FindResource and FindName
When you need to get at a ControlTemplate (or other Resource, for that matter), you can use the FindResource method of the FrameworkElement class. Before, I get into that, I am going to make two changes to the markup in the Window.
The first change is to add a Name property to the Window, placing this inside the opening tag of the Window class markup:  

 x:Name="CurvyValueChangedWindow" 

This is necessary in order for the Window to be accessed from the code-behind.

The second change is purely decorative – changing the Stroke property of the PART_Track path from the LinearGradientBrush to plain Yellow.  

        <Path x:Name="PART_Track"

             Stroke="Yellow" 

 The ProgressBar now looks like this at startup:

To locate that ControlTemplate, I use the following code, which I have placed in the ValueChanged event of the ProgressBar: 

        Dim ct As New ControlTemplate()

        Try

            ct = CType(CurvyValueChangedWindow.FindResource("PBCurvy"), ControlTemplate)

 

        Catch Ex As ResourceReferenceKeyNotFoundException

            '  Design time message

            Console.WriteLine("CT Not found")

            '  Quit gracefully if not found

            Exit Sub

        End Try 

The third line does all the work and you will see now why I added a name to the WPF Window. This Name is used to identify the container in which the Resource named PBCurvy (i.e. the ControlTemplate) should be found.
Note also that if due to a typo or other error the Resource can't be found, then no further action will be taken. At this stage, the Catch is superfluous. It is however important to avoid the application crashing as we move on to the next step.

FindName
So now we have got ourselves a reference to the ControlTemplate, but we still need to drill down into the Path named PART_Track which is a sub-element of that template. To do this, you can use the following code, placing it immediately below the code used to find the ControlTemplate resource:  

        Dim p As New Path

        p = CType(ct.FindName("PART_Track", PBCurvy), Path)

 

        If IsNothing(p) Then

            Console.WriteLine("Path Not found")

            Exit Sub

        End If 

This time the FindName function searches through that ControlTemplate (now referenced as 'ct') in order to find the named Path.
Once again, the test for IsNothing isn't necessary at this stage, because we have not yet tried to do anything with the Path variable 'p'. As before though, when we add further code, this checkpoint – and the Exit Sub if the Path isn't found – are important.

Changing The values
We've now reached the point where we can manipulate values of that Path according to the current values of the ProgressBar. This code placed immediately below the previous snippet will change the color and thickness of the Stroke: 

        Select Case PBCurvy.Value

            Case Is < 25

                p.Stroke = New SolidColorBrush(Colors.Yellow)

                p.StrokeThickness = 5

            Case 25 To 49

                p.Stroke = New SolidColorBrush(Colors.Green)

                p.StrokeThickness = 7

            Case 50 To 75

                p.Stroke = New SolidColorBrush(Colors.Orange)

                p.StrokeThickness = 9

            Case 76 To 99

                p.Stroke = New SolidColorBrush(Colors.Red)

                p.StrokeThickness = 11

            Case Else

                p.Stroke = New SolidColorBrush(Colors.DarkGray)

        End Select 

When you run the application, the colors will change as things progress:  

 

 I have chosen to make those particular changes for demo purposes, but you are of course not limited to those. The key take away points in this blog are the availability of the DataTrigger and the use of the very helpful FindResource and FindName methods when you want to trigger a change via the code-behind.

WPF: Displaying a Master-Detail Collection of In-Memory Objects In a TreeView

 Introduction
In this earlier blog I used an XML file containing nested data items as the data source of a TreeView. In this version I will use a collection of objects as the data source.
The details of the data are much the same as I used in the previous blog, with a couple of tiny changes to avoid any possible confusion caused by the use of Visual Basic keywords as field names:

These classes are saved in a VB file named SalesData.vb. Because it is fairly lengthy, filling about three screen display lengths, I've made it available from this link. (To a large extent, how the the data is created isn't really the topic of this blog – I'm more concerned with the Binding to a source and the templates used for displaying the data.)

Mapping to the local Assembly
In order to be able to access those SalesPerson, SalesOrder, etc classes and objects in the XAML file, it is necessary to create a mapping. The syntax for this is as follows:  

  xmlns:local="clr-namespace:HierarchicalDataTemplate" 

It isn't mandatory to use 'local' as the mapping alias, but it's a fairly traditional approach. In this case, of course 'HierarchicalDataTemplate' is the name of the project I am working on.

With the namespace mapping in place, any of the classes that currently exist in the code-behind files of the project become visible to the XAML file. If you view the code listing for the SalesData.vb file, you will see that the class which creates the demo data is called 'SalesPersonList'. It's now possible to create a new instance of that class in the XAML file : 

    <local:SalesPersonList x:Key="SalesPersonList"/> 

I generally place this in the Window.Resources collection.

Creating a TreeView and Binding its Data Source
In the markup for the Window itself, I'll create a TreeView which contains a single TreeViewItem.  

    <TreeView>

      <TreeViewItem ItemsSource="{Binding Source={StaticResource SalesPersonList}}"

          Header="Sales Figures" />

    </TreeView> 

The ItemsSource is the crucial property here. It identifies exactly where the TreeView should look for its data. In this case it looks into the SalesPersonList instance that I created a few moments ago. For the avoidance of doubt, the exact 'SalesPersonList' that is used is the StaticResource created earlier and identified by the Key. (I possibly should have used a different name for the Key and the underlying Class to avoid any confusion).

Because of the use of the Binding and the HierarchicalDataTemplates, it is only necessary to create this single TreeViewItem. The Binding engine will trawl through all the data and create as many TreeViewItem nodes as it needs to in order to display everything correctly. 

HierarchicalDataTemplates
This example uses three HierarchicalDataTemplates, plus a standard DataTemplate for the SalesItems. Here is the first one (which again I've placed in the Window.Resources collection):  

    <HierarchicalDataTemplate DataType="{x:Type local:SalesPerson}"

          ItemsSource="{Binding Path=Periods}">

      <TextBlock Text="{Binding Path=Name}"/>

    </HierarchicalDataTemplate> 

The DataType property identifies which type of object will be dealt with by this template. In the case of this first template, this will be the SalesPerson type. In other words, when the Binding that I placed on the TreeViewItem finds any instance of a SalesPerson inside that SalesPersonList, it will look at this template to discover how it should display SalesPerson details.
In this case, the Name property of the current SalesPerson will be shown in a TextBlock.
The ItemsSource property also uses a Binding, but it is only interested in knowing what needs to be shown as the child data of SalesPersons. As we know from the diagram above, this will be the Periods data.

If you are finding the DataType and the Bindings' Paths a bit tricky to grasp, it may help if you run the project as it currently stands. Here's the markup for the Window so far: 

<Window x:Class="OrdersListsDisplay"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:local="clr-namespace:HierarchicalDataTemplate"

   Title="Sales List Display" Height="300" Width="300">

  <Window.Resources>

    <local:SalesPersonList x:Key="SalesPersonList"/>

 

    <!–  Data Templates –>

    <HierarchicalDataTemplate DataType="{x:Type local:SalesPerson}"

          ItemsSource="{Binding Path=Periods}">

      <TextBlock Text="{Binding Path=Name}"/>

    </HierarchicalDataTemplate>

 

  </Window.Resources>

    <Grid>

    <TreeView>

      <TreeViewItem ItemsSource="{Binding Source={StaticResource SalesPersonList}}"

          Header="Sales Figures" />

    </TreeView>

  </Grid>

</Window> 

When you run this, you will first see:

Then, when you expand the first node, you will have:

Finally, clicking on either or both the SalesPerson nodes, you will see that the application has tried to display the children of the SalesPersons for you. In the absence of any instruction about formatting the Periods, it simply reverts to displaying the default ToString rendering of the class.

Hopefully though you can now see why the template points to SalesPerson as its DataType, but identifies the next level down the tree as the ItemsSource. (You may have noticed that this wasn't necessary with the XML data example in the earlier blog, where simply assigning a Binding without a Path will work.)

Displaying Periods and SalesOrders
Exactly the same approach is used for the next two templates: 

    <HierarchicalDataTemplate DataType="{x:Type local:Period}"

          ItemsSource="{Binding Path=SalesOrders}">

      <TextBlock Text="{Binding Path=Name}"/>

    </HierarchicalDataTemplate>

 

    <HierarchicalDataTemplate DataType="{x:Type local:SalesOrder}"

         ItemsSource="{Binding Path=SalesItems}">

      <TextBlock Text="{Binding Path=Name}"/>

    </HierarchicalDataTemplate> 

The three HierarchicalDataTemplates in place so far will produce this result:

which should come as no surprise, based on what I explained earlier.

ItemDetail DataTemplate
So that just leaves the template for the SalesItems and ItemDetail data. This time a standard DataTemplate will do, because we know there is no further data below ItemDetail.  

    <DataTemplate DataType="{x:Type local:SalesItem}">

      <TextBlock Text="{Binding Path=ItemDetail}"/>

    </DataTemplate> 

Just for the record, a HierarchicalDataTemplate would work but isn't necessary. With the final DataTemplate added, every level of the Master-Detail data can be accessed:

Formatting
You have many options for formatting the final presentation of the data. In this example, you can change the color, font size and weight, indentation, etc via the individual TextBlock properties. If you wanted to insert additional graphical detail (such as an icon), you simply wrap the TextBlock in a StackPanel with its Orientation set to Horizontal. You can then insert the icon image as an additional child of this StackPanel.

You can build on this basic example shown here to create a much more complex display.

How To Create and Use a Custom Command in WPF

  I've got to be honest and admit up front that initially I wasn't completely sold on the idea that WPF Commands are the great leap forward that they are sometimes billed as. OK, so I get that they can reduce the repetition of event handling code, but even their most ardent supporters aren't going to be able to claim that the required code is particularly intuitive. I will agree though that the availability of CanExecute is useful sometimes when multiple controls are bound to a Command. As a WinForms developer moving to WPF, I still find that in many cases I'm happy to use event handlers and, where necessary, a utility method or two.

So, having got that caveat out of the way, let's look at a basic situation where we want a range of different user actions to trigger the same task.

I've decided to use the scenario that I covered in this blog. It's maybe not the most realistic scenario, but it does give an opportunity to use a wide range of user inputs and gestures to move the image across the screen. It also allows the use of the CanExecute event.

In the earlier blog, the user had to click on an image to make it move from left to right across a Canvas. This can soon become tiresome, so by means of a Command we'll give her several other options. In order to make the use of CanExecute realistic, we will say that once the image reaches the far right edge of the Canvas, it must stay there. So the image move will be allowed to happen (i.e. CanExecute) as long as it hasn't reached the right hand edge of the canvas.

Creating the User Interface
The following XAML will create an updated version of the Canvas-and-Image UI used previously. This version includes various controls that will be bound to the Command. 

<Window x:Class="Window3"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

 

   Title="Using A Command" Height="300" Width="300">

 

 

    <Grid x:Name="MainGrid">

    <Grid.RowDefinitions>

      <RowDefinition Height="Auto" />

      <RowDefinition Height="218*" />

      <RowDefinition Height="Auto" />

    </Grid.RowDefinitions>

 

 

      <!–  Canvas in the main middle section –>

    <Canvas x:Name="MainCanvas" Grid.Row="1">

      <Image x:Name="MoveableImage" Width="55" Source="questionmark2.jpg"

 

        Canvas.Left="0" Canvas.Top="0" />

    </Canvas>

 

    <!– Menu at the top –>

    <Menu Grid.Row="0" Margin="3">

      <MenuItem Header="Move It" Margin="5"

 

               ></MenuItem>

    </Menu>

 

    <ToolBar Grid.Row="2" >

      <Button Content="Move It"

              />

    </ToolBar>

 

      <Button Grid.Row="1" VerticalAlignment="Bottom"

             HorizontalAlignment="Right" Width="100"

             Height="33" Content="Move It" Margin="0,0,4,2"

              />

  </Grid>

</Window>

 (If you've looked at the markup closely and think that the order of elements is haphazard, you would be wrong.   Try moving the MenuItem to what seems a more logical position above the Canvas and you will get an Error when the code is completed.  As you will see, the code behind for the MenuItem will eventually have a link to the Image.   So therefore the Image must be created first in the top down XAML file, before the MenuItem can know about it .  I often think that it's these little potential Gotchas that make the WinForms-to-WPF learning curve so difficult.)

This is what it should look like:

  

Creating the Command
Let's start by creating a new Command Class called MoveItCommand. It will have a single property named MoveIt, a backing field named _move it and a parameterless constructor. The property and field are of type RoutedUICommand, but apart from that are standard and really don't need any additional explanation: 

    Private Shared _moveit As RoutedUICommand

    Public Shared ReadOnly Property MoveIt() As RoutedUICommand

        Get

            Return _moveit

        End Get

    End Property

 The constructor is used to create the various keyboard and mouse gestures that can be used to move the image. For the purposes of demonstration, I've gone totally overboard on these and have included four variations in the final version. But for clarity, I am only showing one in the code snippet below:

     Shared Sub New()

        '  Add keyboard and mouse gestures

        Dim UserInputs As New InputGestureCollection()

        UserInputs.Add(New KeyGesture(Key.M, ModifierKeys.Alt))

 

         '  Assign these gestures to the _moveit field (and thereby to the MoveIt property)

        _moveit = New RoutedUICommand("Move Element", "Move", GetType(MoveItCommand), UserInputs)

 

    End Sub 

  • The constructor begins by creating a new empty collection of mouse gestures.
  • The second line creates and stores a gesture which takes the Alt and M keys as the combination to be used to fire this command. Notice the order of the keys used as arguments – effectively it is "M & Alt" which isn't the way we usually think of the combination. If you switch the order and place the Modifier key first, you will get a runtime error. Trust me, I've been there, done that!
  • Finally, a new RoutedCommand is created, containing descriptive text, its name, owner type (which is this custom command class – MoveItCommand), and the collection of Gestures that will work with this command.

 Note that all the members of this class are Shared, ensuring that only instance of the Command will be in use in the application when it runs.

Additional Gestures
If you are happy with how the Class and its Constructor works, I'll now add in those other gestures I mentioned. These include F12 on its own, a mouse click on its own and finally a combination of mouse click and key press. Here's the revised code:  

    Shared Sub New()

        '  Add keyboard and mouse gestures

        Dim UserInputs As New InputGestureCollection()

        UserInputs.Add(New KeyGesture(Key.M, ModifierKeys.Alt))

        UserInputs.Add(New KeyGesture(Key.F12, ModifierKeys.None))

        UserInputs.Add(New MouseGesture(MouseAction.RightClick, ModifierKeys.None))

        UserInputs.Add(New MouseGesture(MouseAction.LeftClick, ModifierKeys.Shift))

         '  Assign these gestures to the _moveit field (and thereby to the MoveIt property)

        _moveit = New RoutedUICommand("Move Element", "Move", GetType(MoveItCommand), UserInputs)

    End Sub

 

  • The first gesture is Alt and M, which I've already covered.
  • The second gesture is the F12 key on its own. Note that you must include Modifiers.None. if you don't, you will get a runtime error.
  • The third gesture will fire the command when the mouse is right clicked anywhere in the Window. Because of the way that WPF and RoutedCommands work, this effectively means that you can still click on the Image to make it move. If you wanted to limit the mouse click to the Image only, you could harness the power of Bubbling and Tunneling events to trap the mouse button press at the Image level. I haven't done that in this example.
  • The final gesture takes a combination of both the mouse left button click together with holding down the Shift key. Quite awkward to use and only included to demonstrate the range of available gestures.

 

Command Bindings
Having created the custom Command Class, if we want to use it in the XAML – and we do – then it is necessary to create an XML namespace mapping. Without this link, the XAML markup would have no idea about the existence of the class and its property. The syntax is fairly simple: 

   xmlns:local="clr-namespace:GetValue" 

The alias of 'local' is used as the key which is mapped to the namespace in which the MoveItCommand class resides. The namespace is the same as the name of the project and in this case the project is named 'GetValue'.

Given this namespace mapping, we can now set up the CommandBinding in the XAML pane:

 

  <Window.CommandBindings>

    <CommandBinding Command="local:MoveItCommand.MoveIt"

                   Executed="CommandBinding_Executed"

                   CanExecute="CommandBinding_CanExecute"/>

  </Window.CommandBindings>

 

As you see from the snippet above, you create a new CommandBinding inside a CommandBindings collection. The Command property of the CommandBinding points to that MoveIt property created in the MoveItCommand class.

The Executed and CanExecute properties point to two methods which we will create next in the code-behind.

Executing The CommandBinding The task of the CommandBinding_Executed method is to carry out whatever tasks we want to have actioned when the command is invoked. In this demonstration project, this task is simply to shunt the image a few units to the right. So the code is as follows:  

    Private Sub CommandBinding_Executed(ByVal sender As System.Object, ByVal e As System.Windows.Input.ExecutedRoutedEventArgs)

        '  Move the image 5 units to the right

        Dim LeftPos As Double = MoveableImage.GetValue(Canvas.LeftProperty)

        MoveableImage.SetValue(Canvas.LeftProperty, LeftPos + 5)

 

    End Sub 

(If you are not sure about how the GetValue and SetValue functions work, you can read up on it in my blog here).

CanExecute
CanExecute is an optional feature which can be quite useful. In this demonstration, we will only allow the Command to work (and therefore only allow the Image to continue moving to the right) if it hasn't reached the right hand edge of the Canvas. More subtly, if CanExecute becomes set to False, any controls that are bound to the Command will automatically be disabled. I will add Command Bindings to the buttons, etc shortly.

First, here is the code for the CanExecute method: 

    Private Sub CommandBinding_CanExecute(ByVal sender As System.Object, ByVal e As System.Windows.Input.CanExecuteRoutedEventArgs)

        '  Only allow execution of the command if the image

        '  has not yet reached the right hand edge.

        e.CanExecute = MoveableImage.GetValue(Canvas.LeftProperty) < (MainCanvas.ActualWidth – MoveableImage.Width)

 

    End Sub 

It tests the current position of the Image to see if it has reached the right hand edge of the Canvas. CanExecute will be set to True if there is still space to the right side of the Image, otherwise it will be set to False.

The complete code behind for the Window and the Custom Command class together now looks like this: 

Partial Public Class Window3

 

    Private Sub CommandBinding_Executed(ByVal sender As System.Object, ByVal e As System.Windows.Input.ExecutedRoutedEventArgs)

        '  Move the image 5 units to the right

        Dim LeftPos As Double = MoveableImage.GetValue(Canvas.LeftProperty)

        MoveableImage.SetValue(Canvas.LeftProperty, LeftPos + 5)

 

    End Sub

 

    Private Sub CommandBinding_CanExecute(ByVal sender As System.Object, ByVal e As System.Windows.Input.CanExecuteRoutedEventArgs)

        '  Only allow execution of the command if the image

        '  has not yet reached the right hand edge.

        e.CanExecute = MoveableImage.GetValue(Canvas.LeftProperty) < (MainCanvas.ActualWidth – MoveableImage.Width)

 

    End Sub

End Class

 

Public Class MoveItCommand

 

    Private Shared _moveit As RoutedUICommand

    Public Shared ReadOnly Property MoveIt() As RoutedUICommand

        Get

            Return _moveit

        End Get

    End Property

 

    Shared Sub New()

        '  Add keyboard and mouse gestures

        Dim UserInputs As New InputGestureCollection()

        UserInputs.Add(New KeyGesture(Key.M, ModifierKeys.Alt))

        UserInputs.Add(New KeyGesture(Key.F12, ModifierKeys.None))

        UserInputs.Add(New MouseGesture(MouseAction.RightClick, ModifierKeys.None))

        UserInputs.Add(New MouseGesture(MouseAction.LeftClick, ModifierKeys.Shift))

         '  Assign these gestures to the _moveit field (and thereby to the MoveIt property)

        _moveit = New RoutedUICommand("Move Element", "Move", GetType(MoveItCommand), UserInputs)

    End Sub

 

End Class 

At this point, you can run the project and use any of those four gestures to move the Image. Once the Image hits the right hand edge, it will stop moving. The menu item, the two buttons don't play any part in the action yet – that is, clicking them will have no effect and they won't become disabled when the Image reaches the right hand limit.

Binding the Command to the Controls
All that remains to do is to bind this custom command to the menu item and the two buttons. Now things really do become simple and you can begin to see the potential benefit of using a Command. The following piece of markup is added to the MenuItem, the Button in the Toolbar and the Button in the Canvas:  

        Command="local:MoveItCommand.MoveIt" 

With those bindings in place, you can move the Image by any of the seven methods included – the four input gestures and by clicking on any of the three controls. Note now that once the Image hits the right hand edge, those three controls all become disabled.

So, there is a fairly simple example of using your own Command. You can see the final version of the XAML markup here, and also the code behind here.

Passing Multiple Records to a Stored Procedure in SQL Server

There are so many different ways to work with data that it can make your head spin.  Regardless of the technology, one thing I always try to do when working with databases is minimize the number of calls that are made.  I use ORM frameworks a lot so I have to make sure that my code doesn’t end up calling the database a ton and being overly “chatty”. 

My company is currently working on a large Silverlight 3 application for a customer and have a requirement to allow CSV file uploads through the application.  That’s pretty straightforward to do with Silverlight but in looking through the CSV file there can be 1000s of records and there is a lot of custom functionality around each record.  Initially I was going to handle the business rules and insertion for each row individually.  However, once I saw how many rows were involved I backed off my initial approach since that would mean a single file upload could trigger thousands and thousands of calls to the database which certainly isn’t efficient.  Instead of going that route I decided it would be better to pass all of the rows into a stored procedure and let it handle everything.  That way I can make a single database connection yet handle inserting (and updating and deleting based upon the business rules) many records. 

So how can you pass multiple records into a stored procedure?  Back in “the day” I’d pass in delimited strings and then parse them.  Although that technique probably wasn’t the most efficient, it got the job done.  With SQL Server 2005 and higher we have access to a much more efficient technique due to the availability of XQuery.  The current project I’m working on relies on SQL Server 2005 behind the scenes so that’s what I’ll focus on here.  Note that SQL Server 2008 allows .NET DataTable objects to be passed when using table value parameters as well in a stored procedure.  See www.codeproject.com/KB/database/sqlserver2008.aspx for an overview of the table value parameter functionality.

For the import I can serialize the list of records to XML and then pass them into a stored procedure.  It appears that you can pass an XmlDocument object from .NET if the stored procedure takes an XML input parameter type.  However, I never got it to work properly doing that so I pass a string containing serialized XML data and then load it into the XML data type.  The stored procedure can then use XQuery to convert the XML into actual rows.  Here’s some code that handles parsing a flat file, converting the data into a List<JobMaterialImport>, serializing the list into XML and then passing the serialized XML data to a stored procedure named ImportJobMaterials.

public List<ImportJobMaterialsResult> ImportJobMaterials(int jobID, Stream stream, string coNumber, string coDesc, string xmlMapFile)
{
    //Convert flat file to List<JobMaterialImport> using converter and XML mapping file
    //Mapping file passed from FlatFileHandler.ashx in web project
    FlatFileToObjectConverter<JobMaterialImport> converter = new FlatFileToObjectConverter<JobMaterialImport>(stream, xmlMapFile);
    List<JobMaterialImport> imports = converter.ConvertToList();
    imports = imports.Take(imports.Count - 2).ToList(); //last rows are bogus in flat-file

    //Generate XML and pass to sproc
    using (StringWriter sw = new StringWriter())
    {
        XmlSerializer xs = new XmlSerializer(typeof(List<JobMaterialImport>));
        xs.Serialize(sw, imports);
        try
        {
            //Pass materials into sproc
            string xml = sw.ToString().Replace("utf-16", "utf-8");
            return this.DataContext.ImportJobMaterials(xml, jobID, coNumber, coDesc).ToList();
        }
        catch (Exception exp)
        {
            Logger.Log("Error in JobManagementRepository.ImportJobMaterials", exp);
        }
    }
    return null;
}

 

The XML that’s generated from the code above looks like the following.  Security Note: We’ll assume that appropriate measures have been taken to clean the data and ensure it doesn’t contain any bad stuff related to injection attacks. That’s especially important if you’ll be running any dynamic SQL in your stored procedure.  I’m not, but I thought I’d be a good citizen and point it out…always sanitize your data with some Clorox before using it. :-)

<ArrayOfJobMaterialImport xmlns:xsi="www.w3.org/2001/XMLSchema-instance" xmlns:xsd="www.w3.org/2001/XMLSchema">
  <JobMaterialImport>
    <Area>BUILDING A</Area>
    <Phase>LIGHTING</Phase>
    <WorkCode>0</WorkCode>
    <WorkCodeTitle>Manually Assigned</WorkCodeTitle>
    <Description>4x1 1/2in. SQ BOX COMB KO</Description>
    <Quantity>2</Quantity>
    <TotalHours>10.46</TotalHours>
  </JobMaterialImport>
  <JobMaterialImport>
    <Area>BUILDING A</Area>
    <Phase>LIGHTING</Phase>
    <WorkCode>0</WorkCode>
    <WorkCodeTitle>Manually Assigned</WorkCodeTitle>
    <Description>#8x   3/4 P/H SELF-TAP SCREW</Description>
    <Quantity>4</Quantity>
    <TotalHours>0.28</TotalHours>
  </JobMaterialImport>
  <JobMaterialImport>
    <Area>BUILDING A</Area>
    <Phase>LIGHTING</Phase>
    <WorkCode>605</WorkCode>
    <WorkCodeTitle>Wiring and System Devices</WorkCodeTitle>
    <Description>1G TGL SWITCH PLATE - PLASTIC IVY</Description>
    <Quantity>2</Quantity>
    <TotalHours>0.89</TotalHours>
  </JobMaterialImport>
</ArrayOfJobMaterialImport>

 

Here’s what the stored procedure looks like:

 

CREATE PROCEDURE [ImportJobMaterials]
    @JobMaterialsXml AS VARCHAR(MAX),
    @JobID AS INT,
    @ChangeOrderNumber AS VARCHAR(10) = NULL,
    @ChangeOrderDescription AS VARCHAR(100) = NULL
AS
    BEGIN
        DECLARE @XML AS XML

        DECLARE @MaterialsTable TABLE
        (
            ID INT IDENTITY(1,1),
            Area VARCHAR(250),
            Phase VARCHAR(250),
            WorkCodeID INT,
            WorkCodeTitle VARCHAR(250),
            MaterialTitle VARCHAR(250),
            Quantity DECIMAL(18,2),
            TotalHours DECIMAL(18,2)
        )

        SELECT @XML = @JobMaterialsXml

        INSERT INTO @MaterialsTable (Area, Phase, WorkCodeID, WorkCodeTitle, MaterialTitle, Quantity, TotalHours)
        SELECT M.Item.query('./Area').value('.','VARCHAR(250)') Area,
               M.Item.query('./Phase').value('.','VARCHAR(250)') WorkCode,
               M.Item.query('./WorkCodeID').value('.','INT') WorkCodeID,
               M.Item.query('./WorkCodeTitle').value('.','VARCHAR(250)') WorkCodeTitle,
               M.Item.query('./MaterialTitle').value('.','VARCHAR(250)') MaterialTitle,
               M.Item.query('./Quantity').value('.','DECIMAL(18,2)') Quantity,
               M.Item.query('./TotalHours').value('.','DECIMAL(18,2)') TotalHours
        FROM @XML.nodes('/ArrayOfJobMaterialImport/JobMaterialImport') AS M(Item)

        --Process the data        
    END

Once the XML data comes in it’s converted into an XML data type using SELECT @XML = @JobMaterialsXml syntax.  The key part of the T-SQL code is the SELECT statement that grabs each value from the XML data type and looks for specific child nodes.  If the child nodes were attributes instead then you would do something like M.Item.value(‘@attributeName’,’DBType’).  Each JobMaterialImport node in the XML is located by the @XML.nodes(‘/ArrayOfJobMaterialImport/JobMaterialImport’) AS M(Item) code.  What’s nice about this approach is that a single call can be made to the database yet 1000s of records can be processed.  Not optimal for every situation, but exactly what I needed and fairly straightforward to use.

WP Like Button Plugin by Free WordPress Templates