More servicesWindows Live
HomeHotmailSpacesOneCare
 
MSN
Sign in
 
 
Spaces home  the WPF way...ProfileFriendsBlogMore Tools Explore the Spaces community

the WPF way...

the Approach, rather than the Solution
1/21/2008

Moved my blog to "Pixel in Gene"

Hello everyone!

           I have decided to move my blog to http://blog.pixelingene.com. This allows me greater control over making posts, adding images, attachments etc. Also I have the flexibility to play around with Page templates, CSS etc. Moving forward all posts will be made on "Pixel in Gene". I'll retain this blog as there are still links pointing here.

I am in the process of moving all my posts. Once done I'll have a complete copy of "the WPF Way...".

Please update your feeds by visiting the blog !!

(Pixel in Gene)

 

Thanks!

Pavan Podila

1/9/2008

Community input on Write - Speak - Collaborate

Over the past couple of months I have received fairly good response and feedback to some of the posts that I have made. I have also received some criticism that I don't share enough code.

Moving forward in 2008, I would like to change that, at least by making small steps. I would like to take the community's feedback and input on topics that are of supreme interest (eg. ElementFlow). Here is a short list I came up with:

 

Writing

  • Blog posts on interesting ways of applying the WPF concepts/ideas
  • Custom control development (topics of interest to community)
  • Advanced topics in custom control development (mixing 3D, Adorners, virtualization, etc)
  • Design patterns
  • Creative experiments
  • Write a book ??

I will definitely be publishing more source code!

 

Speaking

  • Start off with presentations at local User groups. I am in the North East area of US. I guess I could easily drive within a 3-4 hr radius. So that would include New Jersey, New York, Connecticut, Maryland, Delaware, etc. If you run a User Group or know of some, please do let me know.
  • Speak at conferences

 

Collaboration

  • This could include some exclusive work
  • Side projects

 

I am sure I can benefit from what the community thinks and it will also help me share / collaborate better. Looking forward to your views...

 

Technorati Tags: , ,
1/7/2008

Degrafa goes live

Although WPF development is my full-time activity, I also spend a considerable amount of time with Adobe Flex. Over the past couple of weeks I have been involved in an exciting Open Source project called Degrafa. Degrafa is a Declarative Graphics Framework for Flex that simplifies access to the Flash/Flex graphics API. People familiar with Flex know that creating simple shapes, paths requires Actionscript programming and cannot be done directly in MXML. This becomes very cumbersome especially when creating programmatic skins for Flex.

Degrafa aims to solve this by exposing the Flex graphics API in MXML. This opens up a whole new world of opportunities and creativity. If you think this is useful to you, make sure to drop by www.degrafa.com. We have recently announced a Degrafa Derby contest to award the most creative application built using the framework.

 

image

 

We have lot of interesting features planned for the coming releases. There is also a converter app that will be made available for converting the juicy Degrafa graphics to XAML. Umm, I wonder who is writing that ;-)

 

Technorati Tags: , , ,
1/3/2008

Smooth animations, at the Window level

If you have ever tried animating the Width / Height of a Window control, you would notice some jerkiness during the animation. This happens because the Window control is not really living entirely in the WPF sandbox. It is part WPF and part Native. To achieve a really smooth animation, you have GOT TO BE inside the WPF sandbox. But how do I do it?

 

The AnimationWindow

Creating animations directly on the Window is definitely not a desired solution. You have to first push the window contents (both the client-area and the non-client-area) into the WPF sandbox. You can do this by deriving from the GlassWindow control. You can create very customized ControlTemplates and replicate the look of a native window. You also have the flexibility of completely changing the look and feel of your application windows. This is a first step towards moving the Window content into the WPF sandbox.

However you still have the same problem when it comes to animating the window. That is because the GlassWindow is still using the native window wrapper and animating its Width / Height would still cause the jerkiness. What we need to do is push the entire window contents into a WPF control and then animate that control.

