Don And Chris Are Hilarious!

Don Box and Chris Anderson two of Microsoft genius software architects just shown on Channel9 video fumbling with their "terrible" singing voice, although they are not good singers, or should they be, but the lyrics of the song is really rhyming:

Vista, we shipped it,
Vista, we shipped it,
Vista, we shipped it,
Better late than not.

Vista, you'll love it,
Vista, you'll love it,
Vista, you'll love it,
It's the best we've got.

[Here] we've got Indigo,
and it will really glow,
when you've got avalon,
spicing up the show,

Sure there's no WinFS,
but we've got RSS,
and search and indexing will sort out the rest,

Use - er Ac - count Con - trol
UAT, and I'm no admin,
UAT, and you're no admin,
UAT, and she's no admin,
UAT, and he's no admin,

Which is whyyyyyyyyyyyy!

We're happy again.

I Have Some Fun With FormattedText

| 1 comments

Recently I've been trying the rich text sample code in the WPF documentation, the following custom control is something I come up with when playing with the FormattedText class:

using System;
using System.Xml;
using System.Text;

using System.Threading;
using System.Windows;
using System.Windows.Media;
using System.Windows.Markup;
using System.Windows.Shapes;
using System.Windows.Controls;
using System.Windows.Documents;

using Sheva.Internal;

namespace Sheva.Windows.Controls
{
    public class OutlinedText : FrameworkElement
    {
        private FormattedText formattedText;

        public static DependencyProperty FillProperty;
        public static DependencyProperty StrokeProperty;
        public static DependencyProperty StrokeThicknessProperty;
        public static DependencyProperty FontFamilyProperty;
        public static DependencyProperty FontSizeProperty;
        public static DependencyProperty FontStretchProperty;
        public static DependencyProperty FontStyleProperty;
        public static DependencyProperty FontWeightProperty;
        public static DependencyProperty RenderHighlightProperty;
        public static DependencyProperty TextProperty;
        public static DependencyProperty TextGeometryProperty;
        public static DependencyProperty TextHighlightGeometryProperty;
        private static DependencyPropertyKey TextGeometryPropertyKey;
        public static DependencyPropertyKey TextHighlightGeometryPropertyKey;

        static OutlinedText()
        {
            FillProperty = DependencyProperty.Register(
                "Fill",
                typeof(Brush),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender));

            StrokeProperty = DependencyProperty.Register(
                "Stroke",
                typeof(Brush),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender));

            StrokeThicknessProperty = DependencyProperty.Register(
                "StrokeThickness",
                typeof(Double),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(
                    0.0d,
                    FrameworkPropertyMetadataOptions.AffectsRender |
                    FrameworkPropertyMetadataOptions.AffectsMeasure));

            FontFamilyProperty = DependencyProperty.Register(
                "FontFamily",
                typeof(FontFamily),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(
                    SystemFonts.MessageFontFamily,
                    FrameworkPropertyMetadataOptions.AffectsRender |
                    FrameworkPropertyMetadataOptions.AffectsMeasure),
                    new ValidateValueCallback(IsValidFontFamily));

            FontStyleProperty = DependencyProperty.Register(
                "FontStyle",
                typeof(FontStyle),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(
                    SystemFonts.MessageFontStyle,
                    FrameworkPropertyMetadataOptions.AffectsRender |
                    FrameworkPropertyMetadataOptions.AffectsMeasure));

            FontWeightProperty = DependencyProperty.Register(
                "FontWeight",
                typeof(FontWeight),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(
                    SystemFonts.MessageFontWeight,
                    FrameworkPropertyMetadataOptions.AffectsRender |
                    FrameworkPropertyMetadataOptions.AffectsMeasure));

            FontStretchProperty = DependencyProperty.Register(
                "FontStretch",
                typeof(FontStretch),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(
                    FontStretches.Normal,
                    FrameworkPropertyMetadataOptions.AffectsRender |
                    FrameworkPropertyMetadataOptions.AffectsMeasure));

