Zhou's profileSheva's TechSpacePhotosBlogLists Tools Help
1/5/2009

Streaming Media Content Over WCF RESTful Service

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 samples from HTTP transport or local file system, but doesn’t provide a built-in source filter to read samples 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 2003 and Windows 2008. This link illustrates how to configure WMS in Windows 2003.

1/4/2009

Include XML Declaration in WCF RESTful Service Response

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 serliazation 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);
}

4/5/2008

WPF, Terminal Services & Bitmap Remoting

Everybody who has been playing around with WPF for a reasonable period of time might have known that WPF Application Processing is actually split up into two threads, they are UI thread which runs the dispatcher loop, and processes any GUI, keyboard/mouse/ink input, animation, layout and user initiated messages/events, and there is a hidden unmanaged background thread which is responsible for composing the graphical content (both in hardware or software if fallback is needed), and presenting it to frame buffer for display.

The whole architecture of WPF is built around this two threads model, and it has some of the benefits as articulated by Chris Anderson in the two-year long Channel video. One of the benefits Chris mentioned is that with the two threads model, in terminal services scenario, we can have the UI thread running in the TS server, and have the composition thread (or render thread in other nomenclature) running at the TS client console. And the communication between the two threads are handed over to the TS/RDP protocol. This can enable one interesting scenario called primitive remoting or vector remoting. And since UI thread is running at the TS server side, and it maintains the visual tree and the composition is at the TS client side and it keeps up a composition tree, so in order to keep the client screen up to date, the UI thread will send the edits to the composition tree over the TS/RDP protocol in a highly compressed manner, this not only saves the network bandwidth, because only the edits need to be remoted, but also speeds up the client processing. This type of server/client communication also holds true in the standalone WPF application, the difference is that the two threads are running at the same Win32 process, and the inter thread communication mechanism is used instead of the TS/RDP wire. To enable primitive remoting, both the TS server and TS client should run under Windows Vista and with desktop composition is enabled, this requirement tremendously narrows down the scenario in which the primitive remoting could be leveraged.

The upcoming .NET Framework 3.5 SP1 release would change all of this, in particular, bitmap remoting with sub region update support will always be used even if the TS server and the TS client are equipped to support primitive remoting, primitive remoting can be as good or bad as bitmap remoting, and the scenario in which primitive remoting is enabled is quite rare, because most existing Windows servers such as Windows 2000 or Windows 2003 server families don't support primitive remoting by default. So for any developer who want your WPF applications to run reasonably well under TS scenario and running under TS is an important scenario for your applications, you need to take implication of bitmap remoting into consideration beforehand, there are a couple of ways from which you can improve the performance of your WPF application in TS scenario:

  • Considering using as little animations as possible in your application, and if animations are indispensable, you could try reducing the DesiredFrameRate (The default value is 6O FPS) of each animations you need to use, usually 25~30 FPS should be enough, and if you don't need to high fidelity animation experience, you can use a even lower frame rate.
  • Considering using solid color brushes instead of gradient or tile brushes.
  • Try reducing the number of "hidden redraws" your application needs to perform, "hidden redraws" will be overlaid by its most foreground redraws, but they will still be remoted which waste network bandwidth. You can visualize the "hidden redraws" using the Perforator (part of WPF Performance Suite) with "Show dirty-regions update overlay" CheckBox checked.
1/3/2008

How to Reference Named Elements Within CellTemplate?

Getting reference to the named elements within data template is a commonly requested feature of WPF. In the current version of WPF, there is no intuitive and straightforward way to do it, you need to either traverse the visual tree to compare the Name property of each FrameworkElements within the tree, or alternatively you can first off grab the reference to the ContentPresenter within the ControlTemplate, and call DataTemplate.FindName() passing in the ContentPresenter reference as the "templatedParent" argument. Accessing named elements within CellTemplate complicates the things a bit since each Cell will have different instantiation of CellTemplate, the following helper class gives a possible solution to this problem (I also posted it in this WPF MSDN forum thread):

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

