Relational lifted operators are confusing to me

| 3 comments

I am glad to know that I could access BlogSpot from my workplace (although not from my rental house), which means that I could continue writing something I feel interesting and worthy sharing.

Several months ago, we had a discussion internally about the operator lifting feature in C#, and how we could leverage upon this feature in our own library. Our library is mainly used for SI unit conversion, one requirement of this library is to support the basic arithmetic operations on those unit classes, for example, we have unit classes like Length, Time and Velocity, and we should support operation like follows:

Velocity = Length / Time, Length = Velocity * Time

Apparently, we could use the operator overloading feature in C# to enable the above scenarios, so that we could overload the division or multiplication operators as follows:

public static Length operator *(Velocity velocity, Time time)
{
    return velocity.Amount * time.Amount * Length.Meter;
}

This looks great and okay, but how about if the “velocity” or “time” parameter is null, then we end up having NullReferenceException thrown at us. The correct implementation should be something like the following:

public static Length operator *(Velocity velocity, Time time)
{
    if(velocity == null|| time == null)
    {
        return null;
    }

    return velocity.Amount * time.Amount * Length.Meter;
}

This just follows the rules when overloading operator which could be lifted as Eric Lippert illustrated in his blog post:

3) For the binary operators + - * / % & | ^ << >>, where the operator takes an S and a T and returns a U there is a corresponding lifted operator that takes an S? and a T? and returns a U?. It returns null if either argument is null.

I almost totally agree with the rules described by Eric Lippert except this one:

1) For every equality and relational operator that compares an S to a T and returns a bool there is a corresponding lifted operator that compares an S? to a T? and returns a bool. It returns false if either argument is null. (With the additional exception that if one argument to an equality operator is the null literal then the result may be determined by checking if the nullable term has a value.)

Consider this:

double? a = null;
double? b = 1;
Console.WriteLine(a > b);
Console.WriteLine(a == b);

Console.WriteLine(a < b);

This three comparison operation will all return false which doesn’t make any sense, since the three comparison should be mutually exclusive in logical sense.

Actually I recommend to return bool? when overloading those relational operators as follows:

public class Length
{
    public Length(double amount)
    {
        this.Amount = amount;
    }

    public double Amount
    {
        get;
        private set;
    }

    public static bool? operator >(Length a, Length b)
    {
        if(ReferenceEquals(a, null) || ReferenceEquals(b, null))
        {
            return null;
        }

        return a.Amount > b.Amount;
    }

    public static bool? operator <(Length a, Length b)
    {
        if(ReferenceEquals(a, null) || ReferenceEquals(b, null))
        {
            return null;
        }

        return a.Amount < b.Amount;
    }

    public static bool? operator ==(Length a, Length b)
    {
        if(ReferenceEquals(a, null) || ReferenceEquals(b, null))
        {
            return null;
        }

        return a.Amount == b.Amount;
    }


    public static bool? operator !=(Length a, Length b)
    {
        if (ReferenceEquals(a, null) || ReferenceEquals(b, null))
        {
            return null;
        }

        return a.Amount != b.Amount;
    }
}

With this Length class at hand, then three comparisons shown previously will all return correct result (aka null):

Length a = null;
var b = new Length(1);
Console.WriteLine(a > b);
Console.WriteLine(a == b);

Console.WriteLine(a < b);

I’ve no idea why nullable type in C# doesn’t follow this, but they do have their own explanation which is even more confusing to me:

This seems like a very natural thing for a C# user to want to write. But if equality is three-valued, comparing anything to null always returns a null value (ie null isn't equal to anything), and therefore such a comparison can never succeed. Instead, the user would have to write:

if (!p.HasValue)

or something similar. We decided that the value of having a model that was consistent with the way users were used to dealing with reference null was pretty high, and therefore decided to make the relational operators return bool.

I personally think writing line like if(!p.HasValue) is okay for me, because otherwise I need to deal with other confusing scenario like the one I’ve shown above with three comparisons on double?.

Streaming Media Content Over WCF RESTful Service