            FontSizeProperty = DependencyProperty.Register(
                "FontSize",
                typeof(Double),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(
                    SystemFonts.MessageFontSize,
                    FrameworkPropertyMetadataOptions.AffectsRender |
                    FrameworkPropertyMetadataOptions.AffectsMeasure));

            TextProperty = DependencyProperty.Register(
                "Text",
                typeof(String),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(
                    String.Empty,
                    FrameworkPropertyMetadataOptions.AffectsRender |
                    FrameworkPropertyMetadataOptions.AffectsMeasure));

            RenderHighlightProperty = DependencyProperty.Register(
                "RenderHighlight",
                typeof(Boolean),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(
                BooleanBoxes.FalseBox,
                FrameworkPropertyMetadataOptions.AffectsRender |
                FrameworkPropertyMetadataOptions.AffectsMeasure));

            TextGeometryPropertyKey = DependencyProperty.RegisterReadOnly(
                "TextGeometry",
                typeof(Geometry),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(null));
            TextGeometryProperty = TextGeometryPropertyKey.DependencyProperty;

            TextHighlightGeometryPropertyKey = DependencyProperty.RegisterReadOnly(
                "TextHighlightGeometry",
                typeof(Geometry),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(null));
            TextHighlightGeometryProperty = TextHighlightGeometryPropertyKey.DependencyProperty;
        }

        public Brush Fill
        {
            get { return (Brush)base.GetValue(FillProperty); }
            set { base.SetValue(FillProperty, value); }
        }

        public Brush Stroke
        {
            get { return (Brush)base.GetValue(StrokeProperty); }
            set { base.SetValue(StrokeProperty, value); }
        }

        public Double StrokeThickness
        {
            get { return (Double)base.GetValue(StrokeThicknessProperty); }
            set { base.SetValue(StrokeThicknessProperty, value); }
        }

        public FontFamily FontFamily
        {
            get { return (FontFamily)base.GetValue(FontFamilyProperty); }
            set { base.SetValue(FontFamilyProperty, value); }
        }

        public Double FontSize
        {
            get { return (Double)base.GetValue(FontSizeProperty); }
            set { base.SetValue(FontSizeProperty, value); }
        }

        public FontStyle FontStyle
        {
            get { return (FontStyle)base.GetValue(FontStyleProperty); }
            set { base.SetValue(FontStyleProperty, value); }
        }

        public FontStretch FontStretch
        {
            get { return (FontStretch)base.GetValue(FontStretchProperty); }
            set { base.SetValue(FontStretchProperty, value); }
        }

        public FontWeight FontWeight
        {
            get { return (FontWeight)base.GetValue(FontWeightProperty); }
            set { base.SetValue(FontWeightProperty, value); }
        }

        public String Text
        {
            get { return (String)base.GetValue(TextProperty); }
            set { base.SetValue(TextProperty, value); }
        }

        public Boolean RenderHighlight
        {
            get { return (Boolean)base.GetValue(RenderHighlightProperty); }
            set { base.SetValue(RenderHighlightProperty, BooleanBoxes.Box(value)); }
        }

        public Geometry TextGeometry
        {
            get { return (Geometry)base.GetValue(TextGeometryProperty); }
        }

        public Geometry TextHighlightGeometry
        {
            get { return (Geometry)base.GetValue(TextHighlightGeometryProperty); }
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            EnsureTextGeometry();
            Size geometrySize = GetNaturalSize();
            Double width = availableSize.Width;
            Double Height = availableSize.Height;
            if (Double.IsInfinity(width) && Double.IsInfinity(Height))
            {
                return geometrySize;
            }

            if (Double.IsInfinity(width))
            {
                width = geometrySize.Width;
            }

            if (Double.IsInfinity(Height))
            {
                Height = geometrySize.Height;
            }

            if (width > geometrySize.Width && Height > geometrySize.Height)
            {
                return geometrySize;
            }

            return new Size(width, Height);
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            AdjustTextGeometry(finalSize);
            return finalSize;
        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            if (RenderHighlight)
            {
                drawingContext.DrawGeometry(Fill, GetPen(), TextHighlightGeometry);
            }

            drawingContext.DrawGeometry(Fill, GetPen(), TextGeometry);
        }

        protected virtual void AdjustTextGeometry(Size arrangedSize)
        {
            Size geometrySize = GetNaturalSize();
            Double aspectRatio = geometrySize.Width / geometrySize.Height;
            Double scaleX = arrangedSize.Width / geometrySize.Width;
            Double scaleY = arrangedSize.Height / geometrySize.Height;
            ScaleTransform scaleTransform = new ScaleTransform(scaleX, scaleY, 0, 0);
            TextGeometry.Transform = scaleTransform;
            if (RenderHighlight)
            {
                TextHighlightGeometry.Transform = scaleTransform;
            }
        }

        protected virtual void EnsureTextGeometry()
        {
            FlowDirection flowDirection = Thread.CurrentThread.CurrentUICulture.TextInfo.IsRightToLeft ? FlowDirection.RightToLeft : FlowDirection.LeftToRight;
            formattedText = new FormattedText(
                Text,
                Thread.CurrentThread.CurrentUICulture,
                flowDirection,
                new Typeface(FontFamily, FontStyle, FontWeight, FontStretch, new FontFamily("Segeo UI")),
                FontSize,
                Brushes.Black);

            base.SetValue(TextGeometryPropertyKey, formattedText.BuildGeometry(new Point(0, 0)));
            if (RenderHighlight)
            {
                base.SetValue(TextHighlightGeometryPropertyKey, formattedText.BuildHighlightGeometry(new Point(0, 0)));
            }
        }

        private static Boolean IsValidFontFamily(Object value)
        {
            FontFamily fontFamily = value as FontFamily;
            return (fontFamily != null);
        }

        private Size GetNaturalSize()
        {
            Geometry definingGeometry = RenderHighlight ? TextHighlightGeometry : TextGeometry;
            Pen pen = this.GetPen();
            Rect rect = definingGeometry.GetRenderBounds(pen);
            return new Size(Math.Max(rect.Right, 0), Math.Max(rect.Bottom, 0));
        }

        private Pen GetPen()
        {
            return new Pen(this.Stroke, this.StrokeThickness);
        }
    }
}

 

