Archive for the ‘XAML’ Category.

How To Create An Animated ScrollViewer (or ListBox) in WPF

UPDATED 05/22/09

In the comments, someone mentioned that the project wasn’t working properly for keyed scrolling. I’ve updated the project with:

  • Key scrolling (left, right, up, down, page up, page down)
  • CanKeyboardScroll property on the AnimatedScrollViewer so that keyboard scrolling can be turned off
  • ScrollToSelectedItem property on the AnimatedListBox so that the user can have it automatically scroll to a ListBoxItem

That last one is a little hacky… I use the ListBox ItemContainerGenerator to get the heights of all the items up to the one you want and then scroll it that. I’m almost positive there is a better way and if anyone knows what it is, I’d love to hear it.

First things first, here are the project files.

Animated ScrollViewer and ListBox Project Files (Updated 5/22/09) – Contains the AnimatedScrollViewer control library with AnimatedScrollViewer and AnimatedListBox

Animated ScrollViewer and ListBox DLL (Updated 5/22/09) – For those of you who don’t care how it works and just want it to work

OK… this is going to be something of a whirlwind since I’ve never written a post this in-depth before… it will strain the limits of my ADD.

Problem:

The Listbox/ScrollViewer not only doesn’t animate, but it seems impossible to tweak it so that it animates.

The Reason:

The reason has everything to do with the ScrollViewer. Basically, the ScrollContainer and the ScrollBars are very tightly intertwined. There is a lot of code that does all the scrolling calculations and that code needs to apply to the scrolled content as well as the UI for the ScrollBars. If you dig deep enough, you’ll see the reasons. Reasons which I assume for the moment you don’t care about… you’re probably in more of a “make the @#&($ thing work!” mood. I know I was.

The Solution:

My solution was basically to completely bypass the built-in ScrollBars and put in new ScrollBars with new logic. They look and act just like normal ScrollBars, so you should be able to style them just you would any normal ScrollViewer.

OK… how I did it. (I’m going to use both Blend 2 and Visual Studio 2008)

First, create a new custom control for WPF. This can be done by going into Visual Studio and creating a new Project. Select “WPF Custom Control Library”

clip_image001[7]

In Blend:

 clip_image001[9]

Add a WPF application to the project too so you have something to test. In the WPF application, get Blend to generate the default template for a normal ScrollViewer, accessible (in Blend) by putting a ScrollViewer into the project and right-clicking on it and selecting “Edit Control Parts (Template) –> Edit a Copy…”

clip_image001

Once have the default ScrollViewer template, select the “PART_VerticalScrollBar” and the “PART_HorizontalScrollBar” and copy and paste them. Rename your new ScrollBars something you like… I used “PART_AniVerticalScrollBar” and “PART"_AniHorizontalScrollBar”. Now, set the Visibility of the original ScrollBars to “Collapsed”. (We can’t get rid of them, because the ScrollViewer will be looking for them and will throw a conniption if it can’t find them.)

Also, change the Value of your new ScrollBars to 0. You’ll probably have to click on the orange box next to Value and select “Reset”.

clip_image001[11]

In Visual Studio, right-click on your WPF Custom Control project and go to “Add –> New Item…” . Then select “Custom Control (WPF)” and name it something you like (mine is named AnimatedScrollViewer). This should add a class to your project as well as a basic template to your Generic.xaml file.

Copy the ScrollViewer template that we just made and paste it into the Generic.xaml. The only change we need to make is to change:

TargetType="{x:Type ScrollViewer}"

to

TargetType="{x:Type local:AnimatedScrollViewer}"

in the Style and the ControlTemplate.

OK… that’s pretty much it with the XAML. Now we get to move into the code.

Right now, our class inherits from Control, but we want it to inherit from ScrollViewer like so:

public class AnimatedScrollViewer : ScrollViewer

Next get some containers for our new spiffy ScrollBars so that we can access them from the custom control code. Type the following before the class:

[TemplatePart(Name = "PART_AniVerticalScrollBar", Type = typeof(ScrollBar))]
[TemplatePart(Name = "PART_AniHorizontalScrollBar", Type = typeof(ScrollBar))]

and the following just inside the class:

