Tuesday, 11 September 2007

Mix:UK 07: Building Rich Client Applications with Blend, WPF & Silverlight.

Presented by Jon Harris. May I start by noticing that all the laptops in the room are a MacBook Pro or another. And to answer the question of why I attend this session and not the .net development one, it's because I want to have a better insight at the workflow a designer goes through, whereas the .net part I can fairly easily teach myself on the net.

Jon used to work at Macromedia, and is a User Experience Evangelist. Concentrating on the workflow between blend, WPF and silverlight.

The video showed in the keynote being split in the jiggsaw puzzle was not 70 video files but only one split dynamically in 70 bits.

Build components, data binding, 3d stuff, are all things that we're going to do, and all this with no code.

Look at 3D first. Running the 3.5 beta framework because there are new improvements for 3d.

We start by seeing how we can change the look and feel of a button. Simple animation with a normal windows gray button. Copy a button and drag the copy. By default a guide helps dragging the button aligned with the previous one. Because the text is so small when you switch to a huge screen, the workspace zoom lets you resize the whole UI in the application. The whole panels of Blend can be put away when you need more space.

The first time you use Blend you can be overwhelmed by the amount of properties each component has. Using the filter list on top of the properties you can search for different tools. On the left you have objects, timelines and event management.

Click on a button, choose the button click, what do you do? The UI shows When button_Copy Click is raised, choose a new animation to create a new storyboard / timeline / animation [Edit: 3 names for one concept is a bit weird]. If you ever used Flash before, a new timeline was created, there's a red light which shows the timeline is animated.You turn it on and off by clicking on the red button.

Grab the body of the bird object, move in the timeline, move the bird and create a key frame. There's a faint dotted line showing the animation that is being created.

When clicking the button on the left, the animation moves the bird to the left, with the right button it animates to the right. If you click too fast though, suddently the animation jumps. That's because of the use of key frames.

Blend has this idea of hand-off timelines to do an animation from wherever an object is done to the keyframe. You remove the start key frame and only keep the end key frame. Now when you click the animation, even when clicking fast, the animation moves from wherever it is to the keyframe rather than from one key frame to another.

The buttons still look ugly though. A button is split between the code of how it works and how it looks. You can right click the button and edit a template for the button. A button is made up of a Grid, with a border, and a ContentPresenter that can contains anything. You can grab the border and delete it. It's not going to look better, it's going to look different. Use an ellipse, change the fill, change the stroke. In Blend you can click and drag on the stroke size and it adjusts in realtime. You can add an opacity mask to add a gradient.

The button looks have been changed. It's still a button. This confuses developers, giving the rollodex that is in fact a listbox. Only the style has been changed.

If you want to do a rollover for the button, you have options to trigger things based on when the mouse is over or not. Click Add a new timeline, select the new time on the timeline, and add a rotation transform. Add an option to repeat forever.

As soon as you put the mouse over, the whole circle keeps on circling around, even when you leave. Add a new action for deactivate, select the previous timeline and ask it to stop. Whenever the mouse leaves, the animation leaves.

Question: When you roll out does it reset the animation or stops where it was? If you choose stop as we did it goes back to the original position, if you click pause the animation will pause.

On the right you have a resource panel. You can modify all the styles that have been done. Choose an existing style, drag and drop it to the button, and suddenly the button changes styles but don't change any behavior. Same happens if you choose a 3d flower.

But as you saved the previous style, you can drag and drop it back on the button.

Another example used in Blend is for a bathroom with color wheels on the right. The control that shows the colors is a control. Let's see how it's done.

Create a new control in Blend. You have an empty application and put a yellow background. There's a whole list of controls you can use. Whenever you drag and drop it, it is just the default gray look. You create a new UserControl and set it to the correct size.

Add a Rectangle, round the corners. With vector tools, you do round corners and when you resize so do the corners. They stay to the same size in Blend. Add a fill color, and create a gradient in that rounded corners rectangle. Create a circle, as soon as it gets close to the edge it gets magnetted at a user-defined distance from the border, move it a bit more and it sticks on the border itself.

The original example had a few colors, so if you want to show a list of colors, you use a listbox. It's the default one which is a white box. Remove the background, remove the border, and keep the text black. How do we get data in the listbox? Go to the data window, and choose an xml data. The developer export data in an xml document, the designer uses this, and when the app gets released the developer re-hooks it to the database. Now that it opens you see the content of the xml. You can drag and drop the color list on the list box and shows the create Data Template window.