And here is a little programme which demonstrates how to use this custom control:

<Window x:Class="OutlinedTextDemo.Window1"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:cc="clr-namespace:Sheva.Windows.Controls"
  
Title="OutlinedTextDemo"
    >
  <
DockPanel>
    <
CheckBox DockPanel.Dock="Top" Content="Render Highlight" Name="checkBox"/>
    <
cc:OutlinedText
    
Margin="5"
     
Text="OutlinedText"
     
FontFamily="Vineta BT"
     
FontSize="108"
     
FontWeight="Bold"
     
StrokeThickness="4"
      Fill="Gold"
      Stroke="Green"
      RenderHighlight="{Binding Path=IsChecked, ElementName=checkBox}"/>
  </
DockPanel>
</
Window>

  After compiling and running the above code, you should see something like the following:

Longest Method Name In .NET Framework

There is a method called GetTextEffectCharacterIndexFromTextSourceCharacterIndex under System.Windows.Media.TextFormatting.TextSource which counts 55 in character length, I guess this is the lengthiest method name in .NET Framework, Sounds like that the Framework Design Guidelines actually encourage this kind of naming practice:)

Another Way to Undo Implicit Styles

| 1 comments

Several months ago, Mike Hillberg blogged about how to undo implicit styles, recently I come across a situation in which I apply my custom styles at the app level, and then I want one portion of controls in my app to take on the custom styles, and the other portion of controls to pick up the default styles(aka theme styles), and when I look back at Mike's solution, I find that the technique he suggests doesn't solve my problem, because it's really cumbersome and impractical to set the Style property to null on every control which I want to be decorated using my custom styles. the more I think about this issue, the more I think it's something impossible to do with current bit of WPF until Ian Griffiths points me to the InheritanceBehavior property which is exposed by FrameworkElement class, unfortunately this property is marked as protected, so we need to subclass it:

public class SystemThemeConnector : ContentControl
{
    public SystemThemeConnector() : base()
    {
        this.InheritanceBehavior = InheritanceBehavior.SkipToThemeNext;
    }
}

You can see that SystemThemeConnector is derived from ContentControl, and in the default constructor, I simply set the value of InheritanceBehavior property to InheritanceBehavior.SkipToThemeNext which means that any control which is below the SystemThemeConnector in the logical tree will directly look up the theme styles, bypassing the styles we apply at any level in the logical tree. So if you want any control to be styled using system theme, you can simply put it inside the SystemThemeConnector, and you are done:)

I guess that Microsoft Expression Interative Designer probably holds the similar approach here, we can see that although Expression Team has created an amazing look and feel for this product, any control put inside the design surface will pick up the default look and feel, that's the best application of this property:)

.NET Framework 3.O Is Shipped

I've been to many CTPs and one question I always ask myself is when to RTM, as a WPF enthusiast, I know waiting is so hard to me, fortunately, I don't need to wait any more, MSFT just announces the official release of .NET Framework 3.0 RTM:

Download the quick installer

Readme for .NET Framework 3.0

Microsoft Visual Studio 2005 CTP Extensions for .NET Framework 3.0 (WCF & WPF)

Microsoft Windows SDK for .NET Framework 3.0

Microsoft Visual Studio 2005 Extensions for Windows WorkFlow Foundation

Weak Event Pattern In WPF

| 2 comments

Recently I just came across the weak event pattern in WPF, and when I learnt the tricks to use this pattern, I just want to pick up some code to demonstrate it, before I bombardment with some code, Let me first explain a bit about what is weak event pattern, and what kind of problem this pattern can solve?

Weak event pattern is used in the situation where the event soure object's lifetime is potentially independent of event listener objects. imagine you have a Button on the window, and you have a listener object called ButtonActionHelper which registers to the Button's Click event using classical += operator, when you are done with the actions you want to perform on the Button, you probably want to dispose the ButtonActionHelper object to save memory, and when you do so, you will think that the garbage collector will compact the memory space occupied by the ButtonActionHelper object when the GC finds that it's the appropiate time to do the dirty work, But in actuality, when the GC is triggered to collect the managed heap, It probably cannot collect ButtonActionHelper object, because the Click event source object aka Button object still hold a strong reference to it, why? the problem here is that event implementation in the .NET Framework is based on the CLR's delegate mechanism, you when use the += operator to register event handler to an event, you actually end up creating a new delegate presenting the event handler you attached to this event, and the newly created delegate will be added to the delegate chain, each delegate has two private fields, one is _target, and the other  _methodPtr. and the "culprit" bit aka _target arises from the horizon,  _target is a field which will hold a strong reference to the event listener on which the event handler is defined. that's why even if you've disposed the event listener, you still canot have the GC collect it, one workaround to this problem is to explicitly unregister the Click event, then the event listener can be cleaned up because no strong reference to it exists in the managed heap, but this requires you to determine the appropriate time and circumstance at which you don't want your event listeners anymore, sometimes, it's really hard to determine this, enter weak event pattern.

Weak event pattern solves the aforementioned problem by not having the delegate's _target field holding a strong reference to the event listener, the weak eventing system in WPF employs the same technique and concept which Greg Schechter blogged about ages ago in his awesome article "Simulating Weak Delegates in the CLR". By "decoupling" the event listener from the event source, the event listener's lifetime can be independent of the event source, this is especially important when the event listener holds up a lot of memory space, and unnecessarily keeping it in the managed heap any longer would increase the working set of your application. Okay, I think I just rant too much about the concept, let me start with some code to demonstrate this pattern.