| 1 comments

WCF RESTful service API enables you to serve POX type of content over the http transport, and its default content-type header is application/xml if you use DataContractSerializer and application/json if you use DataContractJsonSerializer. If you need to serve up other contents for instance video/audio content, you need to explicitly control the content-type header, this could be achieved again by writing custom message formatter as demonstrated in the previous post, here is the code:

public class ContentTypeMessageFormatter : IDispatchMessageFormatter
{
    private IDispatchMessageFormatter formatter;
    private String contentType;
    public ContentTypeMessageFormatter(IDispatchMessageFormatter formatter, String contentType)
    {
        this.formatter = formatter;
        this.contentType = contentType;
    }

    public void DeserializeRequest(Message message, object[] parameters)
    {
        formatter.DeserializeRequest(message, parameters);
    }

    public Message SerializeReply(MessageVersion messageVersion, Object[] parameters, Object result)
    {
        if (!String.IsNullOrEmpty(contentType))
        {
            WebOperationContext.Current.OutgoingResponse.ContentType = contentType;
        }
        return formatter.SerializeReply(messageVersion, parameters, result);
    }
}

public class ContentTypeAttribute : Attribute, IOperationBehavior
{
    public ContentTypeAttribute(String contentType)
    {
        this.ContentType = contentType;
    }

    public String ContentType
    {
        get;
        set;
    }

    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
    {
    }

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
    {
        dispatchOperation.Formatter = new ContentTypeMessageFormatter(dispatchOperation.Formatter, ContentType);
    }

    public void Validate(OperationDescription operationDescription)
    {
    }
}

Then you could directly specify the ContentTypeAttribute at the service operation level, the following service could stream WMV video content over http by turning on the streamed transfer mode of WCF:

[ServiceContract]
public interface IMediaService
{
    [OperationContract]
    [ContentType("audio/x-ms-wmv")]
    [WebGet(UriTemplate = "media/{name}")]
    Stream GetMedia(String name);
}

[AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirementsMode.Required)]
public class MediaService : IMediaService
{
    public Stream GetMedia(String name)
    {
        var dir = HttpContext.Current.Server.MapPath("~");
        var file = String.Format("{0}.wmv", name);
        var filePath = Path.Combine(dir, file);
        return File.OpenRead(filePath);
    }
}

You turn on streaming in WCF, you need to configure the service as follows:

<system.serviceModel>
  <
serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
  <
services>
    <
service
     behaviorConfiguration="serviceBehavior"
     name="CustomContentTypeInRESTDemo.MediaService">
      <
endpoint
       behaviorConfiguration="RestBehaviorConfig"
       binding="webHttpBinding"
       bindingConfiguration="HttpStreaming"
       contract="CustomContentTypeInRESTDemo.IMediaService"/>
    </
service>
  </
services>
  <
bindings>
    <
webHttpBinding>
      <
binding name="HttpStreaming" maxReceivedMessageSize="67108864" transferMode="Streamed"/>
    </
webHttpBinding>
  </
bindings>
  <
behaviors>
    <
endpointBehaviors>
      <
behavior name="RestBehaviorConfig">
        <
webHttp/>
      </
behavior>
    </
endpointBehaviors>
  </
behaviors>
</
system.serviceModel>

Streaming audio/video content using RESTful service could be pretty useful, in particular if you need to use WPF’s MediaElement to playback content provided by your service, since MediaElement only allows you to specify a Uri of the media file, the DirectShow has build-in source filter to feed video/audio bits from HTTP transport or local file system, but doesn’t provide a built-in source filter to read media bits from arbitrary stream.

In WPF, you could directly have MediaElement’s Source property pointing to the templated REST Uri:

<MediaElement Source="http://localhost:8080/MediaService.svc/media/testVideo"/>

Actually, if you need VCR type of control over the streamed media content, then you need native protocol level support such as RTSP. Windows Media Services is Microsoft’s server implementation of RTSP protocol, and is available in Windows Server 2003 and Windows Server 2008. This link illustrates how to configure WMS in Windows Server 2003.