ScrollBar _aniVerticalScrollBar;
ScrollBar _aniHorizontalScrollBar;

Now, we’ll override the OnApplyTemplate and make the connection between the template scrollBars and our class ScrollBars:

public override voidOnApplyTemplate()
{
    base.OnApplyTemplate();

    ScrollBar aniVScroll = base.GetTemplateChild("PART_AniVerticalScrollBar") asScrollBar;
    if(aniVScroll != null)
    {
        _aniVerticalScrollBar = aniVScroll;
    }
    _aniVerticalScrollBar.ValueChanged += newRoutedPropertyChangedEventHandler<double>(_aniVerticalScrollBar_ValueChanged);

    ScrollBar aniHScroll = base.GetTemplateChild("PART_AniHorizontalScrollBar") asScrollBar;
    if(aniHScroll != null)
    {
        _aniHorizontalScrollBar = aniHScroll;
    }
    _aniHorizontalScrollBar.ValueChanged += newRoutedPropertyChangedEventHandler<double>(_aniHorizontalScrollBar_ValueChanged);

    this.PreviewMouseWheel += newMouseWheelEventHandler(AnimatedScrollViewer_PreviewMouseWheel);
}

Before we address the three event handlers we added, we need to create the Dependency Properties with which they will be futzing.

(We’re going start going a little bit faster. Please download the code for the excruciating detail.) We need to add the following Dependency Properties. I’m using a “PropertyName (type)”.

Dependency Properties

ScrollingTime (TimeSpan) – This will be an easy way to change the speed of the scrolling. I created mine to default at half a second, but if you changed it to 0 seconds, it would act just like any normal ScrollViewer.

ScrollingSpline (KeySpline) – This property along with the ScrollingTime property is meant to give designers and developers the easiest control possible over the animation. This property describes the spline along which the scrolling will animate. If you don’t know what this means, just leave it alone, you’ll be fine.

TargetVerticalOffset (double) and TargetHorizontalOffset (double) – These are properties that tell the ScrollViewer where it will be animating to. In the PropertyChangedCallback, they kick off a method that starts the animation.

VerticalScrollOffset (double) and HorizontalScrollOffset (double) – For some reason the normal VerticalOffset and HorizontalOffset properties in a ScrollViewer are not capable of animation. So I wrote these properties that can be animated using standard storyboard procedures. If you use them to animate, make sure you also change the TargetVerticalOffset and TargetHorizontalOffset stuff as well… otherwise there will be a disconnect between the two.

Event Handlers

CustomPreviewMouseWheel event handler – This grabs any mouse wheel spinning and uses it to change the TargetVerticalOffset so that the ScrollViewer will still animate the scrolling when the mouse wheel spins.

VScrollBar_ValueChanged and HScrollBar_ValueChanged event handlers – These are called whenever the the ScrollBars are interacted with. There was a really weird problem with some of the interaction (the arrow keys and fast-scrolling buttons weren’t working properly), so these handlers hold logic to try to translate the weirdness into something viable. They then set the Target_Offset properties appropriately.

Methods

animateScroller – This method builds the animation programmatically based off of the appropriate properties and runs it.

And that’s really about it. Once you have the AnimatedScrollViewer working, you can just add use it inside your ListBox templates and it should work. (For those who are averse to doing such a thing, I’ve added extremely simple AnimatedListBox.)

Using the "Tag" Field And Triggers To Avoid Writing a Value Converter in WPF

I was working on a project recently and I wanted one of my layout controls to have a different margin based on a certain piece of data.

(It’s a long story… let’s just say that this is a good post if you want to change properties of a control based on a piece of data of a different type.)

So… for the sake of the argument, let’s say that I want my control to have a margin of “4,4,4,4″ if my data returns “dog” and I want it to have a margin of “2,2,2,2″ if my data returns “cat” and a margin of “0,0,0,0″ if the data is anything else.

Normally, I would use a value converter for this. My problem was that I was sick of using value converters for things so specific and using them only a couple times in my application. So I decided I wanted to do this one with styles and triggers.

First thing I did was bind my data to the “Tag” field.

<Border Style=”{DynamicResource MyBorderWithTriggers}” Tag=”{Binding MySpecialData}” >

Then, I created a style for my Border layout control. If you’re in Blend, go to Object –> Edit Style –> Create Empty…