If you want to implement the weak event pattern, there are two classes you should take care of, they are System.Windows.IWeakEventListener, and System.Windows.WeakEventManager. if you want your event listeners to participate in the WPF's weak eventing system, your event listeners should implement the IWeakEventListener interface, and simultaneously you should subclass WeakEventManager class to provide weak event mangement logic for the event you want to "expose" as a weak event, in my demo code, I create a custom WeakEventManager to "expose" Button's Click event as a weak event:

public class ButtonClickEventManager : WeakEventManager
{
    public static void AddListener(Button source, IWeakEventListener listener)
    {
        ButtonClickEventManager.CurrentManager.ProtectedAddListener(source, listener);
    }

    public static void RemoveListener(Button source, IWeakEventListener listener)
    {
        ButtonClickEventManager.CurrentManager.ProtectedRemoveListener(source, listener);
    }

    private void OnButtonClick(Object sender, RoutedEventArgs args)
    {
        base.DeliverEvent(sender, args);
    }

    protected override void StartListening(Object source)
    {
        Button button = (Button)source;
        button.Click += this.OnButtonClick;
    }

    protected override void StopListening(Object source)
    {
        Button button = (Button)source;
        button.Click -= this.OnButtonClick;
    }

    private static ButtonClickEventManager CurrentManager
    {
        get
        {
            Type managerType = typeof(ButtonClickEventManager);
            ButtonClickEventManager manager = (ButtonClickEventManager)WeakEventManager.GetCurrentManager(managerType);
            if (manager == null)
            {
                manager = new ButtonClickEventManager();
                WeakEventManager.SetCurrentManager(managerType, manager);
            }
            return manager;
        }
    }
}

In the above ButtonClickEventManager implementation, I override the StartListening() and StopListenting() methods to register and unregister Button's Click event respectively, in the OnButtonClick handler, I just simply call the DeliverEvent() method, the DeliverEvent() method will end up dispatching the ClickEvent to the weak event listeners if there are any, and I also define two static methods to enable to caller to add and remove weak event listener. so now we have an event manager which will mange and dispatch the ClickEvent, next we should create an IWeakEventListener listening to the ClickEvent:

public class ExpensiveObject : DispatcherObject, IWeakEventListener
{
    private Button sourceButton;
    private String id;
    public ExpensiveObject(Button sourceButton, Boolean usingWeakEvent, String id)
    {
        this.sourceButton = sourceButton;
        this.id = id;
        if (usingWeakEvent)
        {
            ButtonClickEventManager.AddListener(sourceButton, this);
        }
        else
        {
            sourceButton.Click += OnButtonClick;
        }
    }

    ~ExpensiveObject()
    {
        // Clean up expensive resources here.
        this.Dispatcher.BeginInvoke(DispatcherPriority.Send, new DispatcherOperationCallback(delegate
            {
                sourceButton.Content = String.Format("ExpansiveObject (Id:{0}) is cleaned up.", id);
                return null;
            }), null);

    }

    Boolean IWeakEventListener.ReceiveWeakEvent(Type managerType, Object sender, EventArgs e)
    {
        if (managerType == typeof(ButtonClickEventManager))
        {
            OnButtonClick(sender, (RoutedEventArgs)e);
            return true;
        }
        else
        {
            return false;
        }
    }

    private void OnButtonClick(Object sender, RoutedEventArgs e)
    {
        MessageBox.Show(String.Format("EventHandler called on ExpansiveObject (Id:{0})", id));
    }
}

I call this weak event listener an ExpensiveObject, because I just want to emphasize how classical CLR event will hold up the ExpansiveObject, resulting in memory leak, by implementing IWeakEventListener interface, we will not encounter such problem, presumably this ExpensiveObject will occupy non-trivial memory space, in the above code, I hook up the click event handler based on the boolean parameter specified in the constructor, later on, I will create two ExpensiveObject, one using weak event, and the other using classical event. I also implement the IWeakEventListener's ReceiveWeakEvent() using C#'s Explicit Interface Method Implementation feature, this method will be called by the WeakEventManger's DeliverEvent() method to notify the listener that the ClickEvent is fired, I also define a finalizer for this ExpensiveObject, inside this method, you just simply update the button's display to indicate that the ExpensiveObject is cleaned up.