Include XML Declaration in WCF RESTful Service Response

| 10 comments

When using WCF to write RESTful web services, the default XML response stream doesn’t contain the XML Declaration or XML DOCTYPE. the default XML serialization mechanism used by WCF’s data contract serializer does support emitting XML declaration, but it isn’t turned out by default. You could try using XmlSerializer instead which does support emitting XML declaration,  but if you need stick to data contract serializer, you could try hooking into the WCF serialization process by writing a custom message formatter, the following code contains the full implementation of this approach:

public class XmlDeclarationMessage : Message
{
    private Message message;
    public XmlDeclarationMessage(Message message)
    {
        this.message = message;
    }

    public override MessageHeaders Headers
    {
        get { return message.Headers; }
    }

    protected override void OnWriteBodyContents(System.Xml.XmlDictionaryWriter writer)
    {
        // WCF XML serialization doesn't support emitting XML DOCTYPE, you need to roll up your own here.
        writer.WriteStartDocument();
        message.WriteBodyContents(writer);
    }


    public override MessageProperties Properties
    {
        get { return message.Properties; }
    }

    public override MessageVersion Version
    {
        get { return message.Version; }
    }
}

public class XmlDeclarationMessageFormatter : IDispatchMessageFormatter
{
    private IDispatchMessageFormatter formatter;
    public XmlDeclarationMessageFormatter(IDispatchMessageFormatter formatter)
    {
        this.formatter = formatter;
    }

    public void DeserializeRequest(Message message, object[] parameters)
    {
        formatter.DeserializeRequest(message, parameters);
    }

    public Message SerializeReply(MessageVersion messageVersion, Object[] parameters, Object result)
    {
        var message = formatter.SerializeReply(messageVersion, parameters, result);
        return new XmlDeclarationMessage(message);
    }
}

public class IncludeXmlDeclarationAttribute : Attribute, IOperationBehavior
{
    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
    {
    }

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
    {
        dispatchOperation.Formatter = new XmlDeclarationMessageFormatter(dispatchOperation.Formatter);
    }

    public void Validate(OperationDescription operationDescription)
    {
    }
}

Then you could specify the IncludeXmlDeclarationAttribute at service operation level, if you need to enable this at service wide level, you could try implementing the IServiceBehavior interface instead.

[ServiceContract]
public interface IDemoService
{
    [OperationContract]
    [IncludeXmlDeclaration]
    [WebGet(UriTemplate = "customers/{name}/")]
    Customer GetCustomer(String name);
}

Display HwndHost Inside ToolTip/ContextMenu

| 6 comments

This post is a further elaboration to my reply to this MSDN WPF forum thread.

Before digging into the details of how to solve this issue, let's start with some background information on ToolTip/ContextMenu and HwndHost.

In WPF, ToolTip/ContextMenu is hosted inside a Popup, Popup is essentially a hwnd with WS_POPUP window style. By default, the Popup created by ToolTip and ContextMenu services will have AllowsTransparency property set to true to enable layered windows on it. WPF uses application managed layered windows which is incompatible with the win32/GDI rendering model, which means that application managed layered window doesn't support child hwnd with WS_CHILD window style. So you want to display hwnd based content (through HwndHost) inside the a ToolTip/ContextMenu, you need to disable layered windows.

The caveat here is that the implementation of ToolTip and ContextMenu has hardcoded the AllowsTransparency property value when creating Popup, and it seems that this will not change at least in the next version of WPF. I think it might be common scenario to display content coming from other pre-WPF presentation technologies such as win32 controls, MFC/ActiveX controls or Windows Forms controls etc simply because you already have a control at hand,and it has already implemented all the functionalities you want. There are some known issues with hwnd interop in particular the airspace issue but as long as you don't overlap the hwnd content with WPF content, things should work properly at least visually.