It lets you choose how you want the data being bound to your control. It now looks like a list of text, not quite right yet. We're going to do what we did with the button, and edit the template for the ListBox. There's two templates: the ControlTemplate controls what the control looks like, the grid, the border. You can choose the ItemTemplate to control how the item is bound. You can grab the content and start resizing it. You can draw a rectangle instead of having the text. Each of the properties have a small square next to it. Click on it and you have the databinding window. It hsows you the data you can bind to. Were going to databind the filling colour with the colour that was in the xml file.

Move back to the default area and draw a line on top of it, put some color with a gradient. Sets everything to white and add transparency. Copy the background and this highlight and combine them.

You can now go back to your application design view. You have to rebuild the project before the control you gave it can work. Build and your control appears, double click and the control gets added.

When you rotate it's done from the center. But if you drag the small circle in the middle of the object, you can drag and drop it to become the new rotation center point. Rotate and it now rotates from the bottom border.

Add an animation saying when a window is loaded, start a new animation, which creates a timeline, move later in the timeline, add an angle, go further, add yet another angle.

The fantastic thing is that because you used a ListBox, the keyboard behavior still works perfectly without adding any code and no work from the designer.

Question: Is there an ease-in and ease-out function? See that in a few minutes.

Introducing some layout controls in WPF and Blend. Showing a photo application that shows different group of pictures.

Change the size and the color scheme of the application. What do these things scale? Well Blend is written and designed with Blend and Visual Studio. When you move the mouse over the edges of a window, you can define slices. [EDIT: I assume he's talking about the Grid control].

You can copy and paste content between two different versions. When you move the element on the page, there's a very think line from the side of the object to the side of the application. The chain icon does the same thing to keep the object resized to the section defined earlier.

When you run the application, as you resize, the sides resize and move as expected. If you click on the lock symbol on the side of one of your slices, it preserves the size instead of resizing it, so that it's a fixed size.

You can add a Grid splitter. It lets you draw over that slice you defined. As you drag it on the surface it's default window gray style, You can restyle it. On the left of it draw a gradient. Run the application and drag and drop the splitter, and it resizes correctly.

The data has a parent / child relationship. The data is an xml file, master / details. As before, we drag a list box on the left, style it, and databind it to the gallery array from the xml file. When the Create Data Template window opens, you can remove all the content you don't want. Let's keep the gallery name and remove the pictures. Style the lsitbox to see the text and automatically it's bound and all the galleries defined in your xml file are presented.

Now the right hand side of the application is empty. We want to change the content based on the selection on the left. First, give the controls sensible names. Let's called the left hand part called menu. On the right hand side, we're going to select the DataContext and it opens the databinding. We choose to bind an element property. We choose the menu we created, and you can see all the properties you can bind to. We bind to the SelectedItem property. Now we want to decide whant we want to databind to, so we choose explicit datacontext, and choose the photo. Its only the path of the image path. You can redefine the binded value to Picture instead of text, and Blend will automatically show an Image. [EDIT: The demo didn't work for DataBinding, I still think setting the datacontext to menu.SelectedItem and binding to the object itself would've worked, or set the DataContext to the menu and choose the binding as the SelectedItem property. The presenter recovered admirably though].

You can create a VisualBrush from your application. Then create a Grid and sets its filling as the brush you just created. Do another one, turn it around and add some transparency. Whenever you change anything on the left side of the application, the right side shows the two grids and they change dynamically as you move your mouse over your main application.

You can reuse the same idea with a visual brush on a 3d sphere, and the effeect is the same.

Let's try something different, like a Video. Drag and drop it on the project, then add it to your window. Make it as a visual brush. In your 3d object, change the material to that new brush. When you test it, the video plays on the left, and the 3d object on the right is showing the video wrapped around.

Opening another sample. A couple of events are hooked up (beginning with ZAM3D) and the video plays on the screen and moves around.

Finally, to talk about designer / developer workflow. For silverlight, you need Blend 2, which look mostly the same, but there's a difference. When you create a new project, you now have the choice of Silverlight Javascript, Silverlight .net, WPF application or WPF control library.

Designers have done an application: 12 movies, all named differently.The developer has written the javascript to put them in 3d, because the designer doesn't know much about javascript. Start it, it runs in a browser. The 12 videos are playing at the same time. Went from flat to three dimensional, the designer did the look and feel, the developer did the 3d part.

Technorati Tags:

My take on the keynote

Overall I'm feeling a tiny bit let down. The demos were cool, but nothing very new or very exciting, except of course for adventureworks and the free silverlight hosting and streaming.

Some of the presentations failed to impress me much, with the video player for the government and the tax cut presentations being the least impressive. The video player suffered a bit of scrubbing, was it due to the presentation environment I couldn't tell, but definitely no wow factor there. The forms application was much more form processing oriented, something you'd have expected for a more business intelligence talk rather than a designer / developer conference.

But then again everybody knows I moan a lot. :)