clip_image001

Create a new property trigger by clicking on the “+ Property” button and change the property to “Tag”.

clip_image001[5]

I couldn’t find a way to type “dog” into the field value, so I did it in the XAML (full XAML sample below, for those of you who want to cut to the chase… you know who you are).

With the property trigger highlighted, you’ll see a “Trigger recording is on” sign in the corner of your canvas.

clip_image001[7]

Just change all the properties you want. Of course, in this case, I’m just going to change the Margin property. If we do the same thing for the “Cat” contingency, we get the following style.

<Style x:Key=”MyBorderWithTriggers” TargetType=”{x:Type Border}”>
        <
Setter Property=”Margin” Value=”0,0,0,0″/>        <Style.Triggers>
                <Trigger Property=”Tag” Value=”Dog”>
                        <Setter Property=”Margin” Value=”4,4,4,4″/>
                </Trigger>
                <Trigger Property=”Tag” Value=”Cat”>
                        <Setter Property=”Margin” Value=”2,2,2,2″/>
                </Trigger>
        </Style.Triggers>
</
Style>

And we end up with a layout that changes its properties based on a bound value. And we don’t have to write endless value converters.  Pretty handy… or at least I thought so.

Using Silverlight to Display JSON Data (Collected From The New York Times API)

In this post, you’ll either need to walk through this tutorial on how to call and prepare JSON data gathered from the New York Times API or, if you’re not particularly interested in doing that, you can just download the final project here. This tutorial pretty much assumes that you’re starting from the end of that tutorial.

Fortunately for everyone involved (especially me), this tutorial is much shorter. It is also another in my “without a line of code” series in which you can do everything without even touching the code. Let’s open up our project in Blend and get started. (To see an example what this tutorial makes, scroll to the bottom of this post.)

First of all, I lied. You do have to touch one line of code because you need to get your NYT API key and plug it into the myApiKey variable in the Page constructor (line 26 in the project available for download). The line should look like this:

myApiKey = “&api-key=your_api_key_here”;

Now, right click on the project solution and select “Build Solution” (in Visual Studio or Blend, it doesn’t matter).

clip_image001

This should build the assemblies so that Blend can do a really neat trick. In the Project tab in Blend, you should see a Data panel in the bottom half. Click on the “+ CLR Object” button.

clip_image001[5]

A pop-up will gently encourage you to name your new data source and choose from a list of available data sources. Select “NYTResult” and hit OK.

clip_image001[7]

You will now have your NYTResult data source show up in your Data pane. Before we start building a nice slick looking interface, select your ListBox (named “ResultsDisplay”) and, in the Properties pane, find the “Display Member Path” and reset it by clicking on the little gray box to the right.

clip_image001[13]

Now, right-click on the ListBox  in your “Objects and Timeline” panel and select “Bind ItemsSource to Data…”

clip_image001[9]

Select the data source you just created and select “NYTResult”. Then click on “Define DataTemplate” at the bottom. This will take you to the “Create Data Template” panel, where the fun happens. You will see “New Data Template and Display Fields” automatically selected. We like this. This lets us select all the data we want and give it some basic structure and Blend will do all the bindings for us.

Let’s make a few changes from the standard Data Template setup. Expand the Date field and check Day, DayOfWeek, Month, and Year and change the order with the up and down buttons to something you like. Then, change the Url from “StackPanel” to “TextBlock”. I reordered the data a little bit, so my template looks like this:

clip_image001[15]

Hit OK. The point of that whole exercise was so that Blend would build our data template for us. We don’t actually want the data source and we don’t want our ListBox bound to it. So reset the “ItemSource” property on the ListBox and remove the NYTResult data source. If you run the project now, you should get something like this:

clip_image001[17]

At least we’re getting more data now. Doesn’t look that great, but we’re getting there. Go back to your project in Blend and right-click on your ListBox and go to “Edit Other Templates –> Edit Generated Items (ItemTemplate) –> Edit Template”

clip_image001[19]

We’re now in the DataTemplate but we sadly have no visible data, which makes manipulating it a tad difficult. What I have found works best for me is just to build my desired layout with static data and then translate the bindings. (I haven’t mentioned this, but you should be working in Split mode as a general rule, so you should be able to see the bindings in the XAML.)