This is exactly what the AnimationWindow does. It derives from GlassWindow and overrides its OnApplyTemplate() method. Inside the override it caches a reference to the top level container that contains the complete window contents (client + non-client). When you trigger resizing animations on the Window, the actual animation happens on this container. Since you are completely inside the WPF sandbox, the animations are smooth and your customers happy ;-).

 

So what's the Trick ?

[1] Derive from GlassWindow and override OnApplyTemplate()

 

   [TemplatePart(Type = typeof(Grid), Name = "PART_WindowContent")]
    public class AnimationWindow : GlassWindow
    {
        private Grid _contentGrid;
        private Storyboard _resizeAnimator;

        public static readonly DependencyProperty NewSizeProperty = DependencyProperty.Register(
            "NewSize", typeof(Size), typeof(AnimationWindow), new PropertyMetadata(new Size()));

        public Size NewSize
        {
            get { return (Size)GetValue(NewSizeProperty); }
            set { SetValue(NewSizeProperty, value); }
        }


        static AnimationWindow()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(AnimationWindow), 
new FrameworkPropertyMetadata(typeof(AnimationWindow)));
        }

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

            // Get a reference to the ContentGrid
            _contentGrid = GetChildControl<Grid>("PART_WindowContent");
        }
}

Before starting the animation you need to set the NewSize DependencyProperty. The GetChildControl<T> is a protected method on GlassWindow. Inside OnApplyTemplate() I am caching the top-level container as _contentGrid.

[2] Expose a method to animate window

 

        public void ApplyResizeAnimation()
        {
            Size currentSize = new Size(Width, Height);

            // Temporarily resize the ContentGrid to avoid automatic layout flashes
            _contentGrid.SetValue(WidthProperty, currentSize.Width);
            _contentGrid.SetValue(HeightProperty, currentSize.Height);

            if (NewSize.Width > currentSize.Width)
            {
                Width = NewSize.Width;
            }
            if (NewSize.Height > currentSize.Height)
            {
                Height = NewSize.Height;
            }

            PlayAnimation(currentSize);
        }

        private void PlayAnimation(Size currentSize)
        {
            // Create Storyboard
            _resizeAnimator = PrepareStoryboard(currentSize);
            _resizeAnimator.CurrentStateInvalidated += ResizeAnimator_CurrentStateInvalidated;
            _resizeAnimator.Begin(_contentGrid, true);
        }

        void ResizeAnimator_CurrentStateInvalidated(object sender, EventArgs e)
        {
            Clock clock = sender as Clock;
            if (clock.CurrentState != ClockState.Active)
            {
                Width = NewSize.Width;
                Height = NewSize.Height;

                // Clear Width/Height settings and switch to automatic layout
                _contentGrid.ClearValue(WidthProperty);
                _contentGrid.ClearValue(HeightProperty);

                _resizeAnimator.CurrentStateInvalidated -= ResizeAnimator_CurrentStateInvalidated;
                _resizeAnimator.Remove(_contentGrid);
            }
        }

        private Storyboard PrepareStoryboard(Size size)
        {
            Storyboard board = new Storyboard();
            board.FillBehavior = FillBehavior.HoldEnd;

            // Width
            DoubleAnimation wAnim = new DoubleAnimation(size.Width, NewSize.Width, 
new Duration(TimeSpan.FromMilliseconds(500)));
            Storyboard.SetTargetProperty(wAnim, new PropertyPath("(0)", WidthProperty));

            // Height
            DoubleAnimation hAnim = new DoubleAnimation(size.Height, NewSize.Height, 
new Duration(TimeSpan.FromMilliseconds(500)));
            Storyboard.SetTargetProperty(hAnim, new PropertyPath("(0)", HeightProperty));

            board.Children.Add(wAnim);
            board.Children.Add(hAnim);
            return board;
        }

In ApplyResizeAnimation() I first explicitly set the Width + Height of the _contentGrid. I do this to avoid some automatic layout flashes. These would happen if my NewSize is greater than the current size. I then clear the explicit Width + Height settings when the animation gets over. Note that I am exploiting the precedence nature of the DependencyProperty.

 

