Blog Archives

WPF ListView – Formatting Rows

 By the end of the previous blog item on the topic of the WPF ListView, the ListView looked like this:

In this blog I want to look at ways of changing the look of the rows. You may, for example, want to assign a background color to the rows. And based on what we have done so far, you might be tempted to edit the DataTemplates used for the cells. Maybe you would think about adding a Border with a Background fill and placing this around the TextBlock for each cell:  

  <DataTemplate x:Key="IDCellTemplate2">

      <Border Background="LightGreen">

      <TextBlock Foreground="MediumBlue"

                FontFamily="Calibri"

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

      </Border>

    </DataTemplate> 

I won't waste the space showing the markup for all three templates here, but if you did try this you will get a disappointing result:

Pretty ugly, I think you'll agree. Playing around with the Margin or Padding won't get you any further either.

The answer is to use the ItemContainerStyle property of the ListView. This opens up a number of choices for you. Firstly, if you would like to still have a gap between each of the columns – but an even gap – then you can take the following approach:  

      <ListView.ItemContainerStyle>

        <Style TargetType="ListViewItem">

          <Setter Property="HorizontalContentAlignment" Value="Stretch" />

        </Style>

      </ListView.ItemContainerStyle> 

This will produce the following output, which is an improvement:

If you want the light green to spread across the whole row, then you still use the ItemContainerStyle, but this time you set the Background property of the ListViewItem:  

      <ListView.ItemContainerStyle>

        <Style TargetType="ListViewItem">

            <Setter Property="Background" Value="LightGreen" />

        </Style>

      </ListView.ItemContainerStyle> 

Now you get the result you are probably looking for.

 

If all that whiteness in the background is a bit too much for you, then of course you can blend another shade of green into the mix by setting the ListView's Background property. Using SeaGreen, for example, will produce this:

 

 

The final markup for the ListView looks like this:  

    <ListView Name="ProductsListView"

         ItemsSource="{Binding}"

           Margin="5,25"

              Background="SeaGreen">

      <ListView.ItemContainerStyle>

        <Style TargetType="ListViewItem">

            <Setter Property="Background" Value="LightGreen" />

        </Style>

      </ListView.ItemContainerStyle>

 

      <ListView.View>

        <GridView>

          <!– Product ID –>

          <GridViewColumn

           HeaderTemplate="{StaticResource IDColHeader}"

          CellTemplate="{StaticResource IDCellTemplate}">

          </GridViewColumn>

          <!– Product Name –>

          <GridViewColumn

           HeaderTemplate="{StaticResource NameColHeader}"

           CellTemplate="{StaticResource NameCellTemplate}">

          </GridViewColumn>

          <!– Pack Size –>

          <GridViewColumn

           HeaderTemplate="{StaticResource PackageColHeader}"

           CellTemplate="{StaticResource PackCellTemplate}">

          </GridViewColumn>

        </GridView>

      </ListView.View>

    </ListView> 