So… long story short (it’s getting really late here): I changed the layout to replicate the NYT story design… the Title is a hyperlink button that takes us to the full story, followed by a small byline, the beginning of the story and the date on which the story appeared. If you’d like to look at the design itself in more detail, download the project at the end of this post.

I do want to mention one issue… the issue of getting your text to wrap. With my current redesigned DataTemplate, my project looks like this:

clip_image001[21]

It scrolls horizontally to a degree that is certainly unhealthy. What is happening is that the TextBlock in the DataTemplate is making a request for space and when it hits a limit, it will start wrapping. Unfortunately for us, when the ScrollViewer in the ListBox has the HorizontalScrollBarVisibility set to “Auto”, it is telling the TextBlock that it has all the room in the world and that it doesn’t need to wrap. So, let’s just change the HorizontalScrollBarVisibility on the ListBox to “Disabled”.

And we’re done.

You can download the source here

JSON – Silverlight – New York Times Tutorial (Part 2) Project Files

Questions and comments are always welcome.

XAML Intellisense for Blend

Karsten Januszewski has a post on getting intellisense into Blend. Apparently it only works for WPF (it “works” for Silverlight, but it pulls from the WPF XML schema, which sounds like it could be more confusing than useful).

I’ve been begging for this for a while. I’m glad to see it in there… its has easily been the biggest missing feature in an otherwise fantastic product.

Getting a MouseLeftButtonDown or MouseLeftButtonUp Event From Your TextBox

One of the nifty little tricks I got working in my attempt to update my Silverlight Color Picker was that I wanted to have the entire content of a TextBox to select when I clicked on it. Imagine my surprise when clicking on the TextBox didn’t fire either a MouseLeftButtonUp or a MouseLeftButtonDown event!

This stunned me a little bit. Turns out there is a big discussion about this over at the Silverlight Forum. Long story short, I needed to add this code to my project (you’ll see it in my Color Picker project if you download it).

Add this code to your MyPage.xaml.cs file:

public class TextBoxClickable : TextBox
{
     protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
     {
           base.OnMouseLeftButtonDown(e);
           e.Handled = false;
     }

     protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
     {
           base.OnMouseLeftButtonUp(e);
           e.Handled = false;
     }
}

Your XAML should define your namespace:

<UserControl x:Class=”MyProjectName.MyPage
      xmlns:clickable=”clr-namespace:MyPage“>

And you can use your new clickable TextBox like this:

<clickable:TextBoxClickable MouseLeftButtonDown=”TextBox_SelectAll/>

If you’re like me and want to select everything in the TextBox with a single click, your method will look like this:

private void TextBox_SelectAll(object sender, MouseButtonEventArgs e)
{
     TextBox selectionBox = (TextBox)sender;
     selectionBox.SelectAll();
}

That’s it. I’ll post my updated color pickers in a couple hours.

Styling a Silverlight ScrollViewer (to Look Like a Mac ScrollViewer)

Mac Scroller Project Files Updated for RCW

Just because we’re working in Microsoft technologies doesn’t mean we can’t throw a bone to our Mac friends. After all, they are the people we love, our cousins and our neighbors, and that irritating guy who is dating our daughter and can’t seem to shut up about how awesome his Mac is even though he’ll be long out of his program in musical costume design before he ever pays off his laptop …

Issues? I don’t have issues. Why do you ask?

Anyway, since Silverlight is a semi-ubiquitous technology, it would be nice if we could cater to all platforms and not make anyone feel left out. And nothing makes people feel more left out than when they expect their application to work one way and it doesn’t.

So, here’s a picture of what we’re going for.

clip_image001

As far as I’m concerned (and therefore as far as this tutorial is concerned) the important stuff is to make sure that the incremental buttons (the arrow buttons in the bottom right) are in the right place. We can deal with the color later.

OK, so let create our ScrollViewer (I’ll be using Blend exclusively for this). I tossed a button in it and made it small so we can see both of the ScrollBars.

clip_image001[4]

Right click on the ScrollViewer in the “Objects and Timeline” section and go down to “Edit Control Parts (Template) -> Edit a Copy…”

clip_image001[6]