[3] Create a ControlTemplate for the Window with transparency

    <Style x:Key="TestWindowStyle"
           TargetType="{x:Type Controls:AnimationWindow}">
        <Setter Property="AllowsTransparency"
                Value="True"/>
        <Setter Property="WindowStyle"
                Value="None"/>
        <Setter Property="ResizeMode"
                Value="CanResize"/>
        <Setter Property="Template"
                Value="{StaticResource TestWindow_Template}"/>
    </Style>

 

With all of these, your animations should run super smooth!

 

Getting Creative

Note that you can pull off some really exotic tricks with the AnimationWindow. Right now the resize animations are hard-coded. You can change that to expose a property on AnimationWindow to set custom Storyboards. If you club it with the TransitionContainer, you can even have Mac OSX style genie effects, right on the Desktop !!

 

Download EXE

 

Technorati Tags: ,,
12/15/2007

Controlling Z-Index of children in Custom controls

In WPF, the standard way to control Z-Index (programmatically) is to use Panel.SetZIndex(). However that works well only if you plan to use a list of children inside a Panel. What if you want to get the Z-Index functionality in your own custom controls ?

 

Override GetVisualChild()

The way to do that is to override the GetVisualChild() method of your custom control.

The GetVisualChild() requests for a Visual at a particular index. Generally you would return the child in the same order as in your internal visual collection. This gives you the effect of the Z-order, with the 0th child at the bottom-most position and the (n-1)th child at the top-most position. If you want to change this default ordering, it is possible to do that by returning a different child at the requested index.

Reversing Z-order

Say you want to reverse the child order. In that case you could write your method like so:

        protected override Visual GetVisualChild(int index)
        {
            if (index < 0 || index >= Children.Count)
            {
                throw new Exception("Invalid Child index: " + index);
            }

            int zIndex = GetZIndex(index);
            return Children[zIndex];
        }
        private int GetZIndex(int index)
        {
            return (Children.Count - 1) - index;
        }

Thus the trick with Z-ordering lies in the particular implementation of GetVisualChild().

 

Technorati Tags: , ,
12/10/2007

WPF In Finance Contest [Promo Post]

Got some great ideas? Want to do it in WPF and also earn some big bucks?

A "YES" means you should check out Lab49's WPF Innovation Contest.

image

 

Technorati Tags: , ,
11/19/2007

Improved DragDropManager - Source code

The DragDropManger has been a very handy class for me in couple of my projects. Since my last post I made some changes to the interfaces (IDragSourceAdvisor, IDropTargetAdvisor) and also to DragDropManager. There are no major changes except for a few method additions in the interfaces. These methods make it even more flexible.

Changes to IDragSourceAdvisor and IDropTargetAdvisor

Added method: UIElement GetTopContainer();

In my previous version I had assumed there would be only one MainWindow. Hence I was using Application.Current.MainWindow as my default top container. Of course this assumption worked well for some of my projects but broke when I had to do DnD across windows. This lead me to add the GetTopContainer() method, which is queried for the right container (AdornerDecorator).

How is this useful? Say for example you have a DragSource in one window and a DropTarget in another window. When an element in dragged onto the target window, the location of the feedback-UI is no longer relative to the MainWindow, instead it is relative to the target window. By querying the IDropTargetAdvisor for the top-container we can see the feedback-UI at the right place.

[Note] If you are using just the MainWindow, you can return Application.Current.MainWindow as your top container.

Added read-only property ApplyMouseOffset to IDropTargetAdvisor

When an element is moved from the source to the target, the initial click on the source-element may be at an offset inside its bounding-box. If the same offset needs to be applied to the feedback-UI on the target, the property ApplyMouseOffset can be set to True. In most cases you would set it as True. To accommodate a few outlier cases, this property had to be added.

 

That is all for the changes. I hope you find the code useful.  If you do anything cool with it, I would love to know and shower praise on you ;)

 

Download DragDrop.zip

 

Technorati Tags: , ,
11/6/2007

SlideDeckPanel - panel that does Card Deck layout

In one of my recent explorations in a project I had to implement a panel layout that displayed its items as cards that have been fanned out right->left.

 

image

 

