Archive for the ‘Binding’ 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.)

INotifyPropertyChanged Snippets (And Why You Should Use These Instead of DependencyProperties)

First things first, here are my INotifyPropertyChanged snippets.

INotifyPropertyChanged snippet (PropertyChangedEventHandler and RaisePropertyChanged method)

INotifyPropertyChanged Property snippet

Just download them into your "Visual Studio 2008CodeSnippetsVisual C#My CodeSnippets" folder and they should work. Just type "notify" and intellisense should show you "notifyo" (for NotifyObject) and "notifyp" (for NotifyProperty). Hit tab twice and the code should dump into your project.

This is definitely a "use at your own risk" project.

You see, there I was, minding my own business and trying to build some data to use with some XAML comps I was playing with and I was having some of the strangest things happen with my data. I had a DependecyProperty ObservableCollection in my ViewModel and I put a couple different views in my screen. (I was using an MVVM pattern, because that’s what all the kool kids are doing.)

Then, it suddenly seemed as if all my Views were sharing the same ObservableCollection, even though every other DependencyProperty they were bound to had unique values. So I did what I always do when I have problems like this… I ask Joe McBride.

It turns out I had gotten confused. I understood that DependencyProperties were good for the following:

  • Providing callbacks when the property is changed
  • Binding to stuff
  • Animations

I figured that this is the kind of behavior I wanted from my data. I was wrong. As it turns out that is the kind of behavior I want out of the properties that I use in my WPF and Silverlight controls. It seems that DependencyProperties are meant to be used with controls and not for stand-alone data.

For stand-alone data, I should have used INotifyPropertyChanged, which is an interface for… well… notifying things when a property changes. I already had handy snippets for creating DependencyProperties (thanks to Robby Ingebretsen). So I tweaked his snippets so that they work for INotifyPropertyChanged properties.

Because it seems silly to implement the PropertyChangedEventHandler in every class that needs notify-able properties, I like to create a "NotifyObject" class:

class NotifyObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if(handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }       
}

Then, I can make my new class inherit from NotifyObject and away I go creating my bindable, notify-able data:

public class MyNotifyableData : NotifyObject
{
    public MyNotifyableData()
    {
    }

    #region MyProperty (INotifyPropertyChanged Property)
    private string _myProperty;

    public string MyProperty
    {
        get { return _myProperty; }
        set
       
{
            _myProperty = value;
            RaisePropertyChanged("MyProperty");
        }
    }
    #endregion
}

This property was created using my snippet above. Hope it helps.

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.

WPF Wii Binding Properties: Infrared Data

This is an extension of my previous post, WPF Wiimote Library (Now With Project Files!), which has links to the WPF Wiimote Binding Library project files as well as some information vital to getting you started in connecting your application to the Wiimote.

And now for the IR properties:

The Wiimote can track up to 4 infrared (IR) LEDs at a time. If I were a programmer, I would have created an IR LED enum with the following properties as part of each IR LED. But since I’m not, these properties can be accessed with the following convention: IR[#][propertyName]. Each IR LED has the following properties:

IR[#]RawPosition

Type: Point

Summary: The IR camera has a X,Y resolution of 1024, 768. This property will give you the raw X,Y position that the Wiimote is tracking this LED at.

Binding Usage Example:

<Grid Canvas.Left=”{Binding Source={StaticResource WiiData}, Path=”IR1RawPosition.X, Mode=OneWay}
Canvas.Top=”{Binding Source={StaticResource WiiData}, Path=”IR1RawPosition.Y, Mode=OneWay}/>

Additional Info: This will work best if your Canvas is the exact dimensions of the Wiimote camera (1024, 768). These properties are automatically converted to take into account the IsMultiPoint setting (described in the Miscellaneous Properties (coming soon)).

IR[#]Position

Type: Point

Summary: This is the X,Y ratio of the position of your IR LED. The best way to use this is in a multi-binding with the width and height of your target Canvas. Fortunately for you, I’ve added a converter that will help with this. Simply add the following code in your resources:

<Wii:VariableCanvasPointConverter x:Key=”VariableCanvasConverter/>

And follow the binding example below.

Binding Usage Example:

<Grid>
   <Canvas.Left>
      <MultiBinding Converter=”{StaticResource VariableCanvasConverter}>
         <Binding Source=”{StaticResource WiiData}Path=”IR1Position.XMode=”OneWay/>
         <Binding ElementName=”MyCanvasPath=”ActualWidthMode=”Default/>
      </MultiBinding>
   </Canvas.Left>
   <Canvas.Top>
      <MultiBinding Converter=”{StaticResource VariableCanvasConverter}>
         <Binding Source=”{StaticResource WiiData}Path=”IR1Position.YMode=”OneWay/>
         <Binding ElementName=”MyCanvasPath=”ActualHeightMode=”Default/>
      </MultiBinding>
   </Canvas.Top>
</Grid>

Additional Info: These properties are automatically converted to take into account the IsMultiPoint setting (described in the Miscellaneous Properties (coming soon)).

IR[#]Found

Type: boolean

Summary: This is a property that is “true” if the Wiimote can see the target LED and “false” if it cannot.

Binding Usage Example:

<Grid IsEnabled=”{Binding Source={StaticResource WiiData}, Path=IR2Found, Mode=OneWay}/>

Additional Info:  This property is also available for the midpoint between the first and second infrared light (MidPointFound) and for the target point (TargetFound) which displays a calculated position of where the Wiimote is being pointed.

IR[#]Size

Type: double

Summary: The Wiimote naturally picks up the size of the LED it is tracking. To get larger sizes  (which translates into better reliability) use a small cluster of LEDs (three should do the trick) rather than a single one.

Binding Usage Example:

<Grid Width=”{Binding Source={StaticResource WiiData}, Path=IR1Size, Mode=OneWay}/>

IsIR[#]Visible

Type: bool

Summary: This item is meant for two way binding. If you want a way to programmatically choose whether or not to show the item that is bound to your IR interface, use this property. It is most useful when used in conjunction with the BoolToVisibility Converter, which can be used by placing this XAML in your resources:

<BooleanToVisibilityConverter x:Key=”boolToVis/>

Binding Usage Example:

<Grid Visibility=”{Binding Source={StaticResource WiiData}, Path=IsIR3Visible, Mode=OneWay, Converter={StaticResource boolToVis}/>

<CheckBox IsChecked=”{Binding Source={StaticResource WiiData}, Path=IsIR3Visible, Mode=TwoWay}/>

Additional Info:  This is a great property to attach to a checkbox (as seen above) to allow user control over which items are to be shown.

In addition to the infrared lights, the WPF Wii library is set up to display two calculated points as well:

  • A midpoint between IR1 and IR2
  • A target point (based on the midpoint) which indicates where the Wiimote is being pointed.

These two calculated points still have the position properties listed above (TargetRawPosition, MidPoint RawPosition, TargetPosition, MidPointPosition) as well as the visibility booleans (IsTargetVisible and IsMidPointVisible) and the “found” boolean properties (MidPointFound and IsTargetPossible).

Of course, you can also play around with the items in Intellisense is also a great way to discover all the available properties.

Using WPF Binding For A Huge Performance Boost

(I’m getting to the point in a roundabout way… you can skip directly to the point below if you want.)

When I started working on my WPF-Wii tutorials, my first Wii project was the initial version of the WPF-Wii Visualizer.

However, I quickly got tired of writing the code for handling events and transferring the data from the Wiimote library to my application. So (like any noble geek would do) I wrote even MORE code to solve the problem, not only for myself, but for generations to come.

I’ve spend the last week writing a Wii-To-WPF library that shovels the Wiimote properties into properties that use the INotifyPropertyChanged WPF interface. This will allow anyone to connect to the Wii through the WPF data binding. It’s super cool.

(A point of note, I posted an early version of this library. Ignore it. I’m putting up a much improved version in the next couple days.)

The Point

But I had no idea how moving from a basic data transference and event handling to the INotifyPropertyChanged interface would affect my performance.

Here are some screenshots of Perforator (a WPF performance monitoring application) monitoring my WPF-Wii Visualizer in its code-heavy iteration:

non_Data_Binding_Performance

I don’t know what all those numbers mean, but the one I’m interested in is the frame rate. As a designer, smoother motion is good… especially if I’m trying to design a multi-point application. A frame rate of 27 isn’t too bad, but this is the best I got. The frame rate usually hovered around 20, dipping as low as five.

Now… this is what I got when I was binding the data through the XAML (absolutely no code whatsoever):

Data_Binding_Performance

And this was the worst I got. My frame rate was always in the mid 60s and would spike up to 80. Take note that I’m not changing the interface at all. In fact, I’m running the binding version at a handicap (it’s tracking four infrared points instead of the original two).

Exact same XAML … except that the XAML properties are data bound from within the XAML and not assigned via the C# code.

So, lets take an account of the WPF INotifyPropertyChanged interface:

  • Allows DataBinding
  • Permits code-light or code-free interface design
  • Drastic improvements to performance

Use it!

Enough said.

Binding To Attached Properties (like Grid.Row, Grid.Column, Canvas.Left, Canvas.Top, blah.something, etc)

I recently spent a couple hours trying desperately to bind a TextBlock to the Canvas.Left and Canvas.Top properties for a project I’m working on. My binding looked like this:

 {Binding ElementName=MyElement, Path=Canvas.Left, Mode=Default}

Couldn’t do it. I tried bloody everything to get this thing to work, but it wouldn’t do it.

Then I found a post on binding to attached properties (I’ve removed the link since it now points to an attack site. Thank you, Graham), which is apparently what you call a property that is written as

<TextBlock Canvas.Left=”100
      Canvas.Top=”100
      Grid.Column=”1
      Grid.Row=”1
      Grid.ColumnSpan=”1
      Grid.RowSpan=”1“ />

Forgive the redundancy… I’m trying to write this post so that anyone who is having this problem can find the solution.

So the correct binding (the one that works for me, anyway) is:

{Binding (Canvas.Left), ElementName=MyElement}

It works.

Why? I have no idea.

Just passing it along.