Up until now, I've finish defining the ButtonClickEventManager, and the ExpensiveObject weak event listener, Let' me put those things together by creating an simple demo application:

<Window x:Class="WeakEventPatternDemo.Window1"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   Title="WeakEventPatternDemo" Height="300" Width="300"
    >
    <
StackPanel Margin="10">
      <
Button Name="button1" Content="Commit ExpensiveObject1" Margin="10"/>
      <
Button Name="button2" Content="Commit ExpensiveObject2" Margin="10"/>
      <
Button Name="fooButton" Content="Clean Up Expensive Objects" Margin="10"/>
    </
StackPanel>
</
Window>

public partial class Window1 : System.Windows.Window
{
    private ExpensiveObject object1, object2;
    public Window1()
    {
        InitializeComponent();

        //Associate the button1 with the ExpensiveObject 1 using weak event.
        object1 = new ExpensiveObject(button1, true, "1");

        //Associate the button2 with the ExpensiveObject 2 using classical event .
        object2 = new ExpensiveObject(button2, false, "2");

        fooButton.Click += fooButton_Click;
    }

    private void fooButton_Click(Object sender, RoutedEventArgs e)
    {
        // explicitly clean up the ExpensiveObjects to save memory.
        object1 = null;
        object2 = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}

In this simple demo application, I create three Buttons on the Window, and in the Window's constructor, I create two ExpensiveObjects, and associate them with the button1 and button2 using weak event and classical event mechanism respectively, in the fooButton's Click event handler, I simply nullify the two ExpensiveObjects I create previously, and explicitly force garbage collector to collect the memory instantaneously, I call GC.WaitForPendingFinalizers() to block the current thread until the finalizers for those ExpensiveObjects are get called.

When you run this application, and press the fooButton, you will find button1's display is updated to indicate that the ExpensiveObject 1 associated with it is cleaned up by the GC, but the button2's display is not updated, because the association between ExpensiveObject 2 and button2 is through classical event mechanism, and you can see that as long as button2 is not cleaned up, the button2 will prevent the ExpensiveObject 2 from garbage collected in a timely fashion.

Actually just as Ian Griffiths suggests, you can entirely avoid the problem inherent with the CLR's event mechanism withouting resorting to weak event pattern by carefully authoring your code , my next blog article will dedicate to this topic.

You can download the demo app project from here.

How To Create Alternate Background In WPF?

| 0 comments

Creating alternate background in WPF is a frequently asked question on MSDN WPF forum, and most answers to this question are borrowed from the three solutions posted several months ago by my compatriots in ATC Avalon Team(unfortunately, they decided to shut down their awesome blog), to some extent those solutions require you to define the ItemContainerStyleSelector or ItemTemplateSelector or subclass the exisiting control to override its PrepareContainerForItemOverride() protected method, and although those solutions work pretty well, all of them need you to explicitly refresh the items when the source collection changes, and what's more, for every specific ItemsControl, i.e ListBox, ComboBox, MenuItem, or ListView, you have to create the appropriate selectors or subclass them to get expected result, in this post, I'm going to show another approach to the problem and presumably my solution can be treated as a one all solution.

Actually implementing alternate background can be treated as an behavior extension to the existing controls, and the best practice to extend existing controls to add behaviors is to use attached property as much as possible, you may argue that we can add behaviors using inheritance, but can you respectively subclass the existing ItemsControls say ListBox, ComboBox, MenuItem, TreeView, and ListView etc to just merely add a simple behavior say alternate background? enter ItemsControlBehavior.

The following code is the implementation for the ItemsControlBehavior:

public class ItemsControlBehavior
{
public static readonly DependencyProperty AlternateItemContainerStyleProperty = DependencyProperty.RegisterAttached(
"AlternateItemContainerStyle",
typeof(Style),
typeof(ItemsControlBehavior),
new FrameworkPropertyMetadata(
null,
FrameworkPropertyMetadataOptions.Inherits,
new PropertyChangedCallback(OnAlternateItemContainerStyleChanged)));

public static void SetAlternateItemContainerStyle(DependencyObject element, Stlye value)
{
element.SetValue(AlternateItemContainerStyleProperty, value);
}

public static Style GetAlternateItemContainerStyle(DependencyObject element)
{
return (Style)element.GetValue(AlternateItemContainerStyleProperty);
}

private static void OnAlternateItemContainerStyleChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
ItemsControl control = sender as ItemsControl;
if (e.NewValue != null && control != null)
{
if (control.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
SetAlternateItemContainerStyle(control, (Style)e.NewValue);
}
else
{
control.ItemContainerGenerator.StatusChanged += delegate
{
if (control.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
SetAlternateItemContainerStyle(control, (Style)e.NewValue);
}
};
}
}
}

private static void SetAlternateItemContainerStyle(ItemsControl control, Style alternateStyle)
{
if (control.Items != null && control.Items.Count > 0)
{
for (Int32 i = 0; i < control.Items.Count; i++)
{
if (i % 2 != 0)
{
FrameworkElement container = control.ItemContainerGenerator.ContainerFromIndex(i) as FrameworkElement;
if (container != null) container.Style = alternateStyle;
}
}
}
}
}

