MVVM Model Property Setter

Introduction

Click here to view the source code

Working with MVVM tends to require quite a bit of boiler plate code to set up and use. Many developers will encapsulate common functionality to allow for better visibility and maintainability throughout the codebase. One repetitive functionality that occurs within ViewModels is setting properties. Although hiding the business logic for setting a property can be done on a private member, attempting to do the same on the Model is not quite as clean. In this article I will provide a solution to help reduce boilerplate code for setting a property using a Model’s property without losing property changed events.

Encapsulating Property Setter

First, let us view how setting a ViewModel’s property can be encapsulated. Using the CallerMemberName attribute for receiving the caller’s property name, an implementation can be made to generically set the incoming value along with firing off a PropertyChanged event:

protected bool SetProperty(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
	if (Equals(storage, value) || string.IsNullOrEmpty(propertyName))
	{
		return false;
	}

	storage = value;
	OnPropertyChanged(propertyName);
	return true;
}

By doing this, setting the property is quite straight forward with just a few lines:

private string _name;
public string Name
{
	get => _name;
	set => SetProperty(
			ref _name,
			value);            
}

Problems occur though when you want to follow the same pattern using a Model object’s property rather than the ViewModel’s private member. The reason a Model’s property cannot be used for our current SetProperty implementation has to do with the ref keyword since arguments must either be a variable, field, or array. Because of this, the Model’s property must be set to a temp variable to help with the transfer.

public string Name
{
	get => _toDo.Name;
	set
	{
		var name = _toDo.Name;
		if (SetProperty(
			ref name,
			value))
		{
			_toDo.Name = name;
		}
	}
}

This does not look pleasing to the eyes and may even provide enough of a reason to ignore SetProperty altogether. But if all the other public properties use SetProperty it provides a divide in how setting the property and firing the property changed events occur. Given that the current method is not acceptable let us try to rewrite the method to provide more flexibility

Property Setter with the Model

Since the ref keyword cannot be used to pass in the Model’s property, the only other solution is to leverage reflection. In order to do this, the Model’s class type, incoming value type, and the Model’s property as a form of expression is needed to reflect down to the PropertyInfo and set the Model’s property. The expression provides much of the metadata needed to retrieve the Model’s property current value, but the GetValue and SetValue methods are where the majority of reflection takes place. The solution looks similar to this:

protected bool SetProperty<TClassType, TValueType>(
TClassType classObj, 
Expression<Func<TClassType, TValueType>> outExpr, 
TValueType value, 
[CallerMemberName] string propertyName = null)
{
        var exprBody = outExpr.Body;
	if (exprBody is UnaryExpression)
	{
		exprBody = ((UnaryExpression)outExpr.Body).Operand;
	}

	var expr = (MemberExpression)exprBody;
	var prop = (PropertyInfo)expr.Member;
	var refValue = prop.GetValue(classObj, null);

	if (Equals(value, refValue))
	{
		return false;
	}
	prop.SetValue(classObj, value, null);
	OnPropertyChanged(propertyName);
}

By adding in this method, our ViewModel’s property setter is reduced to this:

public string Name
{
	get => _toDo.Name;
	set => SetProperty(
		_toDo,
		t => t.Name,
		value);
}

Now the ViewModel’s property setters are much easier to maintain and view.

Conclusion

Although this solution is elegant, the reflection aspect makes the function more of a convenience rather than a practical usage for a very highly performant application. Compared to the two styles of property setters, the new SetProperty is at least 6% slower. The speed costs may be negligible based on the needs of your app, but it is certainly something to keep in mind.

WPF Round Table Part 2: Multi UI Threaded Control – Fixes

Introduction

Click here to view the source code

Here are the past articles in the WPF Round Table Series:

In my last post I discussed a control I made that allowed for a user to create inline XAML on different UI threads. Today, I am going to discuss a couple of the pitfalls I ran into when attempting to resolve an issue a user asked about

FrameworkTemplates

So, someone asked about how to solve a particular issue with having 4 controls with busy indicators loading all on separate threads. As I was attempting to construct a solution my first instinct was to simply use the ThreadSeparatedStyle property and set the Style’s Template property with the look you want, sort of like this:

<Style TargetType="{x:Type Control}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Control}">
                <multi:BusyIndicator IsBusy="True">
                    <Border Background="#66000000">
                        <TextBlock Text="Random Text" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                    </Border>
                </multi:BusyIndicator>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Suddenly, I was hit with a UI thread access exception when attempting to do this. The problem arises from how WPF allows users to design FrameworkTemplates. WPF instantiates the templates immediately, which will cause threading issues when attempting to access this setter value on our separate UI thread. The key to solving this is by deconstructing the template into a thread safe string by using XAML serialization. First we will grab any FrameworkTemplates from the style:

var templateDict = new Dictionary<DependencyProperty, string>();
foreach ( var setterBase in setters )
{
    var setter = (Setter)setterBase;
    var oldTemp = setter.Value as FrameworkTemplate;
    // templates are instantiated on the thread its defined in, this may cause UI thread access issues
    // we need to deconstruct the template as a string so it can be accessed on our other thread
    if ( oldTemp != null && !templateDict.ContainsKey( setter.Property ) )
    {
        var templateString = XamlWriter.Save( oldTemp );
        templateDict.Add( setter.Property, templateString );
    }
}

Then, while recreating our Style on the newly created UI thread, we reconstruct the template:

foreach ( var setterBase in setters )
{
    var setter = (Setter)setterBase;
    // now that we are on our new UI thread, we can reconstruct the template
    string templateString;
    if ( templateDict.TryGetValue( setter.Property, out templateString ) )
    {
        var reader = new StringReader( templateString );
        var xmlReader = XmlReader.Create( reader );
        var template = XamlReader.Load( xmlReader );
        setter = new Setter( setter.Property, template );
    }
    newStyle.Setters.Add( setter );
}

Now we are able to design our UI thread separated control inline our main Xaml and also any FrameworkTemplates that are defined within.

XAML Serialization Limitations

I actually ran into another error when attempting to insert my custom UserControl into the UI thread separated Style’s template. It involved a ResourceDictionary duplicate key error. This problem absolutely dumbfounded me; not only in trying to understand why the same resource would try to be defined twice, but also how can there be duplicates on a newly created UI thread. After racking my head for hours to come up with a work around solution I eventually found out the direct cause of the error in question. It had to do with how the XamlWriter class serializes the given XAML tree. To give you an idea let’s say we have our ThreadSeparatedStyle defined like this:

<Style TargetType="{x:Type Control}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Control}">
                <Border Width="100" Height="50" VerticalAlignment="Bottom">
                    <Border.Resources>
                        <converters:ColorValueConverter x:Key="ColorValueConverter"/>
                    </Border.Resources>
                    <Border.Background>
                        <SolidColorBrush Color="{Binding Source='Black', Converter={StaticResource ColorValueConverter}}"/>
                    </Border.Background>
                    <TextBlock Text="Random Text" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

When Xaml.Save attempts to serialize the ControlTemplate here is our string result:

<ControlTemplate TargetType="Control"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:cpc="clr-namespace:Core.Presentation.Converters;assembly=Core"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Border Width="100" Height="50" VerticalAlignment="Bottom">
        <Border.Background>
            <SolidColorBrush Color="#FF000000" />
        </Border.Background>
        <Border.Resources>
            <cpc:ColorValueConverter x:Key="ColorValueConverter" />
        </Border.Resources>
        <TextBlock Text="Random Text" Foreground="#FFFFFFFF" HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Border>
</ControlTemplate>

Now, if we decided to wrap this into a UserControl, called RandomTextUserControl, it may look like this:

<UserControl x:Class="MultiUiThreadedExample.RandomTextUserControl"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:converters="clr-namespace:Core.Presentation.Converters;assembly=Core">
    <UserControl.Resources>
        <converters:ColorValueConverter x:Key="ColorValueConverter"/>
    </UserControl.Resources>
    <Border Width="100" Height="50" VerticalAlignment="Bottom">
        <Border.Background>
            <SolidColorBrush Color="{Binding Source='Black', Converter={StaticResource ColorValueConverter}}"/>
        </Border.Background>
        <TextBlock Text="Random Text" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White"/>
    </Border>
