The Tricks with TreeViewItem Expansion

| 1 comments

As I promised in MSDN WPF forum ages ago, I will post the tricks I learnt when playing with TreeView and TreeViewItems, so here comes the source. I have put slightly detailed explanation(those texts in green colour) on the demo Window, you can see it in the following screenshot:

If you look at the source code, you will find that I use the WpfApplication helper class to implement the DoEvents logic in WPF, I've posted how I do this ages ago, you can find the original article here.

TransitionControl

| 1 comments

Douglas Stockwell has blogged about how he implements transitions in WPF, actually, I really like the animation effects he creates, but I think his implementation is bit cumbersome, so I finally wind up creating my own transition by defining a custom control aka TransitionControl,  here comes the code for this control:

[TemplatePartAttribute(Name = "PART_ContentHost", Type = typeof(ContentPresenter))]
[TemplatePartAttribute(Name = "PART_StaleContentHost", Type = typeof(ContentPresenter))]
public class TransitionControl : ContentControl
{
    private static readonly DependencyPropertyKey IsContentChangedPropertyKey;
    public static readonly DependencyProperty StaleContentProperty;
    public static readonly DependencyProperty IsContentChangedProperty;
    public static readonly DependencyProperty TransitionEffectProperty;

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

        TransitionEffectProperty = DependencyProperty.Register(
           "TransitionEffect",
           typeof(TransitionEffects),
           typeof(TransitionControl),
           new FrameworkPropertyMetadata(TransitionEffects.None));

        StaleContentProperty = DependencyProperty.Register(
            "StaleContent",
            typeof(Object),
            typeof(TransitionControl),
            new FrameworkPropertyMetadata(null));

        ContentControl.ContentProperty.OverrideMetadata(
            typeof(TransitionControl),
            new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnContentChanged)));

        IsContentChangedPropertyKey = DependencyProperty.RegisterReadOnly(
           "IsContentChanged",
           typeof(Boolean),
           typeof(TransitionControl),
           new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));

        IsContentChangedProperty = IsContentChangedPropertyKey.DependencyProperty;
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public Boolean IsContentChanged
    {
        get { return (Boolean) GetValue(IsContentChangedProperty); }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public Object StaleContent
    {
        get { return base.GetValue(StaleContentProperty); }
        set { base.SetValue(StaleContentProperty, value); }
    }

    public TransitionEffects TransitionEffect
    {
        get { return (TransitionEffects) base.GetValue(TransitionEffectProperty); }
        set { base.SetValue(TransitionEffectProperty, value); }
    }

    private static void OnContentChanged(DependencyObject element, DependencyPropertyChangedEventArgs e)
    {
        TransitionControl tc = element as TransitionControl;
        tc.SetValue(IsContentChangedPropertyKey, BooleanBoxes.FalseBox);
        tc.StaleContent = e.OldValue;
        if (e.OldValue != null && e.NewValue != null)
        {
            if (!tc.IsLoaded)
            {
                tc.Loaded += delegate(Object sender, RoutedEventArgs args)
                {
                    tc.SetValue(IsContentChangedPropertyKey, BooleanBoxes.TrueBox);
                };
            }
            else
            {
                tc.SetValue(IsContentChangedPropertyKey, BooleanBoxes.TrueBox);
            }
        }
    }
}

The basic idea is to override the ContentProperty's default metadata by adding a PropertyChangedCallback to track the change of ContentProperty, inside the callback, I assign the old value of the ContentProperty to a custom DP I create (I've no idea of how to come up with a sexy name for this DP, so I just call it StaleContent), and I also toggle the value of IsContentChanged read-only DP to notify that the content of this control is changed, so this is the plumbing I create for my TransitionControl, and the tedious part is over, next question is how to apply transition effects, that's the job of control template, I define different control templates for different transition effects, take waving transition for example, the definition of the control template is as follows:

<!--Waving Transition Template-->
<
ControlTemplate TargetType="{x:Type cc:TransitionControl}" x:Key="WavingTemplate">
    <
Grid>
      <
ContentPresenter
         Name="PART_ContentHost"
         HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
         VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
        
ContentTemplate="{TemplateBinding ContentTemplate}"
         Content="{TemplateBinding Content}" />
      <
ContentPresenter
         Name="PART_StaleContentHost"
        
IsHitTestVisible="False"
         HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
        
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
         ContentTemplate="{TemplateBinding ContentTemplate}"
         Content="{TemplateBinding StaleContent}">
        <
ContentPresenter.OpacityMask>
          <
RadialGradientBrush GradientOrigin="0.5,0.5" Center="0.5,0.5" RadiusX="1" RadiusY="1">
            <
RadialGradientBrush.GradientStops>
              <
GradientStop Offset="0" Color="#00000000"/>
              <
GradientStop Offset="0" Color="#FF000000"/>
            </
RadialGradientBrush.GradientStops>
          </
RadialGradientBrush>
        </
