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.

Creating Image Reflection In WPF

| 0 comments

Today, I just come across Joseph Cooney's blog article on how to create an image reflection in WPF without having to hard-code the width and height, and he uses data binding and converter to do the trick, although this works fine, but still not as clean as we expect. Actually we can use VisualBrush.RelativeTransform instead of VisualBrush.Transform to flip the image, RelativeTransform allows us to specify relative values to the transform:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <
Viewbox>
    <
StackPanel Margin="10">
      <
Border BorderBrush="White" BorderThickness="8" Width="400" Height="300">
        <
Image Source="f:\My Documents\Whidbey\Xaml\bird.jpg" Name="myVisual" Stretch="Fill"/>
      </
Border>
      <
Border BorderBrush="White" BorderThickness="8" Width="400" Height="300">
        <
Border.RenderTransform>
          <
SkewTransform CenterX="0" CenterY="0" AngleX="-50" AngleY="0"/>
        </
Border.RenderTransform>
        <
Border.OpacityMask>
          <
LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
            <
LinearGradientBrush.GradientStops>
              <
GradientStop Offset="0" Color="#FF000000"/>
              <
GradientStop Offset="0.8" Color="#00000000"/>
            </
LinearGradientBrush.GradientStops>
          </
LinearGradientBrush>
        </
Border.OpacityMask>
        <
Border.Background>
          <
VisualBrush Visual="{Binding ElementName=myVisual}">
            <
VisualBrush.RelativeTransform>
              <
ScaleTransform ScaleX="1" ScaleY="-1" CenterX="0.5" CenterY="0.5"/>
            </
VisualBrush.RelativeTransform>
          </
VisualBrush>
        </
Border.Background>
      </
Border>
    </
StackPanel>
  </
Viewbox>
</
Page>

And here comes the screenshot of this Page:

Polygon Binding, Another Approach?

| 0 comments

Beatriz Costa has come up with a series of articles on his blog about different ways to data bind a Polygon's Points to a data source(Part I, Part II, Part III)? in this post, I just want to show another approach to it, and my approach will get rid of all the drawbacks Beatriz Costa mentioned in his blog.

Just as Beatriz Costa mentioned in his blog, Binding to Polygon's Points property is a special case, because Points property is of PointCollection type, if we use traditional binding technique here, when the data source is changed, the change will not be reflected on to the Polygon object, and Beatriz also mentioned that we can work around this by making the collection of points as a dependency property. But this has one drawback, when you do this, you are actually make a bad assumption that your data source will be used in WPF, how about if you plan to import your application to some other presentaion technologies say Windows Forms or ASP.NET, you have to retrofit much of your code to make it proper for other presentation technologies, but if we cannot introduce any dependency in the data layer, we can actually do it in the intermediate layer, enter PointCollectionView.

My basic idea is to define a dependency property on the PointCollectionView, this DP is responsible for bridging between generic data source and UI layer, the following code illustrates:

/// <summary>
///
PointCollectionView acts like a gluing layer between
/// PolygonItem and Polygon when used in Data binding scenario.
/// </summary>
public class PointCollectionView : DependencyObject
{
    public static readonly DependencyProperty PointsProperty;
    public static readonly DependencyPropertyKey PointsPropertyKey;

    static PointCollectionView()
    {
        PointsPropertyKey = DependencyProperty.RegisterReadOnly(
            "Points",
            typeof(PointCollection),
            typeof(PointCollectionView),
            new FrameworkPropertyMetadata(null));

        PointsProperty = PointsPropertyKey.DependencyProperty;
    }

    public PointCollectionView(PolygonItem item)
    {
        base.SetValue(PointsPropertyKey, new PointCollection(item.Points));

        INotifyCollectionChanged notifyCollectionChanged = item.Points as INotifyCollectionChanged;
        if (notifyCollectionChanged != null)
        {
            notifyCollectionChanged.CollectionChanged += this.OnCollectionChanged;
        }
    }

    public PointCollection Points
    {
        get { return (PointCollection)base.GetValue(PointsProperty); }
    }

    private void OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs e)
    {
        switch (e.Action)
        {
            case NotifyCollectionChangedAction.Add:
                for (Int32 i = 0; i < e.NewItems.Count; i++)
                {
                    this.Points.Insert(e.NewStartingIndex + i, (Point)e.NewItems[i]);
                }
                break;

            case NotifyCollectionChangedAction.Move:
                for (Int32 i = 0; i < e.NewItems.Count; i++)
                {
                    this.Points.RemoveAt(e.OldStartingIndex);
                    this.Points.Insert(e.NewStartingIndex + i, (Point)e.NewItems[i]);
                }
                break;

            case NotifyCollectionChangedAction.Remove:
                for (Int32 i = 0; i < e.OldItems.Count; i++)
                {
                    this.Points.RemoveAt(e.OldStartingIndex);
                }
                break;

            case NotifyCollectionChangedAction.Replace:
                for (Int32 i = 0; i < e.NewItems.Count; i++)
                {
                    this.Points[e.NewStartingIndex + i] = (Point)e.NewItems[i];
                }
                break;

            case NotifyCollectionChangedAction.Reset:
                this.Points.Clear();
                break;
        }
    }
}

You can see from the above code that the Points DP is actually a mirror to the PolygonItem.Points collection, it will listen to source collection's CollectionChanged event, and update itself accordingly, and for the usage of the PointCollectionView object, the following xaml illustrates:

<Window
  
x:Class="PolygonBinding.Window1"
   xmlns:cc="clr-namespace:PolygonBinding"
  
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   Title="PolygonBinding"
  
SizeToContent ="WidthAndHeight"
   
    >
  <
Window.Resources>
    <
cc:PolygonItem x:Key="polygonItem"/>
    <
ObjectDataProvider x:Key="src" ObjectType="{x:Type cc:PointCollectionView}">
      <
ObjectDataProvider.ConstructorParameters>
        <
StaticResource ResourceKey="polygonItem"/>
      </
ObjectDataProvider.ConstructorParameters>
    </
ObjectDataProvider>
    <
Style TargetType="{x:Type Polygon}">
      <
Setter Property="Points" Value="{Binding Path=Points, Source={StaticResource src}}"/>
    </
Style>
  </
Window.Resources>
    <
StackPanel>
      <
Button Click="ChangeSource" Margin="10" HorizontalAlignment="Center">Change data source</Button>
      <
Polygon Name="polygonElement" Width="500" Height="500" Margin="25" Fill="#CD5C5C"/>
    </
StackPanel>
</
Window>

The benefit of my approach here is that you can actually use the binding in a style, and in the ChangeSource event handler, you don't need to call the InvalidateMeasure() and InvalidateVisual() method to update the view of the UI,

As a side note, currently I cannot upload the whole project to my blog, because my friend have updated the communityserver.cn site without notifying me beforehand, you will find all the download links here are broken, I will fix those links when I get contact to my friend, if you want to run the source, you can first download Beatriz Costa's project, and replace those changing bits accordingly.

Edit: I just upload the vs project, you can download it from here.