You should have something that looks like this:

clip_image001[8]

Let’s do the VerticalScrollBar first. Right click on it and go to “Edit Control Parts (Template) -> Edit a Copy…” Name it something memorable and you should get something like this:

clip_image001[12]

This is actually easier than it looks. The unnamed rectangles and the path lay down the basic visual backbone for the ScrollBar and the rest of it runs like this:
clip_image001[14]
VerticalSmallDecrease – The up button
VerticalLargeDecrease – The space between the up button and the VerticalThumb
clip_image001[16]
VerticalThumb – The interface element that allows the dragging interaction of the scrollbar
VerticalLargeIncrease – The space between the down button and the VerticalThumb
clip_image001[18]
VerticalSmallIncrease – The down button

The horizontal root in this template is strikingly similar.

So, let’s start by moving the VerticalSmallDecrease button down to the bottom above the VerticalSmallIncrease button. The magic here will happen in the VerticalRoot grid. (I highly recommend the Design/XAML split view for this one.) In the design view, our grid looks like this:

clip_image001[20]

Ugly. However, in the XAML, it looks like this:

<Grid.RowDefinitions>
<
RowDefinition Height=”Auto”/>
<RowDefinition Height=”Auto”/>
<
RowDefinition Height=”Auto”/>
<
RowDefinition Height=”*”/>
<
RowDefinition Height=”Auto”/>
</
Grid.RowDefinitions>
<
Grid.ColumnDefinitions>
<
ColumnDefinition/>
<
ColumnDefinition/>
</
Grid.ColumnDefinitions>

Much easier. For the purposes of maintaining a coherent structure, drag the VerticalSmallDecrease in Objects and Timeline pane until it is between the VerticalSmallIncrease and the VerticalLargeIncrease. Next, change the third RowDefinition to “*”. You can do this in the XAML or by clicking on the “Auto” iconimage until it becomes a “*” icon. image Change the fourth RowDefinition from “*” to “Auto”. When you do this, it won’t immediately act like an “Auto”. This is because Blend gives it an automatic “MinHeight” of whatever the current Height is. You can change that in the XAML (easiest move) or you can highlight that row by clicking just below the “Auto” icon until the row highlights in a semitransparent gray like so.

clip_image001[28]

You may need to zoom in to do this. Once highlighted, the properties of the Row will show up in the Properties tab on the right. Change the MinHeight to 0.

clip_image001[32]

Now we’ll need to change the Grid.Row properties of almost everything. Click on the items in the Objects and Timeline and change the Row property in the Layout section of the Properties tab like so:

VerticalLargeDecrease -> Row = 0
VerticalThumb -> Row = 1
VerticalLargeIncrease -> Row = 2
VerticalSmallDecrease -> Row = 3
VerticalSmallIncrease -> Row = 4

You’re done. With the Vertical part of the ScrollBar at least. You can do the same thing with the Horizontal part of it. Just move around the buttons, change the ColumnDefinitions and update the Column assignments. My best recommendation is to go back to the ScrollViewer template and assign your new ScrollBar template to the HorizontalScrollBar and then go back to editing the template from there.

clip_image001[34]

Later on…

After a bunch of color tweaking, I have a scroll viewer in silverlight that looks like this:

clip_image001[36]

I’m feeling OK with it. I’ve embedded what I have at this point below.

Tip For Finding Resources for a Control in generic.xaml

I’ve recently be working on changing the ControlTemplate of a GridViewColumnHeader in a custom ListView that we’ve been working on. (The ListView was rewritten for sorting, so that’s why it had to be custom.)

One of the things we had to do was swap out ControlTemplates so that we could display a caret to indicate ascending or descending lists. We ended up deciding on ControlTemplates over DataTemplates because the DataTemplates would only work for ListViews that had no custom DataTemplates for the headers. We’re doing all sorts of crazy stuff with our headers and we need to preserve our DataTemplates, so this wasn’t an option.

In any case, I was having no luck finding the resource when I named it this way:

<ControlTemplate x:Key="MyCustomControlTemplate" TargetType="{x:Type GridViewColumnHeader}">

I was using the following code to try and find the resource.

ControlTemplate myNewTemplate = (ControlTemplate)Resources["MyCustomTemplate"];