Mix:UK 07: Keynote

As it happens my badge got lost and arrived late, so I missed the Conchango bits, so straight on with Windows Live Services.

New code to be released tomorrow on codeplex: AdventureWorks. Provides storage and streaming of your Silverlight content.

Windows Live login control was shiped a few weeks ago [EDIT: That's the login experience that is used on the new hotmail]. .

Upload of videos is queued on MSMQ, send to Expresion Video Encoder that transcode it to the correct media format, and streams the resulting Windows Media Video content anywhere the user wants. Audio works the same way.

Photos and friend lists can be imported through spaces.

All the code from QuickApps is on codeplex.

Demo built on QuickApps.

From Sentient. Gathering of running data: The TrackMe application. Looking at friends uploading content, getting alerts whenever new content is available. Social tol on a map like application. Sign in to the tool. By linking the identity between Windows Live and TrackMe gives access to the contact list. All is done through XML [EDIT: Mind blogging, XML in this day and age?].

Deo obviously uses Live Earth for map data. From a contact within that application, using a Messenger control you can initiate a live discussion. [EDIT: Live Messenger control shows the beta logo, maybe the next refresh of 8.5?]

Silverlight videos can be geo-tagged and viewed on the correct place.

They were able to bootstrap their help with the QuickApps demos.

ScottGu arrives. .net was either IIS / asp.net for te web, or desktop with Windows Forms, and Office, as well of course as WPF.Now there's a new category for RIA & media with Silverlight. But all these are using the .net environment, one set of tools, one set of APIs, and whichever language you want. You can leverage your developer skills and the designers can too.

When you integrate with a designer, you go through an initial design, the developer tries to integrate the changes and the CSS / HTML is then done by the designer again. But it doesn't always work very smoothly. Often the tools do't integrate very well, so you have to make compromises.

With Expression Studio the aim is to provide integrate tools that work on the same code, same file formats, which makes collaboration better: Visual Studio for developers, Expression studio for designers.

Blend, Web, Design and Media: the 4 components of the Expression family.

Where's the innovation? Web developer space. Later this year, asp.net gets a new version with .net 3.5 (orcas): AJAX support in the box, LINQ support, and ListView, pure CSS data output. Visual Studio 2008 also comes with new features: Javascript code completion, and debugging support. Design and source view can be shown in split view, as well as richer CSS editor. [EDIT: They finally replaced the IE engine by the... frontpage one! As it happens its better at providing CSS rendering than IE in a few scenarios].

To show this capability, Paul Curtis for EasyJet showing something for EasyJet Holidays.

For the easyet Holidays website, they use the AJAX Image control. Below there's details for the holiday, using AJAX. Everything was done with AJAX Toolkit with Whidbey.

To find your preferred hotel, uses AJAX to provide code completion.To book a holiday for Milan, click find a holiday: At the top you can refine the search by using ajax. The right side of the application *should* be using Virtual Earth. It's production code. But it doesn't work... "Its live code, so users have the exact same problems as we speak". It works. pinpoints hotels on a map. Click on a name, map zooms on it. Birds Eye view available. Star rating for hotels. Each hotel can be atted to a short list, just like a scratch pad. Using a cookie, it saves the list of hotels and can be chosen later.

[Screenshots available at http://blogs.msdn.com/angus_logan/, cool!]

WPF 3.5 updates: LINQ support, FireFox support. and VS Orcas brings Visual Studio designer (Cider), good workflow with Expression.

Silverlight is a cross-browser and cross-platform: IE, Safari, Firefox, Windows and MacOS from Microsoft, and MoonLight from Novell (and the mono team, kudos to Miguel and his team). Mobile devices will be supported in the future.

You can use either the .net programming model or the javascript model. It includes a slimmed down version of the real CLR and a reduced surface library only in 5 megs.

It's the way to build Media Experiences and new applications called RIA: Rich Internet Applications. Brings some richness from the desktop on the browser.

One of the core scenarios is Videos. It includes codecs VC-1, WMV and MP3, can be streamed from any web server, or use a free windows media server for optimized content. Supports HD high quality video from the browser. Much higher quality for a fraction of the cost.

Demo to build Silverlight 1.0 and Expression Studio.

Demo. Expression Media grabs all the files being used and tag them. Supports more than a 100 formats. Can step through photoshop layers from within the application. The quick search lets you filter.

The video plays in the thumbnail too. Take the video, use Expression Encoder. It's not a video editing package. It's a preparation tool to release it after using Final Cut. You can put markers that get stored in an XML file.

The tool can encode bits for the application and check the quality as you go.

The video is showing an iPhone...

You can generate the output with code and buttons. If you're not happy with the result, as it's a project, you can go back and edit it and for example change it with Expression Blend.

You can modify things in Expression Design and export it to Silverlight, and open it in Expression Blend. Through XAML both tools show the same thing. You can then export that content back into the player that was created earlier. You can move the video around in Expression Blend and does a curvy thing around the video and clips around the edge of the video. This is all still XAML.

Some animation can be added. With other packages, there's no timeline. In Blend you only get the timeline when you use it. You create a new timeline, can move it around the screen. Change the scale starting very small and transparent on the timeline. [EDIT: hates quick stuff done the demo way for a designer, not enough time spent on it!]

The nice thing is you can take the project and move it back into Media Encoder, and create it as a template file. The next time a video gets encoded, it will be wrapped in the template you created.

Demo shows a video split in 70 pieces in real time by silverlight.

Real application built for the government, Ben Stirling and Lee Atkinson from Twofour.

Need for more immersive expereince to stream their windows media files. Didn't want to have to re-encode everything. Video of Nelson Mandella and Gordon Brown [EDIT: typical government i suppose].

You can bookmark videos, move them around the screen, and click on a video to play it. Videos can be played across platforms, which is needed for governments. Windows Format SDK and Windows Media Services are leveraged.

From a developer point of view, Silverlight reuses your current skills. By using the same tools, the Live TV platform already built works out of the box.

[EDIT: As I find the demo fairly boring so far, I'm playing around with the USB key given by conchango. It contains the latest Blendables and a copy of the conchango web site, plus the conchango mix reader] 

All this is already shipping today. The programming model for silverlight can be programmed two ways. First, Javascript in existing pages. It's lightweight, easy to get started, and blends silverlight very well with AJAX. In 1.1, .net is included, across platforms. Can use any .net language. It includes a WPF based model like in the desktop.

Why use .net in the browser? You can use any language you want: VB, CSharp, Ruby, Pascal, or any of the 65 supproted languages. It provides a high performance runtime, up to a thousands times faster than javascript. You can use very rich UI controls, graphics and media. Silverlight 1.1 will have a whole suite of controls. You can program against the HTML DOM too. You can have very strong networking support all the way to TCP/IP. And Data can be integrated very easily.

dot net solutions, Dan Scott. Software + Services and Silverlight. Scrum master, definition of what is scrum.

Scrum project wall: One column has backlog, a sprint column, and a column for tasks (Scrum backlog?). They want to do a virtual version of the SCRUM wall. It's a represetation of the normal SCRUM wall.

Pop out a bit from the backlog into a sprint. Each backlog can have a complexity level. Several applications are synchronized across several browser sessions. There is no direct channels between browsers. Using software+services, the data is pushed back and forward. It is just like indirect push for emaisl on on Windows phones.

Accounting: Software for accountants, about 19,000. In the taxation ream, accountants are using the software to do the tax returns and send them over the internet. One of the big issues is integrating the tax returns in such a way that users can interact with them.

Normal form is a pd format. [EDIT: Can they really get me to be interested in tax returns? Oh dear!] Print the acrobat file through the XPS printer, and opens in Internet Explorer. It's all XAML (XPS is XML Paper Specification, based on XAML).

A WPF application lets you import an XPS form (the same one from the Acrobat document). From there metadata can be added to where the fields are. You select a field, give it a key, which data type it is, and when switching to viewing mode it is now an editable column.

You have to tweak the XAML as XPS is only a subset. The form is now usable in a Silverlight application. A Python script is attached to modifications in a field. The code can be changed dynamically from the phone, refresh the browser page, it downloads the script again which is executed against the DLR.

The use of silverlight gives a clean separation between the content of the form and the form itself. Because the script is only a text file, the script can be modified and end users could change the interaction of fields through a GUI. [EDIT: I heard that before...]

Silverlight lets reuse existing skills in the web world, and narrowing the gap between desktop and browser.

Today: Silverlight 1.0 Expression Studio, Encoder 1.0. Silverlight 1.1 Alpha is shipping too, preview of Siverlight 1.1 Tools for Visual Studio 2008.

Later this year, .net 3.5 is shipping with visual studio 2008.

Next year, Silverlight 1.1, Expression Studio 2, and visual studio 2..0 tool support for Silverlight 1.1.

Links for the community: http://www.asp.net for asp.net, http://www.windowsclient.net for any client technology like WPF, and Silverlight on http://www.silverlight.net

Technorati Tags:

Mix:UK 07 - Schedule

It's late and I should be in bed for tomorrow, but I realized the conference center is a whopping ten minutes walk from my home sweet home, so I have a bit of time. Thought I may as well let people know which sessions I'll be watching and reporting about. As you can tell, I'm mostly interested in WP, the DLR and silverlight 1.1.

Day 1

09:30 - 11:00 Mix:UK 07 Keynote
11:30 - 12:30 Designing immersive experiences with Expression Blend, WPF and Silverlight
13:15 - 14:15 Building Silverlight applications using .net Part 2 (to be confirmed)
14:30 - 15:30 Building next generation web applications using Windows Live Services
16:00 - 17:00 Developer Panel

But of course I may change my mind later. Off to bed now, see you all tomorrow. Let's hope wi-fi works alright!

Monday, 10 September 2007

Mix:UK 07 tomorrow

How thrilling! Hopefully I'll be able to blog about it. Wonder if I can get my camcorder with me...

Technorati Tags:

Monday, 3 September 2007

WPF Tips'n'Tricks #6: Preventing ScrollViewer from handling the mouse wheel

In the category of the pot talking to the pan, I present you ScrollViewer. It's the main control to implement scrolling in your templates, but it's also the one not respecting a very  fundamental rule of scrolling: if you're done scrolling, let your parent scroll!

Not only does ScrollViewer handles the mouse scrolling even when no more scrolling is needed, but it also does so when there's nothing to scroll, or worse when it is told not to scroll! Let's take an example XAML file. 

<Window x:Class="CaffeineIT.Blog.ScrollViewerExample.Window1"

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

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

   Title="Window1" Height="423" Width="596">

    <Grid>

        <ScrollViewer>

            <StackPanel>

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <ScrollViewer Name="NoScrollingScrollViewer">

                    <TextBlock>Content that doesn't need scrolling</TextBlock>

                </ScrollViewer>

                <ScrollViewer Height="235" Name="ScrollingNeededScrollViewer">

                    <StackPanel>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <ListView>

                            <TextBlock>Inside Thrid ListView</TextBlock>

                            <TextBlock>Inside Thrid ListView</TextBlock>

                            <TextBlock>Inside Thrid ListView</TextBlock>

                            <TextBlock>Inside Thrid ListView</TextBlock>

                            <TextBlock>Inside Thrid ListView</TextBlock>

                            <TextBlock>Inside Thrid ListView</TextBlock>

                        </ListView>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                        <TextBlock>Inside Second ScrollViewer</TextBlock>

                    </StackPanel>

                </ScrollViewer>

 

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <TextBlock>Inside First ScrollViewer</TextBlock>

                <TextBlock>Inside First ScrollViewer</TextBlock>

            </StackPanel>

        </ScrollViewer>

    </Grid>

</Window>

How can we change the ScrollViewer to behave more like it's supposed to? The most direct approach is to leverage the tunneling and bubbling events and use them against the buggy control.

The idea is that if the PreviewMouseWheel is handled, WPF will not generate the MouseWheel event, and in turn the ScrollViewer will not scroll.

Let's add a handler for the PreviewMouseWheel event on one of our ScrollViewers.

<ScrollViewer Height="235" Name="ScrollingNeededScrollViewer" PreviewMouseWheel="HandlePreviewMouseWheel">

 

        private void HandlePreviewMouseWheel(object sender, MouseWheelEventArgs e)

        {

            if (sender is ScrollViewer && !e.Handled)

            {

                e.Handled = true;

                var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);

                eventArg.RoutedEvent = UIElement.MouseWheelEvent;

                eventArg.Source = sender;

                var parent = ((Control)sender).Parent as UIElement;

                parent.RaiseEvent(eventArg);

            }

        }

This does exactly what we want. It marks the tunneling PreviewMouseWheel event as handled, so as to prevent WPF from raising the bubbling MouseWheel event, which is the one causing the actual scrolling. This is fine in case you don't want a ScrollViewer to scroll at all and let its parent do the scrolling, but what if you only want your ScrollViewer to scroll until it cannot anymore, and then let the parent scroll (this is the behavior in Internet Explorer)? Let's tweak the code a bit.

        private void HandlePreviewMouseWheel(object sender, MouseWheelEventArgs e)

        {

            var scrollControl = sender as ScrollViewer;

            if (!e.Handled && sender != null)

            {

 

                bool cancelScrolling = false;

 

                if ((e.Delta > 0 && scrollControl.VerticalOffset == 0)

                    || (e.Delta <= 0 && scrollControl.VerticalOffset >= scrollControl.ExtentHeight - scrollControl.ViewportHeight))

                {

                    e.Handled = true;

                    var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);

                    eventArg.RoutedEvent = UIElement.MouseWheelEvent;

                    eventArg.Source = sender;

                    var parent = ((Control)sender).Parent as UIElement;

                    parent.RaiseEvent(eventArg);

                }

            }

        }

Now, we check on every mouse wheel scroll if any content needs scrolling in the direction the wheel was scrolled. We check the VerticalOffset property, as it is 0 when you can't scroll up anymore and ExtentHeight-ViewportHeight when you can't scroll down anymore. If there's nothing to scroll, we cancel the event and re-raise it just like we did before.

That's all well so far, but what if I have another child ScrollViewer, like the ListView in our example? The ListView will not receive any notifications if the parent ScrollViewer is scrolled to the max in either direction, because we stop the PreviewMouseWheel before it can reach the ListView. We need to change the code a bit more and do the work the framework would've done.

        private void HandlePreviewMouseWheel(object sender, MouseWheelEventArgs e)

        {

            var scrollControl = sender as ScrollViewer;

            if (!e.Handled && sender != null && !_reentrantList.Contains(e))

            {

                var previewEventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)

                {

                    RoutedEvent = UIElement.PreviewMouseWheelEvent,

                    Source = sender

                };

                var originalSource = e.OriginalSource as UIElement;

                _reentrantList.Add(previewEventArg);

                originalSource.RaiseEvent(previewEventArg);

                _reentrantList.Remove(previewEventArg);

                // at this point if no one else handled the event in our children, we do our job

 

 

                if (!previewEventArg.Handled && ((e.Delta > 0 && scrollControl.VerticalOffset == 0)

                    || (e.Delta <= 0 && scrollControl.VerticalOffset >= scrollControl.ExtentHeight - scrollControl.ViewportHeight)))

                {

                    e.Handled = true;

                    var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);

                    eventArg.RoutedEvent = UIElement.MouseWheelEvent;

                    eventArg.Source = sender;

                    var parent = ((Control)sender).Parent as UIElement;

                    parent.RaiseEvent(eventArg);

                }

            }

        }