The solution I posted in that WPF forum thread requires subclassing from ToolTip, and override the OnTemplateChanged protected method to wire up the code to set the Popup.AllowsTransparency at the right time before the internal implementation of ToolTip creates it for you which will be too late to set that property(setting Popup.AllowsTransparency to false after the ToolTip/ContextMenu is displayed doesn't take effect immediately, you need to hide the popup and then display it again to get this work). The ideal solution is that I could wire up those logic through the well-known WPF pattern - attached behavior pattern. So I could simply write something like the following, and things start to work for both ToolTip and ContextMenu without separate subclassing:

<StackPanel>
  <
Button Content="ContextMenu Demo">
    <
Button.ContextMenu>
      <
ContextMenu cc:PopupBehavior.AllowsTransparency="False">
        <
WebBrowser Width="300" Height="200" Source="http://www.live.com" />
      </
ContextMenu>
    </
Button.ContextMenu>
  </
Button>
  <
Button Content="ToolTip Demo">
    <
Button.ToolTip>
      <
ToolTip cc:PopupBehavior.AllowsTransparency="False">
        <
WebBrowser Width="300" Height="200" Source="http://www.live.com" />
      </
ToolTip>
    </
Button.ToolTip>
  </
Button>
</
StackPanel>

Here is the complete implementation of PopupBehavior:

using System;
using System.Security;
using System.ComponentModel;

using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;

namespace Sheva.Windows.Controls
{
    /// <summary>
    ///
Extends Popup control with added behaviors.
  
/// </summary>
  
public class PopupBehavior
  
{
        public static readonly DependencyProperty AllowsTransparencyProperty =
            DependencyProperty.RegisterAttached(
            "AllowsTransparency",
            typeof(Boolean),
            typeof(PopupBehavior),
            new FrameworkPropertyMetadata(
                true,
                new PropertyChangedCallback(OnAllowsTransparencyChanged),
                new CoerceValueCallback(CoerceAllowsTransparency)));


        public static Boolean GetAllowsTransparency(Control element)
        {
            CheckElementType(element);
            return (Boolean)element.GetValue(AllowsTransparencyProperty);
        }

        public static void SetAllowsTransparency(Control element, Boolean value)
        {
            CheckElementType(element);
            element.SetValue(AllowsTransparencyProperty, value);
        }

        private static Object CoerceAllowsTransparency(DependencyObject element, object baseValue)
        {
            //WPF will force the Popup into WS_CHILD window when running under partial trust, layered windows
            //is only supported for top level windows, so it doesn't make any sense to set the AllowsTransparency to true
            //when running under partial trust.
          
return IsRunningUnderFullTrust() ? baseValue : false;
        }

        private static Boolean IsRunningUnderFullTrust()
        {
            Boolean isRunningUnderFullTrust = true;
            try
          
{
                NamedPermissionSet permissionSet = newNamedPermissionSet("FullTrust");
                permissionSet.Demand();
            }
            catch(SecurityException)
            {
                isRunningUnderFullTrust = false;
            }

            return isRunningUnderFullTrust;
        }

        private static void OnAllowsTransparencyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            Control element = (Control)sender;
            CheckElementType(element);

            if(element.IsLoaded)
            {
                //Find the Popup logical element root.
              
Popup popup = GetPopupFromVisualChild(element);
                if(popup != null) popup.SetValue(Popup.AllowsTransparencyProperty, e.NewValue);
            }
            else
          
{
                var templateDescriptor = DependencyPropertyDescriptor.FromProperty(Control.TemplateProperty, element.GetType());

                EventHandler handler = null;
                handler = (obj, args) =>
               {
                   //Not clear why the BeginInvoke call is needed here, but this could effectively
                   //workaround cyclic reference exception when evaluating ToolTip/ContextMenu's Style property.
                 
element.Dispatcher.BeginInvoke(DispatcherPriority.Send, newAction(delegate
                 
{
                       SetAllowsTransparencyInternal(element, e.NewValue);
                   }));

                   //Clear event handler to avoid resource leak.
                 
templateDescriptor.RemoveValueChanged(element, handler);
               };

                templateDescriptor.AddValueChanged(element, handler);
            }
        }

        private static void CheckElementType(Control element)
        {
            if(!(element is ToolTip || element is ContextMenu))
            {
                throw new NotSupportedException("AllowsTransparency attached property can only be applied to ToolTip or ContextMenu");
            }
        }

        private static void SetAllowsTransparencyInternal(Control element, Object value)
        {
            ToolTip tooTip = element as ToolTip;
            ContextMenu contextMenu = element as ContextMenu;

            // Set the IsOpen property to true to let the ToolTip/ContextMenu create Popup instance early, since
            // we are only interesting in Popup.AllowsTransparency property rather than
            // opening the ToolTip/ContextMenu, set its Visibility to Collapsed.
          
element.Visibility = Visibility.Collapsed;
            if(tooTip != null)
            {
                tooTip.IsOpen = true;
            }
            else if(contextMenu != null)
            {
                contextMenu.IsOpen = true;
            }

            //Find the Popup logical element root.
          
Popup popup = GetPopupFromVisualChild(element);
            if(popup != null) popup.SetValue(Popup.AllowsTransparencyProperty, value);

            //Set properties back to what it is initially.
          
if(tooTip != null)
            {
                tooTip.ClearValue(ToolTip.IsOpenProperty);
            }
            else if(contextMenu != null)
            {
                contextMenu.ClearValue(ToolTip.IsOpenProperty);
            }
            element.ClearValue(FrameworkElement.VisibilityProperty);
        }

        private static Popup GetPopupFromVisualChild(Visual child)
        {
            Visual parent = child;
            FrameworkElement visualRoot = null;

            //Traverse the visual tree up to find the PopupRoot instance.
          
while(parent != null)
            {
                visualRoot = parent as FrameworkElement;
                parent = VisualTreeHelper.GetParent(parent) as Visual;
            }

            Popup popup = null;

            // Examine the PopupRoot's logical parent to get the Popup instance.
            // This might break in the future since it relies on the internal implementation of Popup's element tree.
          
if(visualRoot != null)
            {
                popup = visualRoot.Parent as Popup;
            }

            return popup;
        }
    }
}