</UserControl>

When we replace our current XAML with this control we will receive the ResourceDictionary XamlParseException because it is trying to include ‘ColorValueConverter’ more than once. If we go back to our Xaml.Save result we will find our culprit:

<ControlTemplate TargetType="Control"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:mute="clr-namespace:MultiUiThreadedExample;assembly=MultiUiThreadedExample"
                 xmlns:cpc="clr-namespace:Core.Presentation.Converters;assembly=Core"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <mute:RandomTextUserControl>
        <mute:RandomTextUserControl.Resources>
            <cpc:ColorValueConverter x:Key="ColorValueConverter" />
        </mute:RandomTextUserControl.Resources>
        <Border Width="100" Height="50" VerticalAlignment="Bottom">
            <Border.Background>
                <SolidColorBrush Color="#FF000000" />
            </Border.Background>
            <TextBlock Text="Random Text" Foreground="#FFFFFFFF" HorizontalAlignment="Center" VerticalAlignment="Center" />
        </Border>
    </mute:RandomTextUserControl>
</ControlTemplate>

As you can see, XamlWriter.Save is actually including our parent level resources from RandomTextUserControl. This will cause duplication issue since it will attempt to add the resources displayed here plus the ones already defined inside RandomTextUserControl. The reason is because XamlWriter tries to keep the result self-contained. Meaning, the final result will be a single page XAML tree. Unfortunately, the process tends to add any referenced resources that may come from the overall application. This limitation, along with others, are actually documented by Microsoft. So, the solution here is to either put all your resources into the first content elements resources property or define the design of your control using a template, like this:

<UserControl x:Class="MultiUiThreadedExample.RandomTextUserControl"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:converters="clr-namespace:Core.Presentation.Converters;assembly=Core"
             xmlns:multiUiThreadedExample="clr-namespace:MultiUiThreadedExample">
    <UserControl.Template>
        <ControlTemplate TargetType="{x:Type multiUiThreadedExample:RandomTextUserControl}">
            <ControlTemplate.Resources>
                <converters:ColorValueConverter x:Key="ColorValueConverter"/>
            </ControlTemplate.Resources>
            <Border Width="100" Height="50" VerticalAlignment="Bottom">
                <Border.Background>
                    <SolidColorBrush Color="{Binding Source='Black', Converter={StaticResource ColorValueConverter}}"/>
                </Border.Background>
                <TextBlock Text="Random Text" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White"/>
            </Border>
        </ControlTemplate>
    </UserControl.Template>
</UserControl>

I actually prefer this method since it reduces an unnecessary ContentPresenter from being created and allows for more seamless TemplateBinding with the parent and Triggering.

WPF Round Table Part 2: Multi UI Threaded Control

Introduction

Click here to view the source code

Here are the past articles in the WPF Round Table Series:

In this series I want to express some of the knowledge I gained in WPF over the years when tackling unique situations. For today’s post though I would like to discuss something that was created quite recently after a brief discussion with coworkers about multi UI threaded controls. I always knew how to create a window on a separate UI thread, but what if you wanted a control to be part of a main window, yet have its own dispatcher message pump?

New Window UI

Well to start off we need to understand how to even spawn a new WPF supported UI thread. This article explains how to launch a window on a completely new UI thread. The creation process is actually quite simple as demonstrated in this code snippet:

Thread thread = new Thread(() =>
{
    Window1 w = new Window1();
    w.Show();
    w.Closed += (sender2, e2) =>
    w.Dispatcher.InvokeShutdown();
    System.Windows.Threading.Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

Here we start by simply creating a new thread which will host our new Window. Inside the thread we create a window and make sure the Dispatcher (which will get automatically created on demand for this thread when accessed) starts the message pump. We also handle shutting down the message pump on the window’s Closed event. At the end we set the thread’s ApartmentState to be single-threaded apartment (STA) rather than multithreaded partment (MTA) since WPF UI threads cannot be multithreaded. Once we start the thread we can see our new window now runs on its own UI thread.

Non-Interacting Host

Although a new window has its benefits, what if you want a UI independent control placed inside your main window? Well this MSDN articleexplains how this process can occur using a HostVisual class. The greatest benefit HostVisual provides is a way to arbitrarily connect any Visual to a parent visual tree. Unfortunately, there is not a way to fully measure, arrange, and render an item through a HostVisual without a presentation source. So we create our own presentation source which simply contains and displays our HostVisual to show in our window. Here is the main components of the class:

private readonly VisualTarget _visualTarget;
public VisualTargetPresentationSource( HostVisual hostVisual )
{
    _visualTarget = new VisualTarget( hostVisual );
    AddSource();
}
public override Visual RootVisual
{
    get
    {
        return _visualTarget.RootVisual;
    }
    set
    {
        Visual oldRoot = _visualTarget.RootVisual;
        // Set the root visual of the VisualTarget.  This visual will
        // now be used to visually compose the scene.
        _visualTarget.RootVisual = value;
        // Tell the PresentationSource that the root visual has
        // changed.  This kicks off a bunch of stuff like the
        // Loaded event.
        RootChanged( oldRoot, value );
        // Kickoff layout...
        UIElement rootElement = value as UIElement;
        if ( rootElement != null )
        {
            rootElement.Measure( new Size( Double.PositiveInfinity, Double.PositiveInfinity ) );
            rootElement.Arrange( new Rect( rootElement.DesiredSize ) );
        }
    }
}
protected override CompositionTarget GetCompositionTargetCore()
{
    return _visualTarget;
}

And running the sample project you can test this by toggling the busy indicator:

toggle

 

The main caveat with this method is that you are unable to interact with the control, which is fine for the purpose I want for this control. But even though I was able to create a control independent of the UI I still had issues positioning the thread separated control in relation to my main window.

Decorator with Child Elements

I managed to stumble upon another article that not only addressed the issue of alignment, but goes one step further by allowing the control to have child elements as well. I’ll include a ‘Child’ property along with a ‘ContentProperty’ attribute at the header of my class so that I can create UIElements right into XAML. Here is the logic that helps display our UI content onto a separate thread:

protected virtual void CreateThreadSeparatedElement()
{
    _hostVisual = new HostVisual();
    AddLogicalChild( _hostVisual );
    AddVisualChild( _hostVisual );
    // Spin up a worker thread, and pass it the HostVisual that it
    // should be part of.
    var thread = new Thread( CreateContentOnSeparateThread )
    {
        IsBackground = true
    };
    thread.SetApartmentState( ApartmentState.STA );
    thread.Start();
    // Wait for the worker thread to spin up and create the VisualTarget.
    _resentEvent.WaitOne();
    InvalidateMeasure();
}

Since we are creating a new HostVisual we need to make sure we define the parent-child relationship between the HostVisual and our UI control by calling ‘AddLogicalChild’ and ‘AddVisualChild’. Let’s take a look at how we are creating our UI content on a separate thread:

private void CreateContentOnSeparateThread()
{
    if ( _hostVisual != null )
    {
        // Create the VisualTargetPresentationSource and then signal the
        // calling thread, so that it can continue without waiting for us.
        var visualTarget = new VisualTargetPresentationSource( _hostVisual );
        _uiContent = CreateUiContent();
        if (_uiContent == null)
        {
            throw new InvalidOperationException("Created UI Content cannot return null. Either override 'CreateUiContent()' or assign a style to 'ThreadSeparatedStyle'");
        }
        _threadSeparatedDispatcher = _uiContent.Dispatcher;
        _resentEvent.Set();
        visualTarget.RootVisual = _uiContent;
        // Run a dispatcher for this worker thread.  This is the central
        // processing loop for WPF.
        Dispatcher.Run();
        visualTarget.Dispose();
    }
}

Here we can see us using our VisualTargetPresentationSource custom class to contain the HostVisual. The ‘CreateUiContent’ method is simply a protected virtual method that creates our content for us and can be overrided by inheriting classes. To make sure both our child content and the HostVisual is represented in our control we need to override the ‘VisualChildrenCount’, ‘LogicalChildren’, and ‘GetVisualChild’ methods to take both elements into account. Although this will allow for allow our content to render, our UI separated content will have measuring issues if the Child content has limited size or merely does not exist. To fix this we are going to override the ‘Measure’ and ‘Arrange’ methods like so:

protected override Size MeasureOverride( Size constraint )
{
    var childSize = new Size();
    var uiSize = new Size();
    if ( Child != null )
    {
        Child.Measure( constraint );
        var element = Child as FrameworkElement;
        childSize.Width = element != null ? element.ActualWidth : Child.DesiredSize.Width;
        childSize.Height = element != null ? element.ActualHeight : Child.DesiredSize.Height;
    }
    if ( _uiContent != null )
    {
        _uiContent.Dispatcher.Invoke( DispatcherPriority.Background, new Action( () => _uiContent.Measure( constraint ) ) );
        uiSize.Width = _uiContent.ActualWidth;
        uiSize.Height = _uiContent.ActualHeight;
    }
    var size = new Size( Math.Max( childSize.Width, uiSize.Width), Math.Max( childSize.Height, uiSize.Height) );;
    return size;
}
protected override Size ArrangeOverride( Size finalSize )
{
    if ( Child != null )
    {
        Child.Arrange( new Rect( finalSize ) );
    }
    if ( _uiContent != null )
    {
        _uiContent.Dispatcher.BeginInvoke( DispatcherPriority.Background, new Action( () => _uiContent.Arrange( new Rect( finalSize ) ) ) );
    }
    return finalSize;
}

As you can see I am treating our main parent control mostly like a panel where I either fill out the space given or take the max size of either my Child element or the size of the element on the separate thread.

Thread Separated Style

Although we have our ‘CreateUiContent’ method to instantiate our control from code, what if we want to create our control from a style right within XAML? Well we can create a DependencyProperty called ‘ThreadSeparatedStyle’, but the style itself must be instantiated on the new UI thread or else we’ll run into thread exceptions. In order to get around this issue we are going to recreate the style on the fly using reflection through an anonymous call. Here you can see how this occurs when the style changes:

private static void OnThreadSeparatedStyleChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
    var control = (UiThreadSeparatedControl)d;
    var style = e.NewValue as Style;
    if ( style != null )
    {
        var invokingType = style.TargetType;
        var setters = style.Setters.ToArray();
        control._createContentFromStyle = () =>
        {
            var newStyle = new Style
            {
                TargetType = invokingType,
            };
            foreach ( var setter in setters )
            {
                newStyle.Setters.Add( setter );
            }
            var contentt = (FrameworkElement)Activator.CreateInstance( newStyle.TargetType );
            contentt.Style = newStyle;
            return contentt;
        };
    }
    else
    {
        control._createContentFromStyle = null;
    }
}

Since I use the style’s target type to instantiate the control, the assigned target type in the style should not refer to a base control. I am also holding onto all the setter values for the style so they are preserved on recreation. Although I could avoid using reflection and recreating the style altogether by placing the style in a Themes defined folder Generic.xaml, by doing it this way it allows me to define the style at the same time I create the control:

<multi:UiThreadSeparatedControl IsContentShowing="{Binding ElementName=Toggle, Path=IsChecked}">
    <multi:UiThreadSeparatedControl.ThreadSeparatedStyle>
        <Style TargetType="multi:BusyIndicator">
            <Setter Property="IsBusy" Value="True"/>
        </Style>
    </multi:UiThreadSeparatedControl.ThreadSeparatedStyle>
</multi:UiThreadSeparatedControl>

The convenience of having this as an option seemed to outweigh trying to avoid reflection. Especially since it is much more intuitive to define your styles anywhere in XAML, not just UI independent resource dictionaries.

FrozenProcessControl

Now how could we use this type of control in our application? One scenario could be a case where you want to display a busy cursor if the window happens to freeze. Although it is quite a bad practice for your application to ever freeze. Usually this problem can be circumvented by offloading certain functionality onto a separate, non-UI thread. But sometimes you are left without a choice in the matter. For instance, say you are using a third party control that has become an integral part of your application and suddenly adding new, large amount of data causes the control to inefficiently load all its components on the UI thread. You may not have access to the controls source code or do not have time to replace the control. It would be a much better user experience to at least display something to the user to let it know some form of action is still happening rather than staring at a frozen screen. This is where our FrozenProcessControl comes into play.

At first we will extend our UiThreadSeparatedControl and override the ‘CreateUiContent’ method:

protected override FrameworkElement CreateUiContent()
{
    return new BusyIndicator
    {
        IsBusy = true,
        HorizontalAlignment = HorizontalAlignment.Center
    };
}

We will also have two Timers; one for polling the main window for no response, and another when the window is non-responsive for too long. Here is how our polling method is handled:

private void PollMainWindowTimerOnElapsed( object sender, ElapsedEventArgs elapsedEventArgs )
{
    _pollMainWindowTimer.Stop();
    _nonResponseTimer.Start();
    if ( _mainWindowProcess.Responding )
    {
        _nonResponseTimer.Stop();
        if ( _isContentDisplaying )
        {
            _isContentDisplaying = false;
            _threadSeparatedDispatcher.BeginInvoke( DispatcherPriority.Render, new Action( () =>
            {
                _uiContent.Visibility = Visibility.Hidden;
                _pollMainWindowTimer.Start();
            } ) );
        }
        else
        {
            _pollMainWindowTimer.Start();
        }
    }
}

As you can see we immediately start our non-responsive timer because if the main window’s process is unable to respond, accessing the process will cause the thread to freeze until activity happens again. If we do happen to gain response again and our busy indicator is displaying we need to update its visibility using its UI thread dispatcher to access the separate UI thread. Here we can see how our non-response timer is handled:

private void NonResponseTimer_Elapsed( object sender, ElapsedEventArgs e )
{
    _pollMainWindowTimer.Stop();
    _nonResponseTimer.Stop();
    _isContentDisplaying = true;
    _threadSeparatedDispatcher.BeginInvoke( DispatcherPriority.Render, new Action( () =>
    {
        _uiContent.Visibility = Visibility.Visible;
    } ) );
}

This is pretty straight forward, if the poll timer is frozen from accessing the process we do not want any further events to happen until the window is active again. After that we update the visibility using the separate UI thread to show our busy indicator. Here we can see the control in action in our demo by hitting the Freeze button, viewing the busy indicator on the far right freeze, and then suddenly seeing our thread separated control run on top:

frozen

 

Conclusion

Overall, this is quite a useful control, but the major caveat to using this is there is no ability to accept user input. Other than that this could easily help offload the build time for certain, display-only controls.

WPF Round Table Part 1: Simple Pie Chart

Introduction

Click here to view source code

Over the years I have been presented with many different situations while programming in WPF, which required a certain Control or class to be created to accommodate. Given all the various solutions I created throughout the years I thought it might be helpful to someone else. During this ongoing series I am going to post some of the more useful classes I have made in the past.

Simple Pie Chart

In one project I was assigned to redesign, there was data coming in that we wanted represented in the form of a pie chart. Initially, we simply displayed the information in the form of one out of many static pie chart images. A specific image would get selected based on what the percentage was closest. Although this solved our immediate needs I believed generating this with GeometryDrawing would make the chart much more accurate and should not be too difficult to create. My immediate goal was to try and represent some type of pie chart in XAML to get an idea of how it could be represented dynamically. Initial searching led to this solution involving dividing a chart into thirds. Following the example given will produce a subdivided geometric ellipse:

Pie-Chart-Example-1

Programmatically Build Chart

Unfortunately, using strictly XAML will not work when attempting to create a pie chart dynamically. This is definitely a great starting point in how we could create this Control, but I needed a better understanding how to create geometric objects programmatically. Doing some more searching I came across this Code Project that describes how to create pie charts from code. My pie chart will be much simpler containing only two slices and taking in a percentage value to represent how the slices will subdivide. I still use an Image to represent how the geometry will be drawn and begin the creation of the root elements:

_pieChartImage.Width = _pieChartImage.Height = Width = Height = Size;
var di = new DrawingImage();
_pieChartImage.Source = di;
var dg = new DrawingGroup();
di.Drawing = dg;

Since I know my starting point of the pie will always be at the top I then calculate where my line segment will end (the PieSliceFillers are brushes representing the fill color):

var angle = 360 * Percentage;
var radians = ( Math.PI / 180 ) * angle;
var endPointX = Math.Sin( radians ) * Height / 2 + Height / 2;
var endPointY = Width / 2 - Math.Cos( radians ) * Width / 2;
var endPoint = new Point( endPointX, endPointY );
dg.Children.Add( CreatePathGeometry( InnerPieSliceFill, new Point( Width / 2, 0 ), endPoint, Percentage > 0.5 ) );
dg.Children.Add( CreatePathGeometry( OuterPieSliceFill, endPoint, new Point( Width / 2, 0 ), Percentage <= 0.5 ) );

My CreatePathGeometry method creates both the inner and outer pie slices using a starting point, the point where the arc will end, and a boolean for ArcSegment to determine how the arc should get drawn if greater than 180 degrees.

private GeometryDrawing CreatePathGeometry( Brush brush, Point startPoint, Point arcPoint, bool isLargeArc )
{
    var midPoint = new Point( Width / 2, Height / 2 );
    var drawing = new GeometryDrawing { Brush = brush };
    var pathGeometry = new PathGeometry();
    var pathFigure = new PathFigure { StartPoint = midPoint };
    var ls1 = new LineSegment( startPoint, false );
    var arc = new ArcSegment
    {
        SweepDirection = SweepDirection.Clockwise,
        Size = new Size( Width / 2, Height / 2 ),
        Point = arcPoint,
        IsLargeArc = isLargeArc
    };
    var ls2 = new LineSegment( midPoint, false );
    drawing.Geometry = pathGeometry;
    pathGeometry.Figures.Add( pathFigure );
    pathFigure.Segments.Add( ls1 );
    pathFigure.Segments.Add( arc );
    pathFigure.Segments.Add( ls2 );
    return drawing;
}

A better to visualize this is through a XAML representation:


<GeometryDrawing Brush="@Brush">
 <GeometryDrawing.Geometry>
   <PathGeometry>
     <PathFigure StartPoint="@Size/2">
       <PathFigure.Segments>
         <LineSegment Point="@startPoint"/>
         <ArcSegment Point="@arcPoint" SweepDirection="Clockwise" Size="@Size/2"/>
         <LineSegment Point="@Size/2"/>
       </PathFigure.Segments>
     </PathFigure>
   </PathGeometry>
 </GeometryDrawing.Geometry>
</GeometryDrawing>

And with that we are able to create quick an easy pie charts as shown here:

Pie-Chart-Example-2

Multi Pie Chart

Although this is suitable for a two sided pie chart, but what if you wanted more? That process is pretty straight forward based off what we already created. By including two dependency properties to represent our collection of data and brushes, we only need to rewrite how my segments are created:

var total = DataList.Sum();
var startPoint = new Point( Width / 2, 0 );
double radians = 0;
for ( int i = 0; i < DataList.Count; i++ ) {     var data = DataList[i];     var dataBrush = GetBrushFromList( i );  var percentage = data / total;  Point endPoint;     var angle = 360 * percentage;   if ( i + 1 == DataList.Count )  {       endPoint = new Point( Width / 2, 0 );   }   else    {       radians += ( Math.PI / 180 ) * angle;       var endPointX = Math.Sin( radians ) * Height / 2 + Height / 2;      var endPointY = Width / 2 - Math.Cos( radians ) * Width / 2;        endPoint = new Point( endPointX, endPointY );   }   dg.Children.Add( CreatePathGeometry( dataBrush, startPoint, endPoint, angle > 180 ) );
    startPoint = endPoint;
}

As you can see, the main difference is now we are accumulating the radians as we traverse the list to take into account any number of data objects. The result allows us to add any number of data items to our pie chart as shown here:

Pie-Chart-Example-3

Conclusion

Although I did not get as much use for this class as I would have preferred, developing this helped me gain experience in manipulating geometry objects, which does not happen often enough.

 

Text On A Path With Alignment

Click here to view the source code

In past WPF projects, design specifications given by artists are sometimes challenging to attempt to implement. One scenario I have ran into multiple times was trying to display custom text around a curved object. Most of the time this problem was avoided by the artist providing the content as images, but, fortunately, this was only feasible because the text was finite and static. Recently I came across this same scenario again except this time the incoming text could be dynamic. The immediate reaction was to simply read the text as images stored in a folder provided by the customer. This solution tends to create problems in the future because:

  • The user must be familiar with some image editing tool
  • If not accustomed to any, then the user has to be trained
  • The user must be aware of the exact font, weight, and color the artist intended
  • The user must also have the same eye for lining up text as the original artist intended (which many tools can aid in)

With all these issues, it would be better to assume that if a user could get something wrong then they will, which will result in an application that seems off. Not happy with this path I decided to look into creating text on a path.

Fortunately, a majority of the work had already been developed by Charles Petzold described in his article Render Text On A Path With WPF.

The article provides a comprehensive description of his algorithm for placing text on a path. It is worth a read to get an in-depth understanding of how the algorithm works. To try and sum it up though, the algorithm uses a PathFigure object to shape the path the text will render and the class comes equipped with a method to help simplify calculations. In sizing the text font onto the path, the text is scaled to fit entirely on the length of the path. For the best performance, we render the text as DrawingVisual objects so they only need to be created once when the text changed. The result comes out as this:

Result1

 

Fantastic! This worked well for what I wanted, except for one problem; the text scaling. I knew the path I wanted my text to render, but not the length of the text since that could change dynamically. When attempting to apply this algorithm to a path I had in mind, the results were less than pleasing (red curve represents the path for the text):

Result2

 

I needed the text to render the same size despite the length of the path, but the current algorithm would require me to resize the path dynamically based on the size of the text. This did not seem reasonable, especially since I would prefer the text to rest on the center of the path.

So, in order to accomplish this the first thing I needed was a Dependency Property of type HorizontalAlignment to set the content alignment. Setting the alignment to Stretch will keep the original behavior of the algorithm by resizing the text to fit the path. Then we need another Dependency Property for font size, which will only get applied if the content alignment was not Stretch. Now, when calculating the text length we need to substitute our font size over the default 100

private void OnTextPropertyChanged()
{
    _formattedChars.Clear();
    _textLength = 0;
    if (!String.IsNullOrEmpty(Text))
    {
        foreach (char ch in Text)
        {
            var fontSize = ContentAlignment == HorizontalAlignment.Stretch ? 100 : FontSize;
            var formattedText =
                new FormattedText(ch.ToString(), CultureInfo.CurrentCulture,
                    FlowDirection.LeftToRight, _typeface, fontSize, Foreground);
            _formattedChars.Add(formattedText);
            _textLength += formattedText.WidthIncludingTrailingWhitespace;
        }
        GenerateVisualChildren();
    }
}

Then we move onto our TransformVisualChildren method and make sure the scaling factor stays at 1 since we no longer want the text to rescale to the path

private void TransformVisualChildren()
{
    ...
    var scalingFactor = ContentAlignment == HorizontalAlignment.Stretch ? _pathLength / _textLength : 1;
    ...
}

Since content alignment can be set as Center, or Right aligned, the initial progress will need adjusting to push the text further along the path

private void TransformVisualChildren()
{
    ...
    double progress = 0;
    switch (ContentAlignment)
    {
        case HorizontalAlignment.Left:
        case HorizontalAlignment.Stretch:
            progress = 0;
            break;
        case HorizontalAlignment.Center:
            progress = Math.Abs(_pathLength - _textLength) / 2 / _pathLength;
            break;
        case HorizontalAlignment.Right:
            progress = Math.Abs(_pathLength - _textLength) / _pathLength;
            break;
    }
    ...
}

And that is all we have to do since the scaling factor will be set to 1 if content is not stretched. Here is the result with content alignment set to Center. Also, you can see all the various alignments applied:

Result31

 

Although I was very satisfied with the results, a change in the scope of our project made this solution obsolete. Just another day in the life of a programmer.