The main difference is that before we try to cancel the PreviewMouseWheel event by marking it Handled, we check if any child of the control would mark it Handled before us, which by WPF design would mean we shouldn't handle the event at all.

If you try this example now, you'll notice now that our ListView still prevents the scrolling to happen properly. That's because we only changed the behavior of the ScrollViewer we attached an event handler to, and not the one inside the ListView. Using the attached property initialization hack we used before, we can define an attached property that will do all the hookup work whenever attached to a ScrollViewer.

    public class ScrollViewerCorrector

    {

 

 

        public static bool GetFixScrolling(DependencyObject obj)

        {

            return (bool)obj.GetValue(FixScrollingProperty);

        }

 

        public static void SetFixScrolling(DependencyObject obj, bool value)

        {

            obj.SetValue(FixScrollingProperty, value);

        }

 

        public static readonly DependencyProperty FixScrollingProperty =

            DependencyProperty.RegisterAttached("FixScrolling", typeof(bool), typeof(ScrollViewerCorrector), new FrameworkPropertyMetadata(false,ScrollViewerCorrector.OnFixScrollingPropertyChanged));

 

        public static void OnFixScrollingPropertyChanged(object sender, DependencyPropertyChangedEventArgs e)

        {

            ScrollViewer viewer = sender as ScrollViewer;

            if (viewer == null)

                throw new ArgumentException("The dependency property can only be attached to a ScrollViewer", "sender");

 

            if ((bool)e.NewValue == true)

                viewer.PreviewMouseWheel += HandlePreviewMouseWheel;

            else if ((bool)e.NewValue == false)

                viewer.PreviewMouseWheel -= HandlePreviewMouseWheel;

        }

        private static List<MouseWheelEventArgs> _reentrantList = new List<MouseWheelEventArgs>();

        private static void HandlePreviewMouseWheel(object sender, MouseWheelEventArgs e)

        {

            var scrollControl = sender as ScrollViewer;

            if (!e.Handled && sender != null && !_reentrantList.Contains(e))

            {

                var previewEventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)

                {

                    RoutedEvent = UIElement.PreviewMouseWheelEvent,

                    Source = sender

                };

                var originalSource = e.OriginalSource as UIElement;

                _reentrantList.Add(previewEventArg);

                originalSource.RaiseEvent(previewEventArg);

                _reentrantList.Remove(previewEventArg);

                // at this point if no one else handled the event in our children, we do our job

 

 

                if (!previewEventArg.Handled && ((e.Delta > 0 && scrollControl.VerticalOffset == 0)

                    || (e.Delta <= 0 && scrollControl.VerticalOffset >= scrollControl.ExtentHeight - scrollControl.ViewportHeight)))

                {

                    e.Handled = true;

                    var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);

                    eventArg.RoutedEvent = UIElement.MouseWheelEvent;

                    eventArg.Source = sender;

                    var parent = (UIElement)((FrameworkElement)sender).Parent;

                    parent.RaiseEvent(eventArg);

                }

            }

        }

    }