Effectively the cards are laid out right-to-left, with the card on the right overlaying on the previous one. If the panel has enough space to accommodate all cards, there would be no overlap. As we keep increasing the number of cards, the amount of overlap increases appropriately.

 

image

 

Selections and Hovers

image

Selections and Hovers are an integral part of interacting with a list of items. There are some default selection and hover behaviors that are associated with this layout. However we wanted to make it customizable from the component point-of-view. Thus it is possible for an user of this panel to provide custom animations for selection and de-selection. On the same note, it is also possible to create custom adorners for hovers. The selection + hover logic has been abstracted enough to keep things very simple. The programmer only needs to provide Storyboards for animating the selection/deselections. As regards the adorners for hovers, the panel only needs a ControlTemplate (with standard names for placeholders).

Using these ideas it is also possible to change the selection and hover animations on the fly. The following video demonstrates these concepts. I use two kinds of selections (None, JumpSelection) and two kinds of hovers.

 

 

 

In a future post I'll go over some details about how you can implement such dynamic custom controls/panels.

 

Technorati Tags: , ,
10/10/2007

File organization tip for Custom Control authors

Custom controls can be fun to develop. Depending on the complexity of the control it would be a good practice to break it down into manageable pieces. While developing ElementFlow, I discovered such a technique which you may also find useful.

 

ElementFlow is a fairly complex custom control and there are many interacting pieces in it. Here is a quick listing:

  • 3D setup
  • Handling meshes
  • Animations
  • Viewstates (Coverflow, Timeline, etc)
  • User input handling (Keyboard, Mouse)

Putting all of this logic in the same file (ElementFlow.cs) made it a little cumbersome for me to navigate the file. Ofcourse I could use #region and #endregion to demarcate blocks of code but it was not that appealing. It works great to organize simpler elements like properties, fields, constructors, etc.

A Better way

What I was really looking for was a higher-level logical organization. The answer lied in using Partial Classes. It's a great language feature and should be exploited :) Most of us know that the Visual Designers in VS use partial classes to keep the code-behind separate from the "designer-vomit". It keeps our code-behind neat and readable. As control-authors we can leverage this feature to our benefit. To better understand, let me describe the way I used it.

 

As described earlier, ElementFlow has many logical pieces. Using partial classes, these pieces can be pushed to separate files, keeping the original ElementFlow.cs file pretty short. I decided to organize it into four files:

  1. ElementFlow.cs : contains public-facing properties, constructors and methods. This serves more like a definition of the control.
  2. ElementFlow.3d.cs : contains most of the Viewport3D, mesh-handling logic
  3. ElementFlow.animation.cs : contains creation of Storyboards, manipulating animations, viewstates etc
  4. ElementFlow.input.cs : contains logic to handle user-input

 

Keeping such a separation has given me a convenient way to see the different parts of my control. In future when I have to expand the functionality I could manipulate one of these files [or create a new partial class]. Adopting a convention for file-naming could be the next step when your organization is primarily into custom control development.

 

As a side-thought, this post could be corollary to my earlier article on control development.

 

Technorati Tags: , ,
8/30/2007

TransitionContainer: Easy transitions between views

Transitions, which is another word for animating between views, is a great way of keeping the user engaged as he interacts with your application. Most applications would contain a wide variety of views, where each view aids in interacting with a specific functionality of the application. When switching to a different view, a gradual animated change is far superior than an instant switch. It gives a context to the user telling him where he was earlier and where he is going to next.

TransitionContainer is my custom control that can do a wide variety of transitions, 2D as well as 3D. It contains a bunch of transitions, which come out of the box as well as a really simple framework for creating custom transitions. The transitions that come by default or also implemented using the same framework.

Before I go into details about the framework, lets have a look at a video of the transitions in action. Below you can see my favorite transitions: Genie, Cube and Slide... you can tell where I get my inspiration from ;)

 

 

 

TransitionContainer and the framework