namespace Sheva.Windows.Component
{
    public static class ListViewHelper
  
{
        /// <summary>
        ///
Finds an element that has the provided identifier name within the specified cell template identified by the cellColumn and cellRow
      
/// </summary>
        /// <param name="listView">
the referenced ListView control</param>
        /// <param name="cellColumn">
the index of column from which the CellTemplate will be retrieved</param>
        /// <param name="cellRow">
the index of the row from which the specified ListViewItem will be retrieved</param>
        /// <param name="name">
The name of the requested element.</param>
        /// <returns>
The requested element. This can be null reference if no matching element was found.</returns>
      
public static FrameworkElement FindNameFromCellTemplate(ListView listView, Int32 cellColumn, Int32 cellRow, Stringname)
        {
            if(listView == null)
            {
                throw newArgumentNullException("listView");
            }

            if(!listView.IsLoaded)
            {
                throw new InvalidOperationException("ListView is not yet loaded");
            }

            if (cellRow >= listView.Items.Count || cellRow < 0)
            {
                throw new ArgumentOutOfRangeException("row");
            }

            GridView gridView = listView.View as GridView;
            if (gridView == null)
            {
                return null;
            }

            if (cellColumn >= gridView.Columns.Count || cellColumn < 0)
            {
                throw new ArgumentOutOfRangeException("column");
            }

            ListViewItem item = listView.ItemContainerGenerator.ContainerFromItem(listView.Items[cellRow]) as ListViewItem;
            if (item != null)
            {
                if (!item.IsLoaded)
                {
                    item.ApplyTemplate();
                }
                GridViewRowPresenter rowPresenter = GetFrameworkElementByName<GridViewRowPresenter>(item);

                if(rowPresenter != null)
                {
                    ContentPresenter templatedParent = VisualTreeHelper.GetChild(rowPresenter, cellColumn) as ContentPresenter;
                    DataTemplate dataTemplate = gridView.Columns[cellColumn].CellTemplate;
                    if(dataTemplate != null && templatedParent != null)
                    {
                        return dataTemplate.FindName(name, templatedParent) as FrameworkElement;
                    }
                }
            }

            return null;
        }

        private static T GetFrameworkElementByName<T>(FrameworkElement referenceElement) where T : FrameworkElement
      
{
            FrameworkElementchild = null;
            for(Int32 i = 0; i < VisualTreeHelper.GetChildrenCount(referenceElement); i++)
            {
                child = VisualTreeHelper.GetChild(referenceElement, i) as FrameworkElement;
                if(child != null && child.GetType() == typeof(T))
                {
                    break;
                }
                else if(child != null)
                {
                    child = GetFrameworkElementByName<T>(child);
                    if(child != null && child.GetType() == typeof(T))
                    {
                        break;
                    }
                }
            }
            returnchild asT;
        }
    }
}

This actually requires a bit of coding, hopefully future version of WPF in particular the ListView control could has a much better content model to make it more flexible and extensible than it is right now.

11/25/2007

DataErrorValidationRule - New Way To Invalidate Data In WPF

The WPF 3.5 has introduced a new data validation API aka DataErrorValidationRule, which you can specify on the Binding object, if the data source implements the IDataErrorInfo interface. This new feature enables some of the scenario the previous Custom ValidationRule cannot enable.

One of the scenario the custom ValidationRule cannot support is to enable data binding on the properties of the Custom ValidationRule class. Because ValidationRule is not a DependencyOject, you cannot define dependency properties on it to enable data binding. And because ValidationRule is not a part of the element tree, any Binding expression which relies on RelativeSource or ElementName or similar things that needs to walk up the element tree to find the binding source cannot be evaluated successfully. Some community members such as Josh Smith has come up with a hackery to workaround this limitation using the trick he calls "Virutal Branches". Or our beloved Dr. WPF's ObjectReference custom Markup Extension as he "bloated" in this MSDN WPF thread.

DataErrorValidationRule drives those "dirty tricks" to obsolete. Because You don't need to bind some values to custom ValidationRule object as validation input parameters. Because when implementing IDataErrorInfo, you do the validation logic at the source object. The following is an example of how to leverage the DataErrorValidationRule API to suppport the type of scenario "Virtual Branches" is trying to enable.

First off, the data source class should implement IDataErrorInfo or INotifyPropertyChanged if you want to enable two way data binding as follows:

public class Person : IDataErrorInfo, INotifyPropertyChanged
{
    private int age;
    private int min = 0;
    private int max = 150;

    public int Age
    {
        get { return age; }
        set
        {
            age = value;
            RaisePropertyChanged("Age");
        }
    }

    public string Error
    {
        get
        {
            return null;
        }
    }

    public int Min
    {
        get
        {
            return min;
        }
        set
        {
            min = value;
            RaisePropertyChanged("Min");
        }
    }

    public int Max
    {
        get
        {
            return max;
        }
        set
        {
            max = value;
            RaisePropertyChanged("Max");
        }
    }