I have fully commented the code so it might be a little bit more straightforward to read. All in All, the implementation is a little bit like a hack, and might be broken in the future version of WPF as I commented above:)
Here is the complete VS project: HwndHostInPopupDemo.zip

When Selector.IsSynchronizedWithCurrentItem will be true?

| 4 comments

This looks like an obvious question, you when set it to true either through XAML or code, then the Selector's (such as ListBox and ComboBox) selection operation will drive the setting of the current item within CollectionView which presents the data bound source collection, so when you want to synchronize current item with the selected item, you could write something like the following XAML snippet:

<
Pagexmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:sys="clr-namespace:System;assembly=mscorlib">
  <
Page.Resources>
    <
x:Arrayx:Key="data" 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>
  </
Page.Resources>
  <
StackPanel DataContext="{StaticResource data}">
    <
ListBox ItemsSource="{Binding}" Margin="5" IsSynchronizedWithCurrentItem="True"/>
    <
ComboBox ItemsSource="{Binding}" Margin="5" IsSynchronizedWithCurrentItem="True"/>
    <
TextBlock>CurrentItem: <TextBlock Text="{Binding /}"/>
    </
TextBlock>
  </
StackPanel>
</
Page>

From the above code, the ListBox and ComboBox is data bound to the same source collection, but for each ItemsSource binding, a unique CollectionView is generated, so that both ListBox and ComboBox can make independent selection without affecting each other, this is what most developers expect. So if you want both ListBox and ComboBox to drive the currency, you need to explicitly set the IsSynchronizedWithCurrentItem property to true, this is pretty obvious and straightforward, isn't it?

If you think this is an obvious thing to do, then I have another XAMLPad ready example which might confuse you:

<
Pagexmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:sys="clr-namespace:System;assembly=mscorlib">
  <
Page.Resources>
    <
x:Arrayx:Key="data" 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>
    <
CollectionViewSource x:Key="src" Source="{StaticResource data}"/>
  </