However, we were able to solve the problem by naming the resource this way

<ControlTemplate x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type local:MyCustomListView}, ResourceId=MyCustomControlTemplate}"
        
TargetType="{x:Type GridViewColumnHeader}">

And then using this code to access it.

ComponentResourceKey myCustomTemplateKey = new ComponentResourceKey(typeof(SortableListView), "MyCustomControlTemplate");
ControlTemplate myNewTemplate = (ControlTemplate)this.TryFindResource(myCustomTemplateKey);

Just thought I’d pass it along.

How to Assign ColumnHeaderContainerStyle and ColumnHeaderTemplate to a ListView Style

This is just a quick note on creating a ListView style with the appropriate GridView style and template assignments.

Normally, I’ve been creating listviews that look like this:

<ListView x:Name=”MyListView”
               ItemContainerStyle
=”{DynamicResource MyListViewItemContainerStyle}”>
   
<ListView.View>
        
<GridView ColumnHeaderContainerStyle=”{DynamicResource MyListViewHeaderStyle}”
                        
ColumnHeaderTemplate=”{DynamicResource MyGridColumnHeaderTemplate}”> 

I did this because I didn’t know exactly how to assign these styles and templates to the ListView Style. In the style, ColumnHeaderContainerStyle and ColumnHeaderTemplate are not properties of the ListView, they are properties of the GridView… which you can’t create a style for.

Instead, you can encapsulate all the information above in the following style.

<Style x:Key=”CustomListViewStyle” TargetType=”{x:Type ListView}”>
      <
Setter Property=”GridView.ColumnHeaderContainerStyle” Value=”{DynamicResource MyListViewHeaderStyle}” />
     
<Setter Property=”GridView.ColumnHeaderTemplate” Value=”{DynamicResource MyGridColumnHeaderTemplate}” />
     
<Setter Property=”ItemContainerStyle” Value=”{DynamicResource MyListViewItemContainerStyle}” />
</Style>

Problem solved.

How Do I Make a ListView or a ScrollViewer Left Handed?

Several months back, I was doing some work for a company that was using WPF for a stylus based application. One of the things that they found they needed was a scrollbar that could be used by left handed people who would have to cover the entire screen with their left hand in order to scroll a traditional scroll viewer.

The solution ended up being so easy in WPF that I thought I’d post it here.

I’m in a two-birds-one-stone mood, so we’ll do this for both the listview, which will also cover a more traditional scrollviewer. Let’s start with our ever friendly listview.

NormalListViewAt the very sight of this thing, with a stylus in hand, your average lefty is thinking to him or herself “I wonder if I can do my work upside down?” Let’s show them that we love and accept them just as they are.

The first thing we’re going to do is create a new template for this sucker, so right click on your listview and go to “Edit Control Parts (Template) -> Edit a Copy…

Lefty_EditControlParts

Now we’re looking at the standard listview template. Mine looks like this:

ListViewTemplateLet’s dig right into the ScrollViewer. If you’re doing this from the listview (like I am) then creating a template for the listview has already created a template for the scrollviewer. If you’re starting from a basic scrollviewer, you can pretty much start right here.

For the purposes of making this thing easy to work with in Blend, go ahead and set the HorizontalScrollBarVisibility and VerticalScrollBarVisibility to Visible.

 ScrollBar_Visibility

And then “Edit Control Parts (Template) -> Edit a Copy…” (or “Edit Control Parts (Template) -> Edit Template” if it is available).

We are now looking at the guts of the ScrollViewer Control.

ListView ScrollViewer will look like this:

ListViewScrollTemplateThe normal ScrollViewer will look like this:

 NormalScrollViewer

For our purposes, they’re functionally the same. It is actually a fairly simple control… basically just a Grid panel with the columns and rows set up like so:

<Grid.ColumnDefinitions>
      <ColumnDefinition Width=”*/>
      <ColumnDefinition Width=”Auto/>
</Grid.ColumnDefinitions>

<Grid.RowDefinitions>
      <RowDefinition Height=”*/>
      <RowDefinition Height=”Auto/>
</Grid.RowDefinitions>

The scrollBars are set up so that their visibility is tied to (duh) the visibility that is set on the control. But what this does is it means that when they are collapsed… they Grid reclaims the space that they were taking up.