    public string this[string name]
    {
        get
        {
            string result = null;

            if (name == "Age")
            {
                if (this.age < this.Min || this.age > this.Max)
                {
                    result = String.Format("Age must not be less than {0} or greater than {1}.", this.Min, this.Max);
                }
            }
            return result;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

You can see that Min and Max properties needs to be specified by the user, so we need to bind those two properties to corresponding UI elements as following XAML snippet shows:

<Window x:Class="BusinessLayerValidation.Window1"
       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       Title="WPF IDataErrorInfo Sample"
       Width="450" Height="170"
       xmlns:src="clr-namespace:BusinessLayerValidation">

  <
Window.Resources>
    <
src:Person x:Key="data"/>
    <
Style x:Key="textBoxInError" TargetType="TextBox">
      <
Style.Triggers>
        <
Trigger Property="Validation.HasError" Value="true">
          <
Setter Property="ToolTip"
                 Value="{Binding RelativeSource={x:Static RelativeSource.Self},
                        Path=(Validation.Errors)[0].ErrorContent}
"/>
        </
Trigger>
      </
Style.Triggers>
    </
Style>
  </
Window.Resources>

  <
StackPanel Margin="20" DataContext="{Binding Source={StaticResource data}}">
    <
StackPanel Orientation="Horizontal">
      <
TextBlock Width="60">
        Min:(<TextBlock Text="{Binding Path=Value, ElementName=minSlider}"/>)
      </TextBlock>
      <
Slider Margin="10, 0, 0, 0"
              Name="minSlider"
              Width="300"
              Orientation="Horizontal"
              IsSnapToTickEnabled="True"
              HorizontalAlignment="Right"
              TickPlacement="BottomRight"
              AutoToolTipPlacement="BottomRight"
              Value="{Binding Path=Min, Mode=TwoWay}"
              Minimum="0"
              Maximum="150"
              TickFrequency="10"/>
    </
StackPanel>
    <
StackPanel Orientation="Horizontal">
      <
TextBlock Width="60">
        Max:(<TextBlock Text="{Binding Path=Value, ElementName=maxSlider}"/>)
      </TextBlock>
      <
Slider Margin="10, 0, 0, 0"
              Name="maxSlider"
              Width="300"
              Orientation="Horizontal"
              IsSnapToTickEnabled="True"
              HorizontalAlignment="Right"
              TickPlacement="BottomRight"
              AutoToolTipPlacement="BottomRight"
              Value="{Binding Path=Max, Mode=TwoWay}"
              Minimum="0"
              Maximum="150"
              TickFrequency="10"/>
    </
StackPanel>
    <
TextBlock>Enter your age:</TextBlock>
    <
TextBox Style="{StaticResource textBoxInError}" Name="textBox">
      <
TextBox.Text>
        <
Binding Path="Age"
                ValidatesOnDataErrors="True"
                UpdateSourceTrigger="PropertyChanged">
          <
Binding.ValidationRules>
            <
ExceptionValidationRule/>
          </
Binding.ValidationRules>
        </
Binding>
      </
TextBox.Text>
    </
TextBox>
  </
StackPanel>
</
Window>

You can see from the XAML shown above that DataErrorValidationRule actually provide a greater flexibility when validating data. For a detailed introduction to DataErrorValidationRule, and its role in the WPF data validation model, you can refer to this WPF SDK blog article.

For completeness, I've attached full sample project here for further reference.

Attachment: WPFDataValidation.zip

How To Search Text In WPF FlowDocument?

This blog article is a reply to the recent WPF MSDN forum thread on how to efficiently search text in FlowDocument. The thread starter needs to have the same performance as the search feature in Visual Studio text editor. I don't know how Visual Studio IDE implements the search feature, but in terms of search in FlowDocument, because FlowDocument enables much richer content model, It's presumably much harder to achieve the same search performance as Visual Studio text editor.

I have to say that the code I posted in that thread apparently has a serious performance flaw, it introduces a lot of unnecessary iterations. After digging into this issue at the weekend, I finally come up with a method which can achieve the perceived performance, and I think this should be enough at most circumstance. Based on this method, I mocked up a sample code which shows how to perform find and replace feature in FlowDocument, because find and replace is a common feature every text editing tool should provide, this might help others who need this similar feature. The following shows the core code which perform the search:

/// <summary>
///
Find the corresponding<see cref="TextRange"/> instance
/// representing the input string given a specified text pointer position.
/// </summary>
///
<param name="position">the current text position</param>
///
<param name="textToFind">input text</param>
///
<param name="findOptions">the search option</param>
///
<returns>An<see cref="TextRange"/> instance represeneting the matching string withing the text container.</returns>
public TextRange GetTextRangeFromPosition(ref TextPointer position, String input, FindOptions findOptions)
{
    Boolean matchCase = (findOptions & FindOptions.MatchCase) == FindOptions.MatchCase;
    Boolean matchWholeWord = (findOptions & FindOptions.MatchWholeWord) == FindOptions.MatchWholeWord;

    TextRange textRange = null;

    while (position != null)
    {
        if (position.CompareTo(inputDocument.ContentEnd) == 0)
        {
            break;
        }

        if (position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
        {
            String textRun = position.GetTextInRun(LogicalDirection.Forward);
            StringComparison stringComparison = matchCase ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase;
            Int32 indexInRun = textRun.IndexOf(input, stringComparison);

            if (indexInRun >= 0)
            {
                position = position.GetPositionAtOffset(indexInRun);
                TextPointer nextPointer = position.GetPositionAtOffset(input.Length);
                textRange = new TextRange(position, nextPointer);

                if (matchWholeWord)
                {
                    if (IsWholeWord(textRange)) // Test if the "textRange" represents a word.
                    {
                        // If a WholeWord match is found, directly terminate the loop.
                        break;
                    }
                    else
                    {
                        // If a WholeWord match is not found, go to next recursion to find it.
                        position = position.GetPositionAtOffset(input.Length);
                        return GetTextRangeFromPosition(ref position, input, findOptions);
                    }
                }
                else
                {
                    // If a none-WholeWord match is found, directly terminate the loop.
                    position = position.GetPositionAtOffset(input.Length);
                    break;
                }
            }
            else
            {
                // If a match is not found, go over to the next context position after the "textRun".
                position = position.GetPositionAtOffset(textRun.Length);
            }
        }
        else
        {
            //If the current position doesn't represent a text context position, go to the next context position.
            // This can effectively ignore the formatting or embedded element symbols.
            position = position.GetNextContextPosition(LogicalDirection.Forward);
        }
    }

    return textRange;
}

The code above is part of my FindAndReplaceManager helper class implementation, you can refer to the attachment for the complete source code. The code should be pretty straightforward as I've commentted it. The FindAndReplaceManager can support search options such as FindOptions.MatchCase and FindOptions.MatchWholeWord, aka two commonly used search options. For simplicity, I don't implement reverse search, since this should be really straightforward, instead of using LogicalDirection.Forward, you could use LogicalDirection.Backward.

As I've said, the FindAndReplaceManager should be able to achieve perceived performance at most situation, if you need hard best performance. You'd better choose a more sophisticated search algorithm instead of the bare-bones "start-to-end" search algorithm as is illustrated in the code above.

Another alternative you could choose is the internal undocumented search API provided by WPF. The System.Windows.Documents.TextFindEngine class has a static "Find" method, this method is widely used in build-in document readers and viewers such as FlowDocumentReader, FlowDocumentPageViewer, and FlowDocumentScrollViewer. Because TextFindEngine has a much better understanding of the underlying document content structure, it should provide the hard performance benefit you expect. The following helper method shows how to use this method:

using System;
using System.Windows;
using System.Reflection;
using System.Globalization;
using System.Windows.Documents;

namespace Sheva.Windows.Documents
{
    [Flags]
    public enum FindFlags
    {
        FindInReverse = 2,
        FindWholeWordsOnly = 4,
        MatchAlefHamza = 0x20,
        MatchCase = 1,
        MatchDiacritics = 8,
        MatchKashida = 0x10,
        None = 0
    }

    public static class DocumentHelper
    {
        private static MethodInfo findMethod = null;

        public static TextRange FindText(TextPointer findContainerStartPosition,TextPointer findContainerEndPosition, String input, FindFlags flags, CultureInfo cultureInfo)
        {
            TextRange textRange = null;
            if (findContainerStartPosition.CompareTo(findContainerEndPosition) < 0)
            {
                try
                {
                    if (findMethod == null)
                    {
                        findMethod = typeof(FrameworkElement).Assembly.GetType("System.Windows.Documents.TextFindEngine").
                               GetMethod("Find", BindingFlags.Static | BindingFlags.Public);
                    }
                    Object result = findMethod.Invoke(null, new Object[] { findContainerStartPosition,
                    findContainerEndPosition,
                    input, flags, CultureInfo.CurrentCulture });
                    textRange = result as TextRange;
                }
                catch (ApplicationException)
                {
                    textRange = null;
                }
            }

            return textRange;
        }
    }
}

Because TextFindEngine.Find() is a non-public API, we should use a bit of reflection code to call it. If you are working on pesonal project, feel free to use it as an alternative, but never ever use this method in production code.

WPF should provide a much better built-in public API to perform search operation in FlowDocument. I don't know what type of future plan WPF team has, but from my educated guess, WPF should have a much better support on this in the near future.

Attachment: SearchInFlowDocumentDemo.zip

11/10/2007

WCF Trip - What Happens To BeginInvoke

    Recently I came across Nicholas Allen's blog post talking about how BeginInvoke breaks when used against proxies generated by WCF client runtime, specifically the ChannelFactory. and his conclusion to the misbehaviour exposed by BeginInvoke right here is something like this (quoted from the original article):

The problem is that BeginInvoke knows about and only works with specific types of proxy objects, which do not include the proxy objects generated by ChannelFactory.

    Actually Nicholas Allen's reasoning here is kinda like a "technical correct but lack of detailed explanation" statement, if you write something like the following, no one can imagine that you are actually doing something wrong:

String uri = "net.tcp://localhost:2222/Services";
ChannelFactory<IEchoService> factory = new ChannelFactory<IEchoService>(new NetTcpBinding(), uri);
IEchoService proxy = factory.CreateChannel();
EchoDelegate d = new EchoDelegate(proxy.Echo);
IAsyncResult result = d.BeginInvoke("foo", new AsyncCallback(Callback), null);

   So what really happens here?

   Let's first add some piece of code into the original testing code to check some of presumptions I make on the proxy generated by ChannelFactory:

Console.WriteLine(System.Runtime.Remoting.RemotingServices.IsTransparentProxy(proxy));
Console.WriteLine(System.Runtime.Remoting.RemotingServices.GetRealProxy(proxy).GetType());
Console.WriteLine(result.IsCompleted);

   If running the modified code, you will find some of the interesting bits:

  1. The proxy generated by WCF client runtime aka ChannelFactory is actually a TransparentProxy;
  2. The RealProxy paired with this TransparentProxy is a System.ServiceModel.Channels.ServiceChannelProxy implementation;
  3. When beginInvoking against a proxy generated by ChannelFactory, the call is performed as ordinary synchronous method invocation.

   So what's the happening here? How does WCF relate to the remoting architecture such as TransparentProxy and RealProxy metaphors? and specifically why does BeginInvoke break here?

   To answer those questions, let's first take on the first question, and digg into it, I've spent several hours to examine the implementation of WCF ChannelFactory implementation, one of the greatest discovery I find is that before kicking off the channel stack to process the service request, WCF client runtime will actually intercept every WCF service call by injecting a TransparentProxy and ServiceChannelProxy between WCF service call site and underlying the channel stack. The reason WCF implements the client runtime the way it is is that WCF needs to differ between normal method invocation and WCF service invocation on service proxy objects. how about if you call GetType() on the proxy generated by the ChannelFactory, what type do you expect the GetType() method will return? If you write the code to test, you will get stunned by realizing that GetType() will actually return IEchoService, WTF? How does GetType() method return the interface type object rather than the concrete type object? Actually, WCF has been intercepted the call to GetType(), and revamped it to return the underlying proxied type, thus hiding the real proxy implementation for IEchoService. Another reason WCF intercepts every method call is to differ between synchronous service calls and asynchronous service calls. Imagine you have a WCF service contract like this:

[ServiceContract]
public interface IEchoService
{
    [OperationContract]
    String Echo(String text);
}

   If you run the svcutil.exe tool to generate client side proxy implementation for async call just as Nicholas Allen suggested in his original article:

   svcutil /language:C# /config:App.config /async net.tcp://localhost:2222/Services

   you will get something like this:

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="IEchoService")]
public interface IEchoService
{
   