ContentPresenter.OpacityMask>
      </
ContentPresenter>
    </
Grid>
    <
ControlTemplate.Triggers>
      <
Trigger Property="IsContentChanged" Value="True">
        <
Trigger.EnterActions>
          <
BeginStoryboard>
            <
Storyboard>
              <
DoubleAnimation
                
From="0"
                
To="1"
                
Duration="00:00:0.7"
                
Storyboard.TargetProperty="OpacityMask.(GradientBrush.GradientStops)[0].Offset"
                
Storyboard.TargetName="PART_StaleContentHost"/>
              <
DoubleAnimation
                
From="0"
                
To="1"
                
Duration="00:00:0.7"
                
Storyboard.TargetProperty="OpacityMask.(GradientBrush.GradientStops)[1].Offset"
                
Storyboard.TargetName="PART_StaleContentHost"/>
            </
Storyboard>
          </
BeginStoryboard>
        </
Trigger.EnterActions>
      </
Trigger>
    </
ControlTemplate.Triggers>
</
ControlTemplate>

You can see that I create two ContentPresenters, one for the old content(StaleContentProperty), and one for the new content(ContentProperty), the PART_StaleContentHost ContentPresenter overlapps the PART_ContentHost ContentPresenter, so to achieve transition effects here, I simply "erase" the PART_StaleContentHost to let the PART_ContentHost show through, so here I use Trigger the track the IsContentChanged property, and apply appropriate animation to the PART_StaleContentHost accordingly.

You can see my implementation of transitions is pretty streightforward, and much more clear, and a bit more performant than Douglas Stockwell's approach.

I've upload the control to Channel9's Sandbox, so you can download the source from here.

SplitButton

| 1 comments

Someone asks in MSDN WPF forum on how to implement custom dropdown menu, since recently I am tied up writing my own custom SplitButton control, and I've used some of the features MenuItem provides, I think my code can really demonstrate how to reuse MenuItems outside of Menu context, so I upload the source code to my web blog, here comes the screenshot of my custom SplitButton control:

You can download the source from here.

Get All The Attached DPs/DPs for An Object?

| 0 comments

Someone asks on MSDN forum on how to get a list of all dependency/attached properties of an Object, Douglas Stockwell responds to it with an awesome reflection code on how to get all the dependency/attached properties defined by built-in WPF library classes, but his solution doesn't solve the original poster's problem, after examining the issue for a bit, I come up with my solution:

using System;
using System.Windows;
using System.Collections.Generic;
using System.Windows.Markup;
using System.Windows.Markup.Primitives;

namespace Sheva.Windows.Markup
{
public static class
MarkupHelper
{
///
<summary>
///
Gets a list of locally applied DPs on an element.
///
</summary>
public static List<DependencyProperty> GetDependencyProperties(Object element)
{
List<DependencyProperty> properties = new List<DependencyProperty>();
MarkupObject markupObject = MarkupWriter.GetMarkupObjectFor(element);
if (markupObject != null)
{
foreach (MarkupProperty mp in markupObject.Properties)
{
if (mp.DependencyProperty != null)
{
properties.Add(mp.DependencyProperty);
}
}
}

return properties;
}

///
<summary>
///
Gets a list of locally applied attached DPs on an element.
///
</summary>
public static List<DependencyProperty> GetAttachedProperties(Object element)
{
List<DependencyProperty> attachedProperties = new List<DependencyProperty>();
MarkupObject markupObject = MarkupWriter.GetMarkupObjectFor(element);
if (markupObject != null)
{
foreach (MarkupProperty mp in markupObject.Properties)
{
if (mp.IsAttached)
{
attachedProperties.Add(mp.DependencyProperty);
}
}
}

return attachedProperties;
}
}
}



As an aside, I really want to give my special thanks to Douglas Stockwell, his nifty VSPaste plugin for Live Writer makes my blogging experience much easier.

Two Xaml Tricks

| 0 comments

1. Declare array object in xaml:

<Page 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">

   
<Grid>
       
<ListBox Width="200" Height="200" BorderBrush="Navy" BorderThickness="1">
           
<ListBox.ItemsSource>
               
<x:Array Type="{x:Type sys:String}">
                   
<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>
           
</ListBox.ItemsSource>
       
</ListBox>
   
</Grid>
</Page>

2. Declare inline code in Xaml:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
           xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml" 
           x:Class
="MyPage">
 
<x:Code>
   
<![CDATA[
      private void ButtonClickEventHandler(Object sender, RoutedEventArgs e)
      {
          MessageBox.Show("Hello Xaml!");
      }
   
]]>
 
</x:Code>
 
<Grid>
   
<Button Width="200" Height="60" Content="Click Me" Click="ButtonClickEventHandler"/>
 
</Grid>
</Page>

Note that, when specifying inline code in xaml, you also need to specify the x:Class and the Xaml should be compiled before getting execution, which means that XamlReader.Load() method cannot interpret the xaml which contains inline code.