And the only thing left to do is to change the template for ScrollViewer to always define the attached property by adding the Style to the resources on the Window, and pronto, all your ScrollViewers are now behaving properly.

<Window x:Class="CaffeineIT.Blog.ScrollViewerExample.Window1"

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

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

   Title="Window1" Height="423" Width="596" xmlns:my="clr-namespace:CaffeineIT.Blog.ScrollViewerExample">

    <Window.Resources>

        <Style TargetType="{x:Type ScrollViewer}">

            <Style.Setters>

                <Setter Property="my:ScrollViewerCorrector.FixScrolling" Value="True" />

            </Style.Setters>

        </Style>

    </Window.Resources>

As usual, you can download the ScrollViewerFixer.zip code and sample.

Friday, 31 August 2007

Google adSense

After having adSense for months (and a total earning of $0.18), the ads are finally showing up something connected with my blog:

  • DataGrid controls from Infragistics
  • The power of .net 3.0 from Xceed
  • Debugging Visual Studio from Microsoft
  • Automating your page composition from Dakota... Uh?

Three out of four is not bad, and it's three companies any .net 3 developer should visit quite often for the latest news, so the ads are in this instance quite useful.

As for automating my page... This is a blog?!? Oh well.

Technorati Tags: , ,

Thursday, 30 August 2007