The TransitionContainer is a host element that takes care of all the nitty-gritties of applying transitions between views. A quick snippet of XAML shows its usage:

    <Controls:TransitionContainer x:Name="_transContainer">
      <Image x:Name="_image1"
             Source="/Resources/img1.jpg"
             Stretch="Fill"/>
      <Image x:Name="_image2"
             Source="/Resources/img2.jpg"
             Stretch="Fill"/>
    </Controls:TransitionContainer>

Here the container contains a set of Images. In general it can contain any UIElement (aka views). TransitionContainer.Transition property points to an instance of a class that implements the transition. A transition between two views can be invoked by calling TransitionContainer.ApplyTransition(string, string). The two string parameters point to the names of the two children between which the transition is applied. In the example above, the transition between the images can be applied by calling:

            _transContainer.ApplyTransition("_image2", "_image1");

 

You can see that it is really easy to use the control. Just dump all your views inside the TransitionContainer, set a Transition and call ApplyTransition(). Easy.

 

Transitions

Transitions are pluggable classes and you can switch the transition to use at runtime (and at will ;)). Each transition derives from the abstract class Transition:

    public abstract class Transition
    {
        public abstract void Setup(Grid container, VisualBrush prevBrush, VisualBrush nextBrush);
        public abstract void PlayTransition(Grid container, TransitionContainer transContainer);
    }

ApplyTransition() internally calls the Setup() method first followed by PlayTransition(). In Setup() you can create all the elements that are needed during the transition. PlayTransition() is where the actual transition will be seen on screen. Here you can run Storyboards on the elements you created earlier. At the end of the transition, you are supposed to call TransitionContainer.FinishTransition(). This does some cleaning work, fires a TransitionCompleted event and then brings the new view for user interaction.

[I am in the process of refactoring the APIs so that only the TransitionContainer would need to be passed into the Transition. The first parameter (Grid container) is unnecessarily exposing an implementation detail]

I use the convention of suffixing all my transition classes with -Transition, as in GenieTransition. As a side note, the GenieTransition is actually very thin wrapper around my GenieAnimation class.

 

Technorati Tags: , , , ,
8/27/2007

The iPhone (-like) interface in WPF

Sometime back I had worked on an internal Instant Messaging client for our company. We were looking for some inspiration for our client interface and at about the same time the iPhone was introduced. After a lot of thought (which was like "few minutes"), we decided to mimic the iPhone interface for our client.

The enabling UI technology was Windows Presentation Foundation (WPF). With WPF we could rapidly build something that looks a lot like iPhone in a very short time. I was playing the dual role of a Designer + Developer and tools like Blend and Design greatly helped in skinning the app. Below you can see a bunch of screenshots and a short video of accepting a call.

 

Notification received. You can talk, IM or just ignore.

image

 

In an audio chat (call)

image

 

Contact list

image

 

Video of accepting a notification (via Talk)

 

How was it built?

  • Blend and Design were used for creating the skin of the app. The XAML UI was created in Blend and the graphics were developed in Design. I had made a post earlier about how the icons for the app were created in Design.
  • The GlassWindow control was used for creating the window chrome.
  • Although you cannot see in the screenshots above, the Drag 'n' Drop library was also used
  • I missed out using the ElementFlow, but that can be easily added. I only need to find a business case for that ;)

 

This example only goes to show how powerful WPF can be. With greater tool support from Blend + Design, lot can be achieved in a far lesser time. Now until I get my own iPhone, I will continue to use the WPF version ;)

 

Technorati Tags: , , ,
8/23/2007

ElementFlow is now a Panel !!!

The ElementFlow control was something I was working on a while back and I even posted about it here. The control originally derived from a FrameworkElement and had its own properties for enabling binding to a data-source, namely ElementsSource and ElementTemplate. These properties behave similar to the ItemsSource and ItemTemplate of ItemsControl.

One could argue that instead of deriving from FrameworkElement, I should derive from ItemsControl. That way I would get the Databinding support free of cost. But making ElementFlow an ItemsControl means that I could use any Panel as my ItemsPanel. This ofcourse is NOT true. ElementFlow is primarily meant to visualize items in 3D. This means I would be using Viewport3D and GeometryModels to represent my items. Using any other kind of panel doesn't really work well and is simply not correct. Also I think it violates the Liskov Substitution Principle (LSP).

 