    [System.ServiceModel.OperationContract]
    string Echo(string text);
   
    [System.ServiceModel.OperationContract]
    System.IAsyncResult BeginEcho(string text, System.AsyncCallback callback, object asyncState);
   
    string EndEcho(System.IAsyncResult result);
}

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public interface IEchoServiceChannel : IEchoService, System.ServiceModel.IClientChannel
{
}

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class EchoServiceClient : System.ServiceModel.ClientBase<IEchoService>, IEchoService
{
   
    public EchoServiceClient()
    {
    }
   
    public EchoServiceClient(string endpointConfigurationName) : base(endpointConfigurationName)
    {
    }
   
    public EchoServiceClient(string endpointConfigurationName, string remoteAddress) :
            base(endpointConfigurationName, remoteAddress)
    {
    }
   
    public EchoServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : base(endpointConfigurationName, remoteAddress)
    {
    }
   
    public EchoServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress    remoteAddress) : base(binding, remoteAddress)
    {
    }
   
    public string Echo(string text)
    {
        return base.Channel.Echo(text);
    }
   
    public System.IAsyncResult BeginEcho(string text, System.AsyncCallback callback, object asyncState)
    {
        return base.Channel.BeginEcho(text, callback, asyncState);
    }
   
    public string EndEcho(System.IAsyncResult result)
    {
        return base.Channel.EndEcho(result);
    }
}

    From the above code, we find that WCF follows .NET's asynchronous method invocation pattern quite closely by pairing each service operation call XX with a BeginXX and EndXX async call implementation. the code shown above is really clear and standard, but how does it work out actually? How does a BeginXX call will be performed asynchronously? and how does a EndXX kicks in here to finalize the asynchronous service invocation?

   In order to let the BeginXX and EndXX work as their signature indicate, WCF actually needs to know which service invocation is going to be performed through BeginXX or EndXX calls, to put it another way, WCF needs to know if the BeginXX or EndXX has been called, so it will perform its underlying plumbing to do the magic, in order to get those invocation infomation, WCF needs to have the capability to fine-grained control over the invocation of the service operations exposed by the service contracts. Since TransparentProxy and RealProxy mechanism which is heavily used by the .NET remoting has already haven this capability directly built into the CLR, WCF can leverage this infrastructure to intercept the method calls, and perform its underlying async plumbing at the channel level according to method you are going to invoke.

   Right now, I am almost finishing answering the first question - How does WCF relate to the remoting architecture such as TransparentProxy and RealProxy metaphors? but how about the second question I raised myself, why does BeginInvoke break when all the TP and RP plumbing is in place? This question is much trickier than it seems to be, after a bit of research on the default implementation of TP and RP mechanism used by .NET remoting using both  .NET reflector and the rotor 2.0 implementation of CLR, I finally figure out that for the current implementation of TP and RP mechanism, it only supports asynchronous call when the default RemotingProxy is in place, since the ServiceChannelProxy is WCF's own implementation, it gets ignored by the BeginInvoke mechanism, and the BeginInvoke call against WCF's proxies will be performed synchronously.

   Up until now, all the puzzles has been demystified. BeginInvoke is probably one of the most confusing APIs in the .NET framework as this article and my previous article demonstrates:)