Now… here’s the hilarious part… in order to make this ScrollViewer left handed, all you have to do is swap the Grid.Columns:

<Grid.ColumnDefinitions>
      <ColumnDefinition Width=”Auto/>
      <ColumnDefinition Width=”*/>
</Grid.ColumnDefinitions>

You’ve now switched the columns so that the left handed column is auto. Here’s a list of the Grid.Column realignments you’ll need to make:

Change Column to “1″:

Lefty_Column1

  • PART_HorizontalScrollBar
  • All DockPanels (ListView only)
  • PART_ScrollContentPresenter (ScrollViewer only)
  • Corner (ScrollViewer only)

Change Column to “0″:

Lefty_Column0

  • PART_VerticalScrollBar

Basically, swap everything from in the two columns.

Done.

FinalLeftyListViewIf you want to make this a more robust control, I recommend creating a ScrollViewer with an additional dependency property (IsSouthPaw or something). Make it so that your Grid has three columns:

<Grid.ColumnDefinitions>
      <ColumnDefinition Width=”Auto/>
      <ColumnDefinition Width=”*/>
      <ColumnDefinition Width=”Auto/>

</Grid.ColumnDefinitions>

And then you can just create a trigger that swaps the column placement of your PART_VerticalScrollBar. Such a trigger will look something like this. And by “something”, I mean “exactly”.

<Trigger Property=”IsSouthPawValue=”True>
      <Setter Property=”Grid.ColumnTargetName=”PART_VerticalScrollBar“  Value=”0/>
</Trigger>

Go forth and make Ned Flanders proud.

By the way, I listen to pop punk whenever I write my tutorials and I just thought I should let Senses Fail know that they can probably get away with about 80% less “dying cat” screaming and still put out good music. You know… because they’re probably WPF programmers on the side and they’ll probably read this to solve all their left-handed scrollbar needs.

WPF Designers Guide to Styles And Templates

This is a post that has taken months to complete, but addresses something that I don’t think I’ve seen sufficiently covered for anyone who is new to WPF. Resultantly, we’re going to go through it slowly and I’m officially begging for additional questions at the end.

Part of the problem with styles and templates in WPF stems from the fact that Blend allows a wonderfully simply way of creating a copy of a template:

SNT_EditControlParts

It then gives you something that looks like this:

<Style x:Key=”My_TemplateTargetType=”{x:Type Button}>
      <Setter Property=”Template>
            <Setter.Value>
                  <ControlTemplate TargetType=”{x:Type Button}>
                        <!– blah blah blah –>

So, from a usability point of view… I told it to create a Template and it created a style. I judged from this that styles and templates were roughly the same thing.

And I was confused.

So, first, I’ll try to explain styles and templates by explaining how they work and then I’ll draw an analogy that I hope is helpful.

Let’s say you have a button.

Hi_Button

You can change all sorts of properties of that button… visibility, background, width, height, margins, border thickness, alignment, font, whatever.

If you have a dozen buttons and you want them all to have the same properties, you can create a button style that specifies those properties and assigns them across the board. You can edit a style in Blend by selecting your control, clicking in the menu: “Objects -> Edit Style -> Edit a Copy…“.

Style editing in the objects tab will look like this.

Style_Objects

As you can see, there are no objects in the visual tree to play with… only properties to assign in the properties tab.

Button_Style_Properties

When you assign a property in Blend, your styles will save that assignment as setters and values. Let’s say we wanted all of our buttons to have green 18 point font  bold text. We could create a style that looked like this:

<Style x:Key=”GreenBorderButtonTargetType=”{x:Type Button}>
      <Setter Property=”ForegroundValue=”#FF00FF00/>
      <Setter Property=”FontSizeValue=”18 />
      <Setter Property=”FontWeightValue=”Bold/>
</Style>

The styles can only define properties that belong to the control type that they are styling (which is defined in the “TargetType“). Also, styles can only give information for properties the control already has and only in the way that the control is already set up. For example, because there is no property for changing the corner radius of a button, you can’t change the corner radius of a button using a button style.

However, what if we want to change something about the button that we can’t change with the given properties? For example, let’s say we wanted to see all the text show up twice.