However, ItemsControl does take care of data-binding by automatically generating the ContentPresenters for the items in the data-source. That idea led to a philosophical debate with myself, where I was arguing (with myself) that ElementFlow should really be handling layout of the items in 3D and should not worry about the data-source and deciphering DataTemplates. Its primary job is really to layout items in 3D.

The component in WPF that does pure layout is a Panel. Making ElementFlow a Panel was "definitely" the way to go.

 

Panel issues

Deriving directly from Panel required me to make couple different changes to the control and I also ran into a few issues along the way:

  • Previously I was handling the part where I would generate the ContentPresenters from ElementsSource and ElementTemplate. That all had to go away, since none of it is needed any more.
  • Next I had to hook into the stage where the Panel makes a change to its visual-children collection. This can be done by overriding

        protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)

I make a change to my Viewport3D (adding/removing models) within this method.

  • I also ran into an issue when setting ElementFlow as the ItemsPanel inside an ItemsControl. It had to do with the way ItemsPresenter uses the ItemsPanel property of ItemsControl. ItemsPresenter requires that the count of the visual children of the Panel should be 0 at the beginning (ie before populating the Panel). However inside my VisualChildrenCount override, I was always returning "1", indicating that I only have one visual child, which is my Viewport3D. Obviously I am not supposed to return "1" all the time. To circumvent this issue I call into the base-class to get me the VisualChildrenCount. If the count is zero, I return zero, else I return one.

 

Once past those issues, I had ElementFlow working in collaboration with ItemsControl. I can now get all my UI elements from the ItemsControl and not have to worry about data-binding and its related issues (children add/remove/update). This also saves me lot of development and maintenance time, as I rely more on the framework for things its really good at, namely DataBinding!

 

Note that ElementFlow also works independently of ItemsControl, just like any other Panel :)

 

Technorati Tags: , , , ,
8/17/2007

ItemSkimmingPanel - a panel that does more than just layout

Recently Apple released their next version of iLife, which has some cool enhancements to iPhoto and iMovie. One specific enhancement called "skimming" was interesting from my project's perspective. The idea is that when you scrub your mouse over an album, it skims through all the photos in that album. The same interaction applies when you scrub your mouse over a movie clip: it skims through all of its frames.

We had a similar requirement for viewing all the items inside a container. Skimming looked like a neat way of doing that. We had a couple of different ways of implementing this interaction but finally we decided on making this interaction as a Panel. The justification can be summarized in the bullets below:

  • Panel has a SetZIndex() API that is used to pop items to the front. This is useful to bring an item to the top of the stack.
  • Panels can be used in conjunction with ItemsControl to leverage data-binding. This can be done by setting the ItemsPanel property of ItemsControl

 

We added an extra feature to skimming, which we call "Item Context". When you are skimming through a bunch of items, you would also want to know where the item is positioned in relation to others. In other words you would want to know the context of the item relative to others. It is also very handy to quickly visualize your stack (aka container). Thus from a top level we have two different concepts in our ItemSkimmingPanel:

  1. It skims through all the items in the Panel when you scrub your mouse on it. Each "skimming" action brings the item to the top of the stack.
  2. When you start the skimming process, a context is also displayed to see the relative location of the item.

 

Both of these ideas can be seen in the video below. In the first half of the video you can see the skimming action without the context. The second half shows the context as you skim through the items. It will be clear how effective the skimming can be when the context is displayed.

 

 

 A quick note on internals

The ItemSkimmingPanel leverages the fact that a Panel can automatically handle the ZIndex of an item. We listen to standard mouse events (MouseDown, MouseUp, MouseMove) to achieve the effect of scrubbing. To prevent very rapid scrubs we make sure that the mouse moves a specific distance between each scrub. The context for skimming is shown using Adorners. The Adorner is positioned relative to the panel that is being scrubbed. Skinning of the context is supported via ControlTemplates. There are two Dependency properties on ItemSkimmingPanel used specifically for this purpose: ContextContainerTemplate and ContextItemTemplate. The names should be self-explanatory.