You can see from the above code I just create an AlternateItemContainerStyle attached dependency property, in the property changed callback, I just apply the AlternateItemContainerStyle to the container which has an odd numbered index, then how to use the behavior, the following code demonstrates:

<Window x:Class="ItemsControlBehaviorDemo.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:cc="clr-namespace:ItemsControlBehaviorDemo"
Title="ItemsControlBehaviorDemo" SizeToContent="WidthAndHeight"
>
<
Window.Resources>
<
x:Array Type="{x:Type sys:String}" x:Key="data">
<
sys:String>Paviel Dedved</sys:String>
<
sys:String>Andriy Shevchenko</sys:String>
<
sys:String>Paolo Maldini</sys:String>
<
sys:String>Robert Baggio</sys:String>
<
sys:String>Alessandro Del Piero</sys:String>
</
x:Array>

<
Style x:Key="itemStyle">
<
Setter Property="Control.Background" Value="Beige"/>
</
Style>
<
Style x:Key="alternateItemStyle">
<
Setter Property="Control.Background" Value="LightBlue"/>
</
Style>
</
Window.Resources>
<
StackPanel cc:ItemsControlBehavior.AlternateItemContainerStyle="{StaticResource alternateItemStyle}" Orientation="Horizontal">
<
ListBox
ItemsSource="{StaticResource data}"
Margin="10"
ItemContainerStyle="{StaticResource itemStyle}"/>

<
Menu Margin="10" VerticalAlignment="Top">
<
MenuItem
Header="Player Name"
ItemsSource="{StaticResource data}"
ItemContainerStyle="{StaticResource itemStyle}"/>
</
Menu>

<
ComboBox
Height="20"
Width="120"
ItemsSource="{StaticResource data}"
Margin="10"
VerticalAlignment="Top"
ItemContainerStyle="{StaticResource itemStyle}"/>

<
ListView
ItemsSource="{StaticResource data}"
Margin="10"
ItemContainerStyle="{StaticResource itemStyle}">
<
ListView.View>
<
GridView>
<
GridViewColumn Header="Player Name"/>
</
GridView>
</
ListView.View>
</
ListView>
</
StackPanel>
</
Window>

You can see that the AlternateItemContainerStyle attached DP is inheritable, so I just specify this property on the parent element aka StackPanel, and this property value will propagate to its containing children elements.

Here is the screenshot for this demo app:

From the screenshot, you can see that the AlternateItemContainerStyle is applied successfully to the ListBox, MenuItem, ComboBox and ListView controls. another bonus of my solution here is that you don't need to manually fresh the containers when the underlying data source is changed.

The full source is uploaded, you can download it here.