10/23/2007

How To Globally Specify FontFamily In WPF?

   This question is asked about seven months ago in WPF MSDN forum, From the begining, I think this should be obvious, just specify the TextElement.FontFamily in the Application level, the font shall be applied to the entire UI elements within the app:

<Application TextElement.FontFamily="Constantia"/>

   But the thing is not that so straightforward, since Application is not a DependencyObject, you cannot specify an attached property on it, then how to do this trick?

   Just recently, I come up with an approach, since nearly every WPF UI control hosts TextBlock inside (either in data template or control template) to display text (except FlowDocument, FlowDocument has a different mechanism to render text), I can specify a Style within Application.Resources for TextBlock, then the style shall be applied to each TextBlocks within the app:

<Application x:Class="GlobalFontSettings.App"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   StartupUri="Window1.xaml">
  <
Application.Resources>
    <
Style TargetType="{x:Type TextBlock}">
      <
Setter Property="TextElement.FontFamily" Value="Constantia"/>
    </
Style>
  </
Application.Resources>
</
Application>

     I've written a little test app for it, and it works like a charm, hope this can help others who also want to implement the similar thing in WPF.

10/17/2007

Another Way to Undo Implicit Styles (Revisited)

    In my previous monthly long installment, I showed another way to undo the implicit style, I demonstrated how to leverage the InheritanceBehaviors to break the style lookup chains so you can have a portion of element tree which will directly pick up the system default theme styles. in this post, I will show a different approach to this problem based on the trick Mike Hillberg mentioned in his blog article.

    In Mike's original article, he showed that you can undo implicit style by explicitly set the interesting Element's Style property to null, based on this concept, I come up with the following code:

using System;
using System.IO;
using System.Windows;
using System.Diagnostics;
using System.Windows.Markup;
using System.Windows.Controls;
using System.Collections.Generic;

namespace Sheva.Windows.Components
{
    public class StyleManager
    {
        public static DependencyProperty IsDefaultStyleEnabledProperty = DependencyProperty.RegisterAttached(
            "IsDefaultStyleEnabled",
            typeof(Boolean),
            typeof(StyleManager),
            new FrameworkPropertyMetadata(false,
                                          FrameworkPropertyMetadataOptions.Inherits,
                                          new PropertyChangedCallback(OnIsDefaultStyleEnabledPropertyChanged)));
        private static Dictionary<FrameworkElement, Style> oldStyleStore = new Dictionary<FrameworkElement, Style>();

        public static void SetIsDefaultStyleEnabled(FrameworkElement element, Boolean value)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }

            if (value)
            {
                AddStyleToStore(element);
            }

            element.SetValue(IsDefaultStyleEnabledProperty, value);
        }


        private static void OnIsDefaultStyleEnabledPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            FrameworkElement element = sender as FrameworkElement;
            if (element == null) return;

            if ((Boolean)e.NewValue)
            {
                if (!(Boolean)e.OldValue)
                {
                    AddStyleToStore(element);
                }

                element.Style = null;
            }
            else
            {
                if (oldStyleStore.ContainsKey(element))
                {
                    element.Style = oldStyleStore[element];
                }
            }
        }

        private static void AddStyleToStore(FrameworkElement element)
        {
            Debug.Assert(element != null, "parameter 'element' cannot be null");
            if (!oldStyleStore.ContainsKey(element))
            {
                if (element.ReadLocalValue(FrameworkElement.StyleProperty) == DependencyProperty.UnsetValue)
                {
                    Style style = element.TryFindResource(element.GetType()) as Style;
                    oldStyleStore.Add(element, style);
                }
                else
                {
                    oldStyleStore.Add(element, element.Style);
                }
            }
        }
    }
}

      From the above code, you can see that I've defined a inheritable attached DependencyProperty so when this attached DP is applied in the parent element, all the children elements within its containing scope will has this attached DP inherited, and undo their implicit styles individually. The cloning of Style property using CreateStyleClone helper method is really necessary since when a style is explicitly set, and you want to turn it off, you should first cache the explicit style in the oldStyleStore, and then set the Style to null, the style within the oldStyleStore dictionary will also be nullified if you don't make a copy of the original style.

     The following XAML shows how to use the StyleManager class:

<Window x:Class="UndoImplicitStyles.Window1"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   Title="Undo Implicit Styles" Height="300" Width="300"
       xmlns:local="clr-namespace:Sheva.Windows.Components">
   <Window.Resources>
       <Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
           <Setter Property="FontFamily" Value="{DynamicResource {x:Static SystemFonts.MessageFontFamilyKey}}" />
           <Setter Property="FontSize" Value="{DynamicResource {x:Static SystemFonts.MessageFontSizeKey}}" />
           <Setter Property="FontStyle" Value="{DynamicResource {x:Static SystemFonts.MessageFontStyleKey}}" />
           <Setter Property="FontWeight" Value="{DynamicResource {x:Static SystemFonts.MessageFontWeightKey}}" />
           <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
           <Setter Property="HorizontalContentAlignment" Value="Center" />
           <Setter Property="VerticalContentAlignment" Value="Center" />
           <Setter Property="ClipToBounds" Value="True" />
           <Setter Property="Padding" Value="2" />
           <Setter Property="Margin" Value="10" />
           <Setter Property="Height" Value="30" />
           <Setter Property="Template">
               <Setter.Value>
                   <ControlTemplate TargetType="{x:Type Button}">
                       <Grid>
                           <Rectangle x:Name="GelBackground" Opacity="1" RadiusX="4" RadiusY="4" Stroke="Black" StrokeThickness="1">
                               <Rectangle.Fill>
                                   <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                                       <LinearGradientBrush.GradientStops>
                                           <GradientStop Offset="0" Color="White" />
                                           <GradientStop Offset="1" Color="#99ccff" />
                                       </LinearGradientBrush.GradientStops>
                                   </LinearGradientBrush>
                               </Rectangle.Fill>
                           </Rectangle>
                           <Rectangle x:Name="GelShine" Margin="2,2,2,0" VerticalAlignment="Top" RadiusX="6" RadiusY="6" Opacity="0" Stroke="Transparent" Height="15px">
                               <Rectangle.Fill>
                                   <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                                       <LinearGradientBrush.GradientStops>
                                           <GradientStop Offset="0" Color="#ccffffff" />
                                           <GradientStop Offset="1" Color="Transparent" />
                                       </LinearGradientBrush.GradientStops>
                                   </LinearGradientBrush>
                               </Rectangle.Fill>
                           </Rectangle>
                           <ContentPresenter x:Name="ContentSite" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" />
                       </Grid>
                       <ControlTemplate.Triggers>
                           <Trigger Property="IsMouseOver" Value="true">
                               <Setter Property="Rectangle.Fill" Value="#99ccff" TargetName="GelBackground" />
                               <Setter Property="Rectangle.Opacity" Value="1" TargetName="GelShine" />
                           </Trigger>
                       </ControlTemplate.Triggers>
                   </ControlTemplate>
               </Setter.Value>
           </Setter>
       </Style>
   </Window.Resources>
   <StackPanel>
       <Button Content="Click Me" />
       <CheckBox Content="Undo Implicit Style" Name="checkBox"/>
       <StackPanel local:StyleManager.IsDefaultStyleEnabled="{Binding ElementName=checkBox, Path=IsChecked}">
           <Button Content="Click Me" />
           <StackPanel>
               <Button Content="Click Me" />
               <StackPanel>
                   <Button Content="Click Me" />
               </StackPanel>
           </StackPanel>
       </StackPanel>
       <Button Content="Click Me" />
   </StackPanel>