Programming WPF 2nd Edition is out

Well through Chris Sell's blog, http://www.sellsbrothers.com/news/showTopic.aspx?ixTopic=2122, the new edition is shipping. I liked the previous version, only real reference at the time I started WPF, together with the Petzold.

So I just placed an order for it, and at the same time ordered Nathan's and the other Chris book, so I can have a go at reading them all.

I'll do a comparison of all of them and report here. It's been done before but now that I've been working professionally for what seems like years but is in fact only a year (between the RTM and beta 2), I think I may see things differently.

It will also be fun to compare the first and the 2nd edition of Programming WPF :)

Question is, should I order the 3D Petzold? We'll see after I'm done with the rest.

Anyone wants to commission me to write "Writing controls for WPF: Put some sparkle in your cider!"?

Technorati Tags: , , , ,

Wednesday, 22 August 2007

Funny comment of the day

While coding, found a snippet one of my predecessors left me:

//  Media Player gets its

// knickers in a twist.

Thought it was hilarious!

Friday, 17 August 2007

Using Visual Studio 2008 and Scrum for Team System

If you're using Scrum for Team System and Visual Studio 2008, you may notice that when connecting to a newly created Scrum Team Project, the Work Items node gets a desperate looking red cross.

The solution is to simply connect to TFS using the 2005 Team Explorer. From there, create a new Release. Restart Visual Studio 2008 and your Team Queries will finally show up!