Page.Resources>
  <
StackPanel DataContext="{StaticResource src}">
    <
ListBox ItemsSource="{Binding}" Margin="5"/>
    <
ComboBox ItemsSource="{Binding}" Margin="5"/>
    <
TextBlock>CurrentItem: <TextBlock Text="{Binding /}"/>
    </
TextBlock>
  </
StackPanel>
</
Page>

If you run above XAML snippet in XAMLPad, you will find that both ListBox and ComBox can drive the currency as if the IsSynchronizedWithCurrentItem property is set to true. so what happens?

If you use reflector to example the source code of the Selector, if you will the SetSynchronizationWithCurrentItem() method implementation as follows:

private void SetSynchronizationWithCurrentItem()
{
    bool? isSynchronizedWithCurrentItem = IsSynchronizedWithCurrentItem;
    bool oldSync = IsSynchronizedWithCurrentItemPrivate;
    bool newSync;

    if (isSynchronizedWithCurrentItem.HasValue)
    {
        // if there's a value, use it
       
newSync = isSynchronizedWithCurrentItem.Value;
    }
    else
   
{
        // when the value is null, synchronize if selection mode is Single
        // and there's a non-default view.
       
SelectionMode mode = (SelectionMode)GetValue(ListBox.SelectionModeProperty);
        newSync = (mode == SelectionMode.Single) &&
        !CollectionViewSource.IsDefaultView(Items.CollectionView);
    }

    IsSynchronizedWithCurrentItemPrivate = newSync;

    if (!oldSync && newSync)
    {
        SetSelectedToCurrent();
    }
}

From the bolded line of code, it seems that this is an intentional behaviour, which means that if the SelectionMode of Selector is Single, and the CollectionView data bound to the Selector is not the implicit, default View generated by WPF's data binding engine, Selector will drive the currency. This might not make sense to you, but after the following explanation, I hope it finally makes sense to you.

There are two aspects for this issue, the first is multi selection, and the second is non-default view.

First, it's no brainer that when the Selector is in Multiple SelectionMode, WPF can not take on current synchronization, because there is no such concept of "multi-current items" from the perspective of each ICollectionView implementation(CollectionView for IEnumerable, ListCollectionView for IList and BindingListCollectionView for IBindingList etc), you might think that WPF can choose one item from the selected items as the current item, but it's hard to figure out which one is the best candidate for current item, because this decision usually varies tremendously in different scenarios, and it's nearly impossible for a general purpose framework like WPF to make a good decision for you.

Second, WPF drives currency if you are using the non-default explicit CollectionView, this usually is achieved by declaring the underlying data to be CollectionViewSource, because when you use CollectionViewSource which is a XAML friendly version of CollectionView, WPF assumes that you are mostly likely wanting to enable master/detail binding, and it's obvious that you need the currency synchronization service provided by Selector. So WPF thinks that it's a good default and correct behaviour to implicitly turn on currency synchronization for you.

Knowing that this is the heuristics WPF makes on how you are going to use the data, and it might cause some incorrect behaviour as reported in this WPF MSDN forum thread, so it might worth a blog entry to point this out:)

BTW, for any one who thinks that the {Binding /} syntax is alien to them, you could refer to this Ian Griffith's excellent blog post for explanation.

The Power of Shader - Part One

| 2 comments

.NET Framework 3.5 SP1 Beta1 has been released, this release is not simply a service pack release as we've known for many years of what  SP actually means. It seems that Microsoft has changed its strategy, and start to include new features in SP release.

One of the most exciting feature of this release is a new hardware accelerated, pixel shader based custom effect architecture which drives the software, WIC based bitmap effect architecture into obsolete. This new architecture has tackle many of the performance problems inherent with previous stale architecture. On one hand, the new custom effect will run in composition thread rather than UI thread, which means that it will not tie up the UI thread as the previous effect does, on the other hand, it will be hardware accelerated if your GPU supports pixel shader 2.0 or above. If you don't have decent GPU, the effect will be emulated using software, RenderTargetBitmap is a special case, if any visual which has effect applied to it needs to be rasterized into the RenderTargetBitmap, it will go through software rendering path.