All of the skimming and context display logic is nicely encapsulated inside the ItemSkimmingPanel.

 

Technorati Tags: , , , , , ,
8/3/2007

Creating WPF based addins with System.AddIn

With Framework 3.5 we have a new namespace called System.AddIn which is useful for creating AddIn based application architectures. For an introduction to this namespace and its usage refer to:

CLR AddIn blog

Jason He's Paint.Net adventure with System.AddIn

 

WPF AddIns

When creating WPF AddIns one of the first things you would want is the ability to exchange some UI related classes across AppDomains. Doing so requires us to marshall these classes using a Contract (as per System.AddIn parlance). The WPF team has created a new namespace System.Windows.Presentation that provides this contract for exchanging WPF elements. Since the AddIn does not directly depend on the Contract, the exchange over the wire happens through an Adapter class. The Adapter will adapt the Contract to the View or the View to the Contract based on whether it is translating on Host side or the AddIn side.

System.Windows.Presentation contains a class called VisualAdapters that does exactly this job. When transmitting the Visual (System.Windows.Media.Visual) from the AddIn side, one needs to convert it to a Contract. The Contract interface defined for a Visual is called System.AddIn.Contract.INativeHandleContract defined in the System.AddIn.Contract assembly. VisualAdapters.ViewToContractAdapter is the method that does this conversion for us.

 

public static System.AddIn.Contract.INativeHandleContract ViewToContractAdapter(System.Windows.Media.Visual root)
    Member of System.AddIn.Pipeline.VisualAdapters

Similarly to translate from a Contract to a Visual we have the complementary method on VisualAdapters: ContractToViewAdapter. Note that this method is not exactly symmetrical with the previous one. It does not return a Visual, instead a FrameworkElement.

 

public static System.Windows.FrameworkElement ContractToViewAdapter(System.AddIn.Contract.INativeHandleContract nativeHandleContract)
    Member of System.AddIn.Pipeline.VisualAdapters

 

Passing Collections across AppDomains

Once you start building functionality into your addins you would soon hit the requirement to pass collections. Fortunately we already have contracts defined for them. System.AddIn.Contract defines the IListContract<T> which is a contract for passing IList. The adapter for this contract is defined in System.AddIn: CollectionAdapters. It contains a bunch of generic methods for translating between IList<T> and IListContract<T>.

I need more Contracts!

One of the AddIns I am trying to develop requires me to pass things like VisualBrush, Storyboard, etc. However there is no contract defined for these classes. Hopefully the WPF team will add it in the future or make some available via a CodePlex project ! I hope someone from the WPF team is reading this :)

Technorati tags: ,
7/2/2007

Making the Scrollbar work (with DragDropManager)

This post is a corollary to a set of posts I did on the DragDropManager component.

 

If you have been using the DragDropManager with a ListBox, you may have encountered an issue where you are not able to scroll using the ScrollBar. There are couple of reasons for this:

  1. I have setup Preview events on the UI control on which you attached the DragDropManager. This traps all the mouse events happening on the control.
  2. When you try to use the ScrollBar to scroll, the DnD manager comes in and checks if a Drag-gesture is being made. This traps the mouse events for the ScrollBar and hence it never sees it. This is the default behavior since the ScrollViewer is part of the ControlTemplate for the ListBox and hence considered part of the control.
  3. When the PreviewMouseLeftButtonDown event occurs, the dragged-element that is returned turns out to be the ListBox itself and not the ListBoxItem or ContentPresenter (in case of a Databound ListBox). Thus it is not clear from the dragged-element, whether the MouseDown event happened on the ScrollBar or the List item.

 

So what's the workaround?

The main reason the Scrollbar doesn't work is because of it being part of the ControlTemplate. Hence we need to take it out. We can then put the ListBox inside a ScrollViewer separately and get the desired scrolling behavior. Now the mouse preview events do not include the ScrollBar anymore.

 

A side note

I have improved the DragDropManager and made some changes to the IDragSourceAdvisor and IDropTargetAdvisor interfaces. Will make a post on that soon :)

Technorati tags: , , ,
View more entries