Thursday, 16 August 2007

Xceed DataGrid for WPF v1.2

 We've used the WPF DataGrid successfully on the National Express project, and the guys at Xceed are very prompt to answer questions and very quick to fix bugs we encountered with the first version of their products.

I'm being told it's now top quality and probably the best DataGrid available. And it's just been updated! Check their News Headlines page for the new features.

Technorati Tags: , , , ,

Wednesday, 15 August 2007

Some TFS links

Not the freshest of links but useful if you use TFS.

TFS Bug Snapper v1.0 Released

and

www.scrumforteamsystem.com that provides similar functionality to the eScrum tool I talked about before.

Tuesday, 14 August 2007

Quick note for testers

A quick link to Anutthara's blog because it's an invaluable resource for any tester. I'll probably enforce reading it to any tester I have to work with.

Install windows components on a locked-down machine

More and more companies set their users as non admin, even with XP. The so-called locking down tries to protect the user and the network against anything only an administrator should do.

But there's also group policy that directs what gets shown in windows, which software gets activated, etc. In my case, the policy doesn't let you access the Add/Remove Windows Components section.

Being an administrator on the machine, I could go and change the registry to deny read permission to whichever account is being used for policies. That's a bit drastic and I wouldn't recommend it.

But thanks to the complexity and myriad of options available to group policy, sometimes you can get away with easier things.

To add or remove windows components, open PowerShell and type the following.

PS C:\WINDOWS> sysocmgr /i:$env:windir\inf\sysoc.inf