Double_Button

In order to do this, we need to make what I’m going to call “structural changes” to our control. Structural changes are changes in the actual guts of the control, changes to the base elements that make up the control. For this we need a control template.

Boiled down to their essence, templates are little chunks of XAML that are inserted whenever you use your control. When you right click on something and go to  “Edit Control Parts (Template) -> Edit a Copy…“, Blend takes the default XAML that makes up your control and places it in the resources so that you can change it at your whim.

You can get to the Control Template using the right-click method described at the top of this post. Your basic button template will look something like this:

Button_Template

<Style x:Key=”MyButtonStyleTargetType=”{x:Type Button}>
      <Setter Property=”TemplateValue=”{DynamicResource MyButtonTemplate}/>
</Style>

<ControlTemplate x:Key=”MyButtonTemplateTargetType=”{x:Type Button}>
      <Microsoft_Windows_Themes:ButtonChrome x:Name=”Chrome>
            <ContentPresenter />
      </Microsoft_Windows_Themes:ButtonChrome>
</ControlTemplate>

We can go in and add an additional ContentPresenter in here, like so:

<ControlTemplate x:Key=”MyButtonTemplateTargetType=”{x:Type Button}>
      <Microsoft_Windows_Themes:ButtonChrome x:Name=”Chrome>
            <Grid>
                  <Grid.RowDefinitions>
                        <RowDefinition Height=”.5*/>
                        <RowDefinition Height=”.5*/>
                  <Grid.RowDefinitions>
                  <ContentPresenter Grid.Row=”0/>
                  <ContentPresenter Grid.Row=”1/>
            </Grid>
      </Microsoft_Windows_Themes:ButtonChrome>
</ControlTemplate>

And now our button shows all the content twice, one right on top of another.

The best way I’ve found to think about it is to think of your control as a car.

The dealer give the buyer a list of things that they can change about the car… interior color, leather or fabric seats, 4 or 6 cylinder engine… these are properties of the car… defined in the car “style”. (Basically, you can think of everything that you’re allowed to tweak at this website as the style of the car.)

<Style x:Name=”MySpecialCarTargetType=”{x:Type Camry}>
      <Setter Property=”ExteriorColorValue=”Blue/>
      <Setter Property=”TransmissionTypeValue=”5SpeedManual/>
</Style>

Camery_Basic
 
But let’s say that the buyer doesn’t want a normal seat… she wants a big comfy chair in place of the regular drivers seat. This is something outside of the scope of the list of things she was allowed to choose from, so they have to draw up new blueprints for making this new car. They have to create a new car “template”.

If our normal Camry blueprint looks like this:

<ControlTemplate x:Key=”MySpecialCarBlueprintTargetType=”{x:Type Camry}>
      <CamryFrame x:Name=”CamryFrame>
            <Seat Type=”Drivers/>
            <Seat Type=”FrontPassenger/>
            <Seat Type=”BackBench/>
      </CamryFrame>
</ControlTemplate>

We can go in and replace :

<Seat Type=”Drivers/>

With

<Seat Type=”ComfyChair/>

ComfyChair

You may also notice that, with this model we could get rid of all the other seats except the drivers seat or we could add 12 new rows of seats. We can change anything about the car because we’re down into the original car blueprint.

This is the basic difference between styles and templates.

  • A style is a list of properties that can be assigned in bulk to a control.
  • A template goes a big step further and actually defines the underlying structure of the control.

You may be asking: “So how do these two work together? And what is this Data Template think I keep hearing about?”

Given that this post is getting dangerously long already, I’m going to address those issues in a couple more posts on styles and templates.

I’ll end on this note: if you are working in WPF and you’re having trouble with styles and templates, please read all of these posts (as I get to them) and ask questions in the comments section. I’m pretty good about getting to the comments questions and if the question is big enough, I’ll write a whole post on it. There are few things more vital to a WPF developer/designer than to have a firm grasp on styles and templates. It is in this understanding that the power of WPF really comes out.

  • Who’s The Boss? Property Priority in Styles and Templates (coming soon)
  • Create Conditional Styles and Templates (With the Magic of Triggers) (coming soon)
  • So How Do Data Templates Fit Into All This? (coming soon)