</
Window>

   When you run above XAML code, you will find that when checking and unchekding the CheckBox, the style of Buttons within the containing StackPanel parent will by toggled between default system style and the implicit style set in the resource.

   Disclaimer: The above solution just gives you a way to tackle the problem of undoing implicit styles, and it's not an elegant or performant way of doing things, I just come up with it here for completeness rather than as a recommendation. if you want to have a portion of your element tree to just pick up the system default styles, I strongly recommend you to use the approach I demonstrated in my previous article, since presumably this approach is also taken by the Expression Blend.

Attachment: UndoImplicitStyles.zip

10/16/2007

How To Enumerate All The Bindings Set On A Specfied DependencyObject?

    Dr WPF one of the most active WPF MSDN forum participant just posts a reply on MSDN forum on how to enumerate all the binding objects set on a specified DependencyObject, this guy who seems to have the whole WPF SDK imprinted into his brilliant mind really knows something about WPF:)

   I just refactored his code a little bit, and made into my own WPF component/control library. kudos, Dr WPF:)

using System;
using System.Windows;
using System.Windows.Data;
using System.ComponentModel;
using System.Collections.Generic;

namespace Sheva.Windows.Components
{
    public static class DependencyPropertyHelper
    {
        public static IList<DependencyProperty> GetAttachedProperties(Object element)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }

            List<DependencyProperty> attachedProperties = new List<DependencyProperty>();

            foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(element,
                new Attribute[] { new PropertyFilterAttribute(PropertyFilterOptions.SetValues |
                                                                             PropertyFilterOptions.UnsetValues |
                                                                             PropertyFilterOptions.Valid) }))
            {
                DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(pd);
                if (dpd != null && dpd.IsAttached)
                {
                    attachedProperties.Add(dpd.DependencyProperty);
                }
            }

            return attachedProperties;
        }

        public static IList<DependencyProperty> GetProperties(Object element)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }

            List<DependencyProperty> properties = new List<DependencyProperty>();

            foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(element,
                new Attribute[] { new PropertyFilterAttribute(PropertyFilterOptions.SetValues | 
                                                                             PropertyFilterOptions.UnsetValues |
                                                                             PropertyFilterOptions.Valid) }))
            {
                DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(pd);
                if (dpd != null)
                {
                    properties.Add(dpd.DependencyProperty);
                }
            }

            return properties;
        }

        public static IEnumerable<Binding> EnumerateBindings(DependencyObject element)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }

            LocalValueEnumerator lve = element.GetLocalValueEnumerator();

            while (lve.MoveNext())
            {
                LocalValueEntry entry = lve.Current;

                if (BindingOperations.IsDataBound(element, entry.Property))
                {
                    Binding binding = (entry.Value as BindingExpression).ParentBinding;
                    yield return binding;
                }
            }
        }
    }
}