If you have read the blog series written by Greg Schechter about the new shader effect feature, you could have been familiar with how to create simple effects. But those shader effect expects you to pass in the pre-compiled HLSL bytecode, which really requires you to use the shader compiler (fxc.exe) which is shipped with the DirectX SDK to compile the shader first, then pass it to the ShaderEffect derivative's constructor. How about if I want to directly pass in the source shader string, and have it get compiled and executed at runtime, this is called online compilation as compared with offline compilation with fxc.exe tool. Fortunately, I could use the Microsoft.DirectX.Direct3D.ShaderLoader class which is part of the managed DirectX API which can do exactly what I want, Here is the ShaderEffect implementation which supports online compilation:

public class SourceShaderEffect : ShaderEffect
{
    // The custom effect expects pixel shader 2.0 support.
    public static readonly String PixelShaderProfile = "ps_2_0";

    public static readonly ShaderFlags ShaderFlags = ShaderFlags.None;

    // We use "main" as the default function name for the shader.
    public static readonly String DefaultFunctionName = "main";

    /// <summary>
    /// Constructs a new SourceShaderEffect instance.
    /// </summary>
    /// <param name="shaderFilePath">path to the source shader file</param>
    /// <param name="functionName">shader entry function name</param>
    public SourceShaderEffect(String shaderFilePath, String functionName)
    {
        GraphicsStream stream = ShaderHelper.TryThrowCriticalException(() =>
        {
            return ShaderLoader.CompileShaderFromFile(
                shaderFilePath,
                functionName,
                null,
                PixelShaderProfile,
                ShaderFlags);
        });

        if (null != stream)
        {
            base.PixelShader = new PixelShader();
            base.PixelShader.SetStreamSource(stream);
        }
    }

    /// <summary>
    /// Constructs a new SourceShaderEffect instance.
    /// </summary>
    /// <param name="shaderStream">stream which contains the shader source code.</param>
    /// <param name="functionName">shader entry function name</param>
    public SourceShaderEffect(Stream shaderStream, String functionName)
    {
        GraphicsStream stream = ShaderHelper.TryThrowCriticalException(() =>
       {
           return ShaderLoader.CompileShaderFromStream(
               shaderStream,
               functionName,
               null,
               PixelShaderProfile,
               ShaderFlags);
       });

        if (stream != null)
        {
            base.PixelShader = new PixelShader();
            base.PixelShader.SetStreamSource(stream);
        }
    }

    /// <summary>
    /// Constructs a new SourceShaderEffect instance with default shader entry function name.
    /// </summary>
    /// <param name="shaderFilePath">path to the source shader file</param>
    public SourceShaderEffect(String shaderFilePath) : this(shaderFilePath, DefaultFunctionName) { }

    /// <summary>
    /// Constructs a new SourceShaderEffect instance with default shader entry function name.
    /// </summary>
    /// <param name="shaderStream">stream which contains the shader source code.</param>
    public SourceShaderEffect(Stream shaderStream) : this(shaderStream, DefaultFunctionName) { }
}

 

There is no fancy stuff in this code, with the above code, you could simply pass a file path or stream to the shader source code, and you are done with it. Let's create a simple effect to see if it actually works, the following is a Sepia shader which I learnt from this nice article:

sampler2D s0 : register(s0);
float4 main(float2 tex : TEXCOORD0) : COLOR
{
    float4 color = tex2D(s0, tex);
    float value = color[0] * 0.299f + color[1] * 0.587f + color[2] * 0.114f;
    return tex2D(s0, value);
}

Let's save it into a file called Sepia.fx, and add it as a resource file into the WPF project you create from visual studio. In XAML, you could place an Image element, and at the code behind, you could write something like the following:

image.Effect = CreateSourceShaderEffect("Sepia");