Or for people still using cmd

C:\WINDOWS> sysocmgr /i:%WINDIR%\inf\sysoc.inf

I'd rather we didn't have to play catch and seek with network administrators, but you have to do what you have to do to get the job done sometimes.

Technorati Tags: , ,

Thursday, 9 August 2007

Mix:UK 07 - I'll be there!

Well, it's now official, I'll be at Mix:Uk 07!

Hope to get chatting with many of you about all things WPF / Silverlight. So much cross-over and so many differences!

DirectShow filters from MediaElement

I previously pointed to Jeremiah blog about his and Leslie's amazing win32 integration work.

Little did I realize that the trick I read a while ago to build your own DirectShow filter for a MediaElement control was also his!

Respect.

Wednesday, 8 August 2007

On why you shouldn't really subclass through XAML

As I am reviewing some code at the moment, I have been looking for this blog entry from Rob for a while, and just found it again: Building a control which holds content: CustomControl vs. MarkupSubclassing vs. UserControl. Included in my specification references, but posting it so I can reuse it as a reference.

And the ever so useful Neil (when are you getting a blog back?) points me to an article by Kevin on the same subject: Don't subclass a Panel, unless you're making a Panel.

It always amazes me that people, after x years of OOD, still don't see a problem in using inheritance instead of combination / encapsulation.

Then again these guidelines postdate most of the uses I've seen so far so you can't really blame anyone.

Technorati Tags: , , ,

Tuesday, 7 August 2007

Documentation != Help, or why visual studio sucks

Visual Studio 2005 has the terrible habit of opening the full msdn library whenever you press F1, which in my case is mostly accidental. Not that I don't need help, but the F1 is a reflex I use when I don't understand the meaning of an option on the UI. I couldn't care less for msdn at that point.

Visual Studio 2008 seems to have a faster <cough> <cough> documentation explorer, but goes into what I'd consider to be pure vice: The little question mark box next to the close button is for bloody contextual help. Guess what, opening your big document explorer in my face when I'm already trying to understand what in the name of god you meant by allow checked-in items to be edited is not contextual. I loose my patience, and definitely loose my respect for whichever manager decided that after all, contextual help could be in the big documentation.

Can I have my tooltips back? Please?

Thursday, 2 August 2007

WPF Tips'n'Tricks #5: Receive notifications for dependency properties

Receiving notifications for dependency property changes on an existing object is a very common scenario. The way to do it properly is not very obvious. So much so that while reviewing some code, I found the following snippet.

// Believe it or not, this seems to be the only way to get change
// notifications for DPs unless you derive from the relevant
// class and override OnPropertyChanged.

PropertyDescriptor prop = TypeDescriptor.GetProperties(obj)["Prop"];
prop.AddValueChanged(obj, delegate { viewModel.RaisePropertyChanged("Prop"); });

There's a few issues with this code. The first one is that you reflect on the CLR property anchoring the dependency property, and not the dependency property itself. For example, the following code wouldn't work.

public Dock Dock { get { return DockPanel.GetDock(this); } }
public void TestDockProperty()
{
    PropertyDescriptor descriptor = TypeDescriptor.GetProperties(this)["Dock"];
    descriptor.AddValueChanged(this, delegate(object sender, EventArgs args) { MessageBox.Show("ValueChanged!"); });

    DockPanel.SetDock(this, Dock.Top);
}

The reason is that the PropertyDescriptor points to the CLR property, not to the dependency property.

The second issue is a problem of performance. TypeDescriptor.GetProperties reflects on every call and doesn't cache the result, so its cost is O(n). Here's the result of iterating several times on the code using TypeDescriptor.

  • 1,000 iterations : 00:00:00.2811402
  • 10,000 iterations : 00:00:01.4369388
  • 100,000 iterations : 00:00:14.1194856

So what is the correct way to do it? Say hi to DependencyTypeDescriptor. Here's the code rewritten to use DependencyProperties.

DependencyPropertyDescriptor prop = DependencyPropertyDescriptor.FromProperty(ParentObject.PropProperty, obj.GetType());
            prop.AddValueChanged(obj, delegate { viewModel.RaisePropertyChanged("Prop"); });

If you execute the code in the small benchmark application we used previously, the results are completely different.

  • 1,000 iterations : 00:00:00.00
  • 10,000 iterations : 00:00:00.00
  • 100,000 iterations : 00:00:00.0312378

As you can see in the source code, I simply use a DateTime before and after the call, and everything runs on the UI thread.

And the source is stored on box.net for those that want a peek. Be aware it's a visual Studio 2008 solution and project.

Download the source.