The markup for the DataTemplates and Styles is the same as that shown in the previous blog, all of which I placed in the Application.xaml file (App.xaml for C# projects).

There are some other row formatting options I want to cover, but I will leave those for another day.

WPF ListView: DataBinding and Column Headers

 A recent question on VBCity came from a developer who was searching for a way of changing the background color, font and border of the Column Headers in a ListView. This has always been a particularly tough call in Windows Forms. (A DataGridView, on the other hand, does have this feature, so that might often be an easy workaround.)

But, as usual when questions of difficult layout come up, my mind turns to WPF as a possible solution. Usually I would say 'an easy solution', but in this case honesty forces me to say that I've always found the WPF ListView to be one of its less user-friendly elements. Windows Forms certainly makes it easier to create data by hand, with the ability to add sub-items via the properties window. WPF effectively forces you to use data binding as the means of populating the ListView – although the data source can be a relatively simple collection of objects.   So I thought it might be useful to blog how to create a relatively uncomplicated ListView in WPF – one with a differently colored Column Headers,of course.

There is quite a lot of repetition of the graphical characteristics of the various sub-elements of a WPF ListView – the Column Headers and the content of the columns themselves, for example. So, it is always worth spending the time to create Styles or Templates which can be reused. Not only does this save time in the long run, it reduces the amount of markup used to create the actual ListView itself in the Window which usually makes it a little easier to read.

The first version isn't going to be too ambitious and will look like this:

  

Of course I could have added lots of other graphics junk in there, but I want to try and keep things as straightforward as possible. By the time we've worked our way through the Styles, Templates and XML Data Provider, I think that will be quite enough for one session. In a later blog, I plan to expand on this version.

The Basic ListView
The first step is to drag an empty ListView from the Toolbox and drop it on the XAML pane. Note that I say XAML pane, not the Design pane. As in this case, it is often easier to start with an empty element rather than have to edit the default property settings that you will see in the XAML if you drop it on to the Design pane.

In order to display the content, a WPF ListView requires the use of a View. This has the same role as the View property in the Windows Forms ListView, i.e. it controls the manner in which the data is laid out. The similarities end there, however. At the time of writing, the WPF ListView only has one choice of view – the GridView. In its basic form, this is similar to the WinForms ListView Details View, (except of course that WPF isn't limited in the way you can package and display the data).

As you can see from the following screenshot, even if you wanted to choose a value for the View property, this is something that has to be created in XAML. Future versions of WPF may perhaps increase this choice, but WPF already gives you the freedom to use the equivalent of Large Icon, Small Icon, List, etc, if that is the look you want, so maybe not.

  

The markup to create the View is simple: 

      <ListView >

         <ListView.View>

             <GridView>

 

             </GridView>

         </ListView.View>

       </ListView>

 There will be very little to see in the Design Pane yet. The next step is to add some columns. Add three columns to the GridView of the ListView:

                <GridView>

            <GridViewColumn Width="85">

            </GridViewColumn>

            <GridViewColumn></GridViewColumn>

            <GridViewColumn></GridViewColumn>

        </GridView>

 If you check the Design pane now, you will see a fine outline of the Column Headers. There is a divider after the first column, because I have set a Width value on it. The other two columns are not visible because they currently have a zero width.

  

Create a Reusable Style
Each of the three Column Headers will have some properties that are set to the same values as each other. Therefore it makes sense to set those property values in one place and assign them to each Column Header. The alternative approach would be to repeat virtually the same XAML three times, which clearly isn't a sensible way forward. WPF Styles is the technique which makes this very easy to implement.

In this simple example I am going to use a TextBlock to hold the text of the Column Header. The following markup, which is placed in the Application.xaml file (for VB) or App.xaml file (for C#) creates a Style for a TextBlock:  

    <Style x:Key="ColHeaderText" TargetType="TextBlock">

      <Setter Property="Width" Value="110" />

      <Setter Property="Height" Value="29" />

      <Setter Property="FontSize" Value="14" />

      <Setter Property="FontWeight" Value="Bold" />

      <Setter Property="Background" Value="Yellow" />

      <Setter Property="Foreground" Value="Navy" />

    </Style>

 If you're not familiar with the concept of Styles, all it does is set values on an assortment of TextBlock properties. The Style is assigned a key – in this case 'ColHeaderText'. This Style can now be applied to any TextBlock in the application.

The markup for the ListView can now be extended to include a Header that contains a TextBlock:  

 <GridViewColumn Width="85">

             <GridViewColumn.Header>

              <TextBlock Text=" Product ID"

              Style="{StaticResource ColHeaderText}"  />

            </GridViewColumn.Header>

          </GridViewColumn>

 The TextBlock created by this markup has Text content of 'Product ID' and its color, font, etc are all set by the values stored in the Style. You can see the result in the Design pane screenshot below.

 

  

In the final version, I have added similar markup for the remaining two columns. I have left them out of the snippet above for brevity.

Populating with Data
As I mentioned earlier, you need to use some form of data binding to populate the ListView. In this example I am using a simple XML file. You can view this file here. The markup that creates the link between the application and the XML file is straightforward:

 

    <XmlDataProvider x:Key="ProductList" Source="Products.xml" />

 

It uses an XMLDataProvider which I've keyed as 'ProductList' so that it can be referred to elsewhere in the project. The source data comes from the Products.xml file, which is located with the other project files in Solution Explorer.

Now that we have a data source, the ListView's ItemsSource property can be set to point to it. The markup is a bit tortuous, but not as complex as it might first appear. Essentially, the ItemsSource property is assigned a Binding and that Binding links to the ProductsList data provider. From the ProductsList, XPath syntax is used to point directly to the Product elements in the XML file. XPath isn't always the easiest syntax to use, but in the case of our simple XML file this is relatively straightforward.  

ItemsSource="{Binding Source={StaticResource ProductList}, XPath=Products/Product}" 

Next, the various columns can be bound to the appropriate fields. The GridViewColumn has a DisplayMemberBinding property which , as its name implies, sets the Binding to be used for the content of the column. Once again, XPath is used for this.  

   DisplayMemberBinding="{Binding XPath=ProductID}" 

In the above snippet, DisplayMemberPath is assigned a Binding which links back to the ProductID element of the Products.xml file. (Note: If the field in the data source is an XML Attribute, as opposed to an Element, it is necessary to add a leading @ symbol to the XPath name.)

For this basic ListView, that's all that is needed. You can view the Application.xaml file here, and the markup for the Window here. In a future blog, I'll improve this basic version and look at some other functionality, but if you haven't previously dealt with WPF ListViews I hope this will get you started.

WPF: How To Animate a Gradient Brush

 

In the previous blog item in this series, I created a simple Animation in Visual Basic Code. This used a DoubleAnimation to animate the thickness of the gradient border. That example doesn't even begin to scratch the surface of what you can achieve with WPF Animation and – as you have seen demonstrated in the previous items – how you can include these animations in Windows Forms.

In this part, we will look at a slightly more complex animation. Or at least one that seems complex at first, but a quick analysis reveals that it is really rather simple and easily created by writing the XAML by hand.

In order to see the animation effect, I recommend you download the project attached to this blog item and run it. When you click the Button if there is no text in the TextBox, two animations will run. The first is the resize border one that was covered in the previous blog. The second animation changes the position of each of the colors in the gradient to give the impression of movement.

If you are new to WPF, you perhaps won't be too comfortable with the idea of hand-writing the XAML. You can of course use a tool, such as Expression Blend, to create the XAML for you. A time-limited trial version of Expression Blend is available, so if you decide that the hand-written route isn't for you, then you can certainly use Blend instead. (That said, there is something of a learning curve involved in getting to grips with Blend too – especially if, like me, you have more of a Developer mindset than Designer).

One of the reasons I decided to add this part to the blog was that sometimes you need to start the animation running from some user action. In this case, the user action will be the clicking of a button on a totally unrelated UI – a Windows Form, as it happens (although of course the same approach works fine with an all-WPF application too.)

So, firstly, here is the XAML that goes in the WPF UserControl to create the moving gradient effect: 

(Note that there is a formatting problem with the blog editor.  The GradientStop isn't really a Devil's Head it is the numeral 6 in square square brackets – [ 6 ], but without the spaces.  )

    <Storyboard x:Key="MoveColors" >

 

      <DoubleAnimation By="0.2" Duration="0:0:1.3"

         AutoReverse="True" 

         Storyboard.TargetName="GradBorder"

               Storyboard.TargetProperty="BorderBrush.GradientStopsDevil.Offset"

                BeginTime="0:0:0.6" />

 

      <DoubleAnimation By="0.2" Duration="0:0:1.3"

                       AutoReverse="True"

              Storyboard.TargetName="GradBorder"

               Storyboard.TargetProperty="BorderBrush.GradientStops[5].Offset"

                BeginTime="0:0:0.6" />

 

      <DoubleAnimation By="0.2" Duration="0:0:1.3"

                       AutoReverse="True"

             Storyboard.TargetName="GradBorder"

               Storyboard.TargetProperty="BorderBrush.GradientStops[4].Offset"

                BeginTime="0:0:0.6" />

 

      <DoubleAnimation By="0.2" Duration="0:0:1.3"

                       AutoReverse="True"

         Storyboard.TargetName="GradBorder"

               Storyboard.TargetProperty="BorderBrush.GradientStops[3].Offset"

                BeginTime="0:0:0.6" />

 

      <DoubleAnimation By="0.2" Duration="0:0:1.3"

                       AutoReverse="True"

             Storyboard.TargetName="GradBorder"

               Storyboard.TargetProperty="BorderBrush.GradientStops[2].Offset"

                BeginTime="0:0:0.6" />

 

      <DoubleAnimation By="0.2" Duration="0:0:1.3"

                       AutoReverse="True"

            Storyboard.TargetName="GradBorder"

               Storyboard.TargetProperty="BorderBrush.GradientStops[1].Offset"

                BeginTime="0:0:0.6" />  

 

      <DoubleAnimation By="0.2" Duration="0:0:1.3"

                       AutoReverse="True"

             Storyboard.TargetName="GradBorder"

               Storyboard.TargetProperty="BorderBrush.GradientStops[0].Offset"

                BeginTime="0:0:0.6" />

 

    </Storyboard> 

That may look like a lot of typing, but there's a whole lot of repetition in there, which means you can copy and paste the majority of it, then just make minor tweaks. 

 <Storyboard x:Key="MoveColors" > 

The first line shown above simply creates a new Storyboard instance and assigns it a name, or Key, that we can use to reference it.

The next block creates a DoubleAnimation.  

      <DoubleAnimation By="0.2" Duration="0:0:1.3"

         AutoReverse="True" 

         Storyboard.TargetName="GradBorder"

         Storyboard.TargetProperty="BorderBrush.GradientStopsDevil.Offset"

         BeginTime="0:0:0.6" /> 

Most of us tend not to think of Types such as Double numeric values when we are thinking about animation. In our mind's eye we are more likely to picture the physical result of such a change – the size of an element or its position, its shape or its color, perhaps. But it is perfectly possible to change the value of a Double Type, taking a set amount of time to make the change, and then having this change be visible to a user by assigning it to a property of an element that takes type Double.

That's exactly what we are doing here – changing the value of the Double that is being used to set the position of a GradientStop in a LinearGradientBrush. Here's a more detailed breakdown of what's going on:

By changes the Double value by the amount stated – in this case by 0.2. In our demonstration animation this moves one of the colors that make up the gradient 0.2 along the gradient's linear scale.

Duration sets the length of time taken to change the value from its starting value to the end of the By value. In this case it is 1.3 seconds.

AutoReverse set to True will ensure that the value returns to its starting value by the end of the Duration. In our gradient example this will cause the color to move 0.2 out and then return the same 0.2 distance back.

Storyboard.TargetName uses the WPF Attached Property syntax to identify which element is the target of the animation.

Storyboard.TargetProperty in a similar way identifies the property of the target element which is to be animated. See the further explanation below about the identification of the property.

BeginTime is an optional pause feature. The animation will only begin after an initial pause of (in this example) 0.6 seconds.

The TargetProperty in each of these DoubleAnimations is the Offset value of a GradientStop. If you look at the XAML which creates the BrightGradient LinearGradientBrush, you will see that it contains seven colors, each of which has its position in the gradient assigned by its Offset value. All we are doing in this animation is shunting each of the colors along by a value of 0.2 and this creates the effect of the color movement.

The particular block of XAML shown above animates the last GradientStop, which has an index of 6 – the index being zero based. When you look at the six DoubleAnimations which follow that one, the only difference is that the Index has changed so that the next GradientStop is targeted. So by copying and pasting the first DoubleAnimation, pasting it six times and then changing the value of the Index, this complex looking animation is shown to be very basic in reality.

All that remains now is to wire up this Storyboard in the code-behind.  

    Public Sub MoveColors()

        Dim SB As Storyboard = CType(FindResource("MoveColors"), Storyboard)

        If SB IsNot Nothing Then

            SB.Begin()

        Else

            MessageBox.Show("Can't find storyboard")

        End If

    End Sub 

The FindResource method is very useful in these kind of situations in WPF. I used it in the original example to change the LinearGradientBrush on the Border element and now we can employ it to find the animation. It allows you to dig into the XAML, find the markup you need for a particular task and use it. In this cas, the Resource we are looking for is the Storyboard that has a Key of 'MoveColors' – the one we have just dissected above.

Over in the Windows Forms Form1 code, the Button click has only one additional line from where we left it at the end of the previous blog. This calls the MoveColors procedure shown above, which in turn runs the animation. The additional line is: 

           MovingGradientTextBox1.MoveColors() 

You can see the remaining unchanged Button Click event code in the sample project attached.

WP Like Button Plugin by Free WordPress Templates