public static ShaderEffect CreateSourceShaderEffect(String shaderLocation)
{
    ShaderEffect effect = null;
    shaderLocation = "pack://application:,,,/Shaders/" + shaderLocation + ".fx";
    Stream shaderStream = Application.GetResourceStream(new Uri(shaderLocation, UriKind.Absolute)).Stream;
    if (null != shaderStream)
    {
        effect = new SourceShaderEffect(shaderStream);
    }

    return effect;
}

 

Then, it seems that you've got everything ready to run, but actually you don't, if you are running under 64 bit Windows, you need to set the visual studio build system to target X86 architecture instead, otherwise you will get a BadImageFormatException. This means that to enable online compilation, your Application should be 32 bit, and it will be emulated when running under 64 bit Windows through WOW64 layer, which might not be what you expect. so if you are targeting 64 bit Windows, and you want your WPF application to be 64 bit, this technique is not the way to go, otherwise, it could be an option for you.

The following is a full sample code with another two simple shader effects such as Invert, and Grayscale. On the next installment, I will try to take adventure on shader effects with input parameters and with multi-sampler blending when I learnt how to do them:)

Attachment:ShaderEffectDemo.zip

Applicatons = Markup + Code

| 1 comments

I was asked by one of Chinese leading ComSci book publishers to write a book review on Charles Petzold's classical WPF book Applications = Markup + Code, because they've just finished with translating this awesome book into Chinese. Charles is always one of my most respectable .NET gurus, and here is my humble attempt at commentting on his book:

Windows Presentation Foundation hits the Windows programming community quite tremendously from the very beginning of its CTP release not only because it's a much better and superior technology than the stale GDI/USER based UI Framework, but also because it brings in a new programming paradigm that most Windows programmers might have never thought of, that is Applications = Markup + Code.

Windows Presentation Foundation is Microsoft's first attempt at unifying the programming model both for Windows desktop and the Web going forward (with the introduction of Silverlight, you can employ the same programming concept and techniques to author Rich Internet Applications). Windows Presentation Foundation also enables a new workflow between developers and designers, with Windows Presentation Foundation, designers has become an integral part of the whole software development process, and they will have a vital say over the final appearance of the whole UI, because they are trained for this, and specialized at doing this. This can free the developers from concerning about something they are not good at, such as how to adjust the colour contrast to make the Button looks more esthetically pleasing.

Windows Presentation Foundation also integrates text, imaging, graphics (both 2D and 3D), animations, audio/video, documents, printing, and resources management APIs into a single framework, those powerful APIs and toolsets really enable developers to build rich visualization applications. The ability to seamlessly incorporate 2D content over 3D scenes and vice versa is simply stunning which gives possibility to write Northface Demo type of applications.

Charles Petzold brings in his years of Windows programming experiences to provide us with a hitchhikers' guide around Windows Presentation Foundation first from the perspective of code, then XAML (Extension Application Markup Language), which might be the ultimate UI definition language for Windows moving forward. From Chapter 1 to Chapter 17, Charles first introduces us the basic WPF controls and how they differ from traditional win32/Windows Forms counterparts, he also teaches us probably the most important core concepts of WPF such as Dependency Properties and Routed Events which is a little bit different from what we've known about properties and events in C#. He also gives us a de tour on how to write a custom layout panel to layout elements/controls in a predefined manner which is pretty useful when you want to roll up your own data presentation controls. In the unique Chapter 18, Charles aggregates what we've learnt from the previous chapters to tell us how to write a full-blown WPF application such as Notepad. From Chapter 19 to Chapter 31, the amazing XAML tour starts. Again in those Chapters, Charles still focus on the basic building block of WPF such as navigation, geometrical transformation, data binding, control templates and data templates etc, but this time, from the XAML perspective, he tells us how to declaratively specify WPF constructs, and how they relate to their code representations, which is very important, this can help developers to better understand XAML, what it can and cannot do.

Charles' book just covers hoards of WPF contents and concept which I cannot name it all, but suffice it to say that I find the book Applications = Markup + Code quite complete, informative and interesting to read. I think this book should be put onto every serious WPF developer's bookshelves, what you think?