Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Building High Performance WPF/E Enterprise Class Application in C# 4.5

0.00/5 (No votes)
3 Jun 2012 4  
An in-depth reference of how to build performance-oriented applications in WPF for both Windows and the Web.

Preface

This article provides an in-depth reference of how to build performance-oriented applications in WPF for both Windows and the Web. This article talks about all major aspects with examples, including design pattern trade-offs, multi-threading, WCF Service calls (client server architecture or /smart Client Model), managing memory, parallelism, etc., which are a must to start building an enterprise class application from scratch.

Contents

  • Overview.
  • Introduction.
  • WPF/E or Silverlight 
  • Factors need to considered for enterprise class application with WPF/Silverlight
    1. WPF Programming Model.
    2. Initial Architecture.
    3. KSmart pattern for WPF.
    4. Model Layer implementation.
  • Advance Memory Management.
    1. Caching objects.
    2. Weak References.
  • Garbage Collection. 
    1. Unmanaged Objects.
  • Asynchronous Programming.
    1. Dispatcher.
      1. Using the Dispatcher.
      2. Updating the UI.
      3. Updating the UI Asynchronously.
    2. 2.       Background Worker.
      1. Using Background Worker in WPF. 
  • Binding.
    1. Direction of Data Flow.
    2. What Triggers Source Updates.
  • Page and Navigation.
    1. Refreshing the current Page.
    2. Navigation Lifetime.
  • Programming Guidelines for Improving Performance.
  • Conclusion. 

Overview

This article provides in-depth reference on how to build WPF applications which is targeted for high performance and still will work similar to Silverlight or any other third party plug-ins for browser.  This article also targets on the common mistake developer or architects do in choosing design patterns, implementing multi-threading or making WCF Service calls in building smart client applications. This also discuss key design issues which end in large memory consumptions, decreasing application performance, resolution issue, Managing user sessions, Parallelism etc.

This concept applies to WPF, WPF running in client (XBAP), Silverlight, all applications which sticks onto the concept of WPF.

Introduction

Today large numbers of developers are switching to WPF, XBAP or Silverlight due to level of flexibility it offers in building applications. Now Microsoft has stopped its updates on the windows control from .NET 4.0 and is focusing completely on to WPF. This helps to build Jazzy applications which current industry needs. Microsoft has added numerous enhancements to WPF 4.5 or Silverlight 5, which helps to build enterprise class applications seamlessly on Windows and Web, which can be deployed over windows/Web with little or no change.

A large number of cool features with WPF/Silverlight, from which developers can easily debug UI, create more stable applications which target both Windows/Web.

It becomes extremely important for the designer to understand the framework, memory, parallelism and other aspects to build advanced applications with WPF/E or Silverlight.

WPF/E or Silverlight

The WPF/E refers to Windows presentation foundation – Everywhere and also Silverlight are the next generation UI development platforms for the .NET developers. Microsoft is unifying the development tools which makes possible to build apps, with these tools which targets desktop, laptops, touch-pads, mobile, all kind of devices with same kind of UI with WPF.

In few years most of the applications build on windows OS targeted to both web and windows will be with WPF and Silverlight. The WPF being extremely rich in UI, with new style of development can become extremely complex and pose several issues to designers and developers including memory leakage, large performance pitfalls, and huge memory consumptions.

In today’s world as many users utilizing network bandwidth in data basis, it becomes extremely important for the developers and designer to concentrate more on lower bandwidth consumption. If not given proper importance this can become trivial issue and can affect the whole network and make applications unusable in the enterprise.

Factors need to considered for enterprise class application with WPF/Silverlight

There are various factors that need to consider while building enterprise class applications in WPF. It’s very important to understand WPF architecture at the initial stage on how WPF application runs in the windows operating system.

WPF Programming Model

WPF programming happens in the managed code. The WPF becomes more robust, stabilized when running through the managed code as the CLR provides number of features that makes development productive (including memory management, CTS etc) which comes with a cost.

The WPF architecture is as illustrate below:

The red sections of the diagram are the code portion of the WPF which includes Presentation Framework, Presentation Core, and milcore. These are the code portion of the WPF. There is one unmanaged component milcore.  This is directly coupled with DirectX Engine; all display happening through WPF is through DirectX engine which make effective hardware and software rendering and make the application looks Jazzy.

Initial Architecture 

The architecture consideration for the WPF is extremely important in building WPF/Silverlight applications, this determines the performance, it’s possible to build applications which are highly robust than web applications, consumes less bandwidth compared to ASP.NET,  low memory intensive and can take advantage of hardware acceleration to deliver high quality graphics through the web. The XBAP application running in full trust can run outside the browser sandbox and can take the advantage of hardware which is impossible in ASP.NET or any other web technologies offers without plug-ins which need to be separately installed on the client.

Since .NET framework is shipped with windows operating systems with windows server 2003 hosting .NET framework 1.1, Vista hosting .NET 3.0, Windows 7 with .NET 3.5, Windows 8 and server 2008 hosting .NET 4.0, it is possible that all applications demand .NET framework as it remain only model for building next generation applications in Windows.

Windows 8 supporting metro-style applications, the application becomes very powerful and capable of providing high end graphics, high quality UI, which can be run on variety of platform like Windows, web, touch pads, laptops, mobiles , all with same or little code change when building applications on WPF, which becomes ideal platform for all developers.

Considering the initial architecture, WPF provides various programming model like MVVM (Model View View Model) being the most famous one, MEF (Manage extensibility framework), PRISM which embeds MVVM design, MVP etc.

The MVVM is coined based on various other design patterns of its predecessor like MVP (Model view presenter), MVC (Model View Controller). The MVC is a design pattern which is coined on Ruby on Rails development which became extremely popular and has been adapted extensively in ASP.NET applications which provides new platform for the development.

Note: The main point what I want to highlight here is these design pattern, though several website indicates these are the design patterns which provides enormous benefits while building enterprise class application, most of the designers or developers intend to follow the pattern as most WPF applications falling under MVVM or PRISM and few built on MVC, MVP or MEF frameworks.

The detail descriptions of these architecture are beyond the scope of this article, I am trying to say based on my experience in developing more than 20 Application across 6 companies with around 15+ clients, these architectures makes extremely cumbersome for the development and leads to various flaw in the development and can lead to various problems which expects only expert developers to work for implementation, implementing unwanted commands, makes cumbersome to pass events argument to the function, decreasing performance, increasing memory consumption and also increase in network bandwidth.

However, I am not pointing against this, but will be required only in certain kind of development and should not be usual choice for developers and designers.

These add lots of additional complexity in development more than resolving issues and also make application unusable in the production.

The MVVM has the following architecture:

The User general Choice for developers will be using is PRISM design patterns which has MVVM in-built for application development. This architecture has View Layer which is usually a presentation layer or UI, The PRISM or MVVM design pattern indicates there will be no .cs file for XAML.

This can become more cumbersome for the developers as there will be no .xaml.cs file and all the events are to be pushed to View Model as methods, and also for the events which requires complex parameters it becomes extremely difficult for the developers especially who are switching from ASP.NET and doesn’t bring any additional benefits, this can be helpful when UI developers develop in Expression Blend and use in .NET by developers. This however adds additional complexity and majority of the project involves developers to be involved in UI development and can become extremely cumbersome for those.

It’s possible to attach ICommand objects than delegate commands and can be done without PRISM or MVVM.

The MVVM architecture expects all calls from model to service in Async patterns, this may look beneficial at the outer look, but this raises lot of overhead and complexity in application development, Since the service calls are async it’s possible to trigger multiple service calls at one shot, but results are to be captured in Completed event. (This supports only CallBack functionality on remote service with normal configurations).

For example, consider you were filling employee history in the form from database which has multiple service calls, till all the service call happens the UI should be blocked, in this case it very difficult to manage in async programming in CallBack fashion.

The Calculator service demonstrated below represents the scenario:

public void Add()
{
    MathClient.AddAsync();
}
Public void Sub()
{
    MathClient.SubAsync();
}
public void Add_Completed(object sender, EventArgs e)
{
    //Process Result
} 
Public void Sub_Completed(object sender, EventArgs e)
{
    //Process Result
}
Colourised in 6ms

In the above code which returns the result first and which returns result last, the developers will not be able to predict, it will be hard to block the UI thread till all results are returned. Hard to synchronize all items. It will be very difficult to dispose service. The services have the inner Channel which is unmanaged and need to be dispose or else memory consumption will be high. There are many instance we see where Silverlight or WPF application hangs the UI, which makes the application very unfeasible at the production.

The service call has to be made in synchronous fashion to avoid all these issues.

Since almost all the code have delegates and events, it consumes more memory, long processing time, and since everything is asynchronous here it can lead to instability in the code, which has to be addressed.

There are chances that same service is called many times, causing unnecessary roundtrip to the server, may also impact on the bandwidth, where you see only data-transfer consumes more memory than web applications, the performance will also have an impact, causing long time to update UI.

KSmart pattern for WPF

Here by I present my custom design pattern which solves most of the problems incurred in WPF development, by making application development easier, keeping low memory, increased stability, increased performance, lesser network bandwidth.

The detail of the KSmart pattern will be presented separately in-detail in another code project article, which contains comparisons of various design patterns with KSmart pattern.

 

 

 


The Ksmart pattern has view, which generally contains presentation logic for the UI. The controller can be .xaml.cs or can be viewmodel or combination of both, this contains code for binding data, handling events etc. All processing logic will be done by business layer and layer can be shared across different controllers. Model contains code for making service calls, disposing service after its use. The service contains WCF Services for model calls. Business layer at the service handles all the business logic at server side. The DAL will make call to the Database and return result to business Layer.

The service interface and data contract project will be share across all layers and will have flexibility to type cast to service, or service disposal in another layer and also data is share across through data contracts in the application.

This design pattern provides greater flexibility in implementing effective code for WPF/E or Silverlight.

Model Layer implementation

Even though the model layer provides service interface to WCF client, this will be the key component in improving performance, providing better memory management, reducing network bandwidth.

Let see how model layer improves overall performance of the application. The model layer make calls to WCF layer, it’s possible than model layer can make async calls for set of operations in WCF, whose results are required parallel, the model layer can wait till all of it returns result thus enhancing performance of the application and still returns result in synchronous style to the business layer.

Its responsible for better memory management, the memory has to release as it make use of unmanaged channel for communication, once result is returned, the service should be disposed.

public class CustomerModel
{
    public int Add()
    {
        using (CalcService service = new CalcService())
        {
            return service.Add();
        }
    }
    public int Sub()
    {
        using (CalcService service = new CalcService())
        {
            return service.Sub();
        }
    }
}
Colourised in 6ms

In the above code the service is created, the call to service is made, and service is disposed. This kind of code provides large memory reductions, make WPF/Silverlight applications healthier and perform better, which is must in WCF.

CalcService is wrapper, which interns takes care of opening channel and returning service.

This is very critical to application performance, better memory management and reduces network bandwidth. As compared to:

public void Add()
{
    MathClient.AddAsync();
}
Public void Sub()
{
    MathClient.SubAsync();
}
public void Add_Completed(object sender, EventArgs e)
{
    //Process Result
} 

Public void Sub_Completed(object sender, EventArgs e)
{
    //Process Result
}
Colourised in 4ms

Here, it very hard to dispose objects, hard to maintain synchronization among objects consumes more memory, bandwidth and hinders performance as everything is based on delegates and events.

Advance Memory Management

Caching objects

Keep all the objects like view Model objects, Model objects, business objects, static objects etc.. in a centralized Cache. Disposing centralized cache can promote greater memory reductions.

Microsoft provides built-in Cache in .NET runtime, but I recommend strongly not to use it, because if there are exceptions cache is invalidated automatically. Beside it will be hard time to remove all the cache items during session timeout, applications sign-out, reloading new controls etc. The Cache has to be invalidated during all these times.

The custom light weight, application specific cache looks like below:

public class ApplicationCache
{
    Dictionary<string, object> CentralCache = new Dictionary<string, object>();

    public void Add(string key, object Value)
    {
        if (!CentralCache.ContainsKey(key))
        {
            CentralCache.Add(key, Value);
        }
    }

    public object GetItem(string key)
    {
        if (CentralCache.ContainsKey(key))
        {
            return CentralCache[key];
        }
        return null;
    }
    static ApplicationCache cache = null;
    public static ApplicationCache CreateInstance()
    {
        if(cache == null)
        {
            return new ApplicationCache();
        }
        return cache;
    }
}
Colourised in 9ms

In this, assigning null to cache will invalidate the whole cache, and programmer has more control on cache and will not be invalidated automatically during exceptions.

Use this Cache similar to WeakReference. Like keeping objects in weak reference, maintain the object in this cache, which provide more benefits,

Weak Reference

Avoid keeping objects in WeakReference as at any time the object may be removed by garbage collection and reference will be destroyed automatically.

Garbage Collection

It’s very important to understand, how garbage collection works, to build high performance, low memory intensive applications, which stands good after production. All managed objects in .NET will be held in Managed Heap, there will be no information on what the size of managed heap is or when the garbage collection is triggered. It’s always good to trigger garbage collection at regular intervals or an actions like Changing the Navigation, application Sign-out, Session timeout etc.

Garbage collection happens on two types of objects:

Strong reference objects, by default all objects are of strong reference, the Garbage Collector requires the objects to be explicitly marked for collection.

ApplicationCache cache = new ApplicationCache();
object item = cache.GetItem("itemKey");
cache = null;
GC.Collect();
Colourised in 1ms

WeakReference objects, which are automatically picked up by the garbage collector. These objects need not to be marked explicitly and these are short lived objects.

class Program
{
    static void Main(string[] args)
    {
        WeakReference refe = new WeakReference(new Test());
        //test.Display("123");            
        GC.Collect();
        //test.Display("123");
        Console.WriteLine(refe.IsAlive);
        Console.Read();

    }
}
Colourised in 5ms

In the above code the refe.IsAlive prints False, as the object is wiped by the Garbage Collector. One has to see the proper trade-off between them before implementing a solution.

Unmanaged objects

The objects which performs the operation and doesn’t contains managed code, like FileStream objects, DataSet, DataTable, ComObjects, WCF service objects,  Channel objects, SQL connection objects, Command objects, windows GDI objects etc. requires manually Dispose those objects for memory cleanups.

It’s important to understand that these unmanaged objects consume large amount of memory and ignoring to dispose these objects can result in large memory leakage in the production, user can experience these while development also.

All the above mentioned objects, except ComObjects has Dipose() interface, which can be called after its use. The using block can be used and recommended for this kind of scenario. The following code demonstrates the same:

class Program
{
    static void Main(string[] args)
    {
        DataSet ds = null;
        using (SqlConnection conn = new SqlConnection())
        {
            //Open the connection
            using (SqlCommand comm = new SqlCommand())
            {
                //Command code here
                //Excecute the command
            }
            ds.Dispose();
        }
    }
}
Colourised in 8ms

In the above code all the unmanaged code like connection, command are embedded in using block and disposed automatically after going out of the scope.  The ds of type DataSet is disposed by calling dispose interface.

The COM objects can be disposed as shown below:

while (Marshal.ReleaseComObject(comObject) > 0){}
Colourised in 0ms

The COM objects are wrapped inside Callable Wrapper. The Runtime Callable Wrapper has reference count every time COM interface pointed to it. The ReleaseComObject method decrements the reference count of runtime callable wrapper, if there are more than one reference then this method decrements and return the number of remaining references.

To ensure runtime callable wrapper and the original COM objects are released, the loop should be constructed until the return reference count is a zero.

Asynchronous Programming

Asynchronous programming has both Advantages and Disadvantages. However we can convert disadvantages to advantages if we properly use them, otherwise this can become more cumbersome to program or manage, cause instability in the application, take longer processing time, can consume more bandwidth and make application almost not usable in the production.

The Calculator service demonstrated below represents the scenario:

public void Add()
{
    CalcModel.Add();
}
Public void Sub()
{ 
    CalcModel.Sub();
}
public void Add_Completed(object sender, EventArgs e)
{
    //Process Result
} 
Public void Sub_Completed(object sender, EventArgs e)
{
    //Process Result
}
Colourised in 5ms

The call is made as below:

CalcViewModel.Add();
CalcViewModel.Sub();
Colourised in 0ms

In the above code which returns the result first and which returns result last, the developers will not be able to predict, it will be hard to block the UI thread till all results are returned. Hard to synchronize all items. It will be very difficult to dispose service. The services have the inner Channel which is unmanaged and need to be dispose or else memory consumption will be high. There are many instance we see where Silverlight or WPF application hangs the UI, which makes the application very unfeasible at the production.

The same implementation with Async and Await keywords, available in .NET 4.5, or Async CTP for 2010.

public int Task<int> Add(int a, int b)
{
    return CalcModel.Add(a, b);
}
public int Task<int>Sub(int a, int b)
{ 
    return CalcModel.Sub(a, b);
}
Colourised in 3ms

The call made as below:

int res = await CalcViewModel.Add();
int res1 = await CalcViewModel.Sub();
Colourised in 0ms

This bridges the gap between asynchronous and synchronous programming and returns the result in efficient fashion, and also addresses all the problems stated above.

Dispatcher

WPF run on multi-threaded apartment, since there are multi-threads running it’s very easy to get into situation of deadlocks, concurrency management is trivial of WPF applications. Most objects in WPF derive from DispatcherObject. WPF is based on messaging system implemented by the Dispatcher.  This is very similar to Win32 message pumps.

There are two main things with respect to concurrency in WPF.

  • Dispatcher
  • Thread Affinity

The Dispatcher class is used to perform work on his attached thread. It has a queue of work items and it is in charge of executing the work items on the dispatcher thread.

Almost every WPF element has thread affinity. This means that access to such an element should be made only from the thread that created the element. In order to do so, every element that requires thread affinity is derived, eventually, from DispatcherObject class. This class provides a property named Dispatcher that returns the Dispatcher object associated with the WPF element.

If you want to make Async calls you should only make using:

Dispatcher.CurrentDispatcher.BeginInvoke(
....
);
Colourised in 0ms

i.e. only through dispatcher otherwise get runtime errors, that thread Id is different from thread which updated it.

Dispatchers object hierarchy:

In the above we can see all objects are derived from dispatcher object and handles concurrency in more effective way.

Using the Dispatcher

The Dispatcher class provides a gateway to the message pump in WPF and provides a mechanism to route work for processing by the UI thread. This is necessary to meet the thread affinity demands, but since the UI thread is blocked for each piece of work routed through the Dispatcher, it is important to keep the work that the Dispatcher does small and quick. It is better to break apart larger pieces of work for the user interface into small discrete blocks for the Dispatcher to execute. Any work that doesn't need to be done on the UI thread should instead be moved off onto other threads for processing in the background.

Typically you will use the Dispatcher class to send worker items to the UI thread for processing. For example, if you want to do some work on a separate thread using the Thread class, you could create a ThreadStart delegate with some work to do on a new thread as shown below.

Updating UI with Non-UI Thread—The Wrong Way
// The Work to perform on another thread
ThreadStart start = delegate()
{
    // ...

    // This will throw an exception 
    // (it's on the wrong thread)
    statusText.Text = "From Other Thread";
};

// Create the thread and kick it started!
new Thread(start).Start();
Colourised in 5ms

This code fails because setting the Text property of the statusText control (a TextBlock) is not being called on the UI thread. When the code attempts to set the Text on the TextBlock, the TextBlock class internally calls its VerifyAccess method to ensure that the call is coming from the UI thread. When it determines the call is from a different thread, it throws an exception. So how can you use the Dispatcher to make the call on the UI thread?

The Dispatcher class provides access to invoke code on the UI thread directly. The below shows the use of the Dispatcher's Invoke method to call a method called SetStatus to change the TextBlock's Text property for you.

Updating the UI
// The Work to perform on another thread
ThreadStart start = delegate()
{
  // ...

  // Sets the Text on a TextBlock Control.
  // This will work as its using the dispatcher
  Dispatcher.Invoke(DispatcherPriority.Normal, 
                    new Action<string>(SetStatus), 
                    "From Other Thread");
};
// Create the thread and kick it started!
new Thread(start).Start();
Colourised in 4ms

The Invoke call takes three pieces of information: the priority of the item to be executed, a delegate that describes what work to perform, and any parameters to pass into the delegate described in the second parameter. By calling Invoke, it queues up the delegate to be called on the UI thread. Using the Invoke method ensures that you are going to block until the work is performed on the UI thread.

As an alternative to using the Dispatcher synchronously, you can use the BeginInvoke method of the Dispatcher to asynchronously queue up a work item for the UI thread. Calling the BeginInvoke method returns an instance of the DispatcherOperation class that contains information about the execution of the work item, including the current status of the work item and the result of the execution (once the work item has completed). The use of the BeginInvoke method and the DispatcherOperation class is shown below.

Updating the UI Asynchronously
// The Work to perform on another thread
ThreadStart start = delegate()
{
    // ...

    // This will work as its using the dispatcher
    DispatcherOperation op = Dispatcher.BeginInvoke(
        DispatcherPriority.Normal, 
        new Action<string>(SetStatus), 
        "From Other Thread (Async)");
    
    DispatcherOperationStatus status = op.Status;
    while (status != DispatcherOperationStatus.Completed)
    {
        status = op.Wait(TimeSpan.FromMilliseconds(1000));
        if (status == DispatcherOperationStatus.Aborted)
        {
            // Alert Someone
        }
    }
};

// Create the thread and kick it started!
new Thread(start).Start();
Colourised in 9ms

Background Worker

There are many instances, where developer encounters taking long time to update UI, for example moving from login screen to application or clicking on menu opens the particular module or screen. It takes long time if amount of data to be displayed to be huge or have complex graphics to be displayed.

In WPF, it’s very easy to handle these components through Background worker, for better UI responsiveness and fast loading on the screen so that user doesn’t see the delay.

Now that you have a sense of how the Dispatcher works, you might be surprised to know that you will not find use for it in most cases. In Windows Forms 2.0, Microsoft introduced a class for non-UI thread handling to simplify the development model for user interface developers. This class is called the BackgroundWorker. The below shows typical usage of the BackgroundWorker class.

Using a BackgroundWorker in WPF
BackgroundWorker _backgroundWorker = new BackgroundWorker();

...

// Set up the Background Worker Events
_backgroundWorker.DoWork += _backgroundWorker_DoWork;
backgroundWorker.RunWorkerCompleted += 
    _backgroundWorker_RunWorkerCompleted;

// Run the Background Worker
_backgroundWorker.RunWorkerAsync(5000);

...

// Worker Method
void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    // Do something
}

// Completed Method
void _backgroundWorker_RunWorkerCompleted(
    object sender, 
    RunWorkerCompletedEventArgs e)
{
    if (e.Cancelled)
    {
        statusText.Text = "Cancelled";
    }
    else if (e.Error != null) 
    {
        statusText.Text = "Exception Thrown";
    }
    else 
    {
        statusText.Text = "Completed";
    }
}
Colourised in 8ms

The BackgroundWorker component works well with WPF because underneath the covers it uses the AsyncOperationManager class, which in turn uses the SynchronizationContext class to deal with synchronization. In Windows Forms, the AsyncOperationManager hands off a WindowsFormsSynchronizationContext class that derives from the SynchronizationContext class. Likewise, in ASP.NET it works with a different derivation of SynchronizationContext called AspNetSynchronizationContext. These SynchronizationContext-derived classes know how to handle the cross-thread synchronization of method invocation.

In WPF, this model is extended with a DispatcherSynchronizationContext class. By using BackgroundWorker, the Dispatcher is being employed automatically to invoke cross-thread method calls. The good news is that since you are probably already familiar with this common pattern, you can continue using BackgroundWorker in your new WPF projects.

Binding

In WPF, as being one of the rich clients has huge graphics to display and takes more, since today ppl. Are using advance systems it’s not major concern. But if we attach manually all the data and update UI, will be most critical factor and will have large impact on the performance, this can also be one of the major factor for WPF. One should note that in WPF almost all the UI stuffs has to be updated on the binding for better performance.

This section contains the following subsections.

Typically, each binding has these four components: a binding target object, a target property, a binding source, and a path to the value in the binding source to use. For example, if you want to bind the content of a TextBox to the Name property of an Employee object, your target object is the TextBox, the target property is the Text property, the value to use is Name, and the source object is the Employee object.

The target property must be a dependency property. Most UIElement properties are dependency properties and most dependency properties, except read-only ones, support data binding by default. (Only DependencyObject types can define dependency properties and all UIElements derive from DependencyObject.)

Although not specified in the figure, it should be noted that the binding source object is not restricted to being a custom CLR object. WPF data binding supports data in the form of CLR objects and XML. To provide some examples, your binding source may be a UIElement, any list object, a CLR object that is associated with ADO.NET data or Web Services, or an XmlNode that contains your XML data. For more information, see Binding Sources Overview.

As you read through other software development kit (SDK) topics, it is important to remember that when you are establishing a binding, you are binding a binding target to a binding source. For example, if you are displaying some underlying XML data in a ListBox using data binding, you are binding your ListBox to the XML data.

To establish a binding, you use the Binding object. The rest of this topic discusses many of the concepts associated with and some of the properties and usage of the Binding object.

Direction of the Data Flow

As mentioned previously and as indicated by the arrow in the figure above, the data flow of a binding can go from the binding target to the binding source (for example, the source value changes when a user edits the value of a TextBox) and/or from the binding source to the binding target (for example, your TextBox content gets updated with changes in the binding source) if the binding source provides the proper notifications.

You may want your application to enable users to change the data and propagate it back to the source object. Or you may not want to enable users to update the source data. You can control this by setting the Mode property of your Binding object. The following figure illustrates the different types of data flow:

OneWay binding causes changes to the source property to automatically update the target property, but changes to the target property are not propagated back to the source property. This type of binding is appropriate if the control being bound is implicitly read-only. For instance, you may bind to a source such as a stock ticker or perhaps your target property has no control interface provided for making changes, such as a data-bound background color of a table. If there is no need to monitor the changes of the target property, using the OneWay binding mode avoids the overhead of the TwoWay binding mode.

TwoWay binding causes changes to either the source property or the target property to automatically update the other. This type of binding is appropriate for editable forms or other fully-interactive UI scenarios. Most properties default to OneWay binding, but some dependency properties (typically properties of user-editable controls such as the Text property of TextBox and the IsChecked property of CheckBox) default to TwoWay binding. A programmatic way to determine whether a dependency property binds one-way or two-way by default is to get the property metadata of the property using GetMetadata and then check the Boolean value of the BindsTwoWayByDefault property.

OneWayToSource is the reverse of OneWay binding; it updates the source property when the target property changes. One example scenario is if you only need to re-evaluate the source value from the UI.

Not illustrated in the figure is OneTime binding, which causes the source property to initialize the target property, but subsequent changes do not propagate. This means that if the data context undergoes a change or the object in the data context changes, then the change is not reflected in the target property. This type of binding is appropriate if you are using data where either a snapshot of the current state is appropriate to use or the data is truly static. This type of binding is also useful if you want to initialize your target property with some value from a source property and the data context is not known in advance. This is essentially a simpler form of OneWay binding that provides better performance in cases where the source value does not change.

Note that to detect source changes (applicable to OneWay and TwoWay bindings), the source must implement a suitable property change notification mechanism such as INotifyPropertyChanged. See How to: Implement Property Change Notification for an example of an INotifyPropertyChanged implementation.

The Mode property page provides more information about binding modes and an example of how to specify the direction of a binding.

What Triggers Source Updates

Bindings that are TwoWay or OneWayToSource listen for changes in the target property and propagate them back to the source. This is known as updating the source. For example, you may edit the text of a TextBox to change the underlying source value. As described in the last section, the direction of the data flow is determined by the value of the Mode property of the binding.

However, does your source value get updated while you are editing the text or after you finish editing the text and point your mouse away from the TextBox? The UpdateSourceTrigger property of the binding determines what triggers the update of the source. The dots of the right arrows in the following figure illustrate the role of the UpdateSourceTrigger property:

If the UpdateSourceTrigger value is PropertyChanged, then the value pointed to by the right arrow of TwoWay or the OneWayToSource bindings gets updated as soon as the target property changes. However, if the UpdateSourceTrigger value is LostFocus, then that value only gets updated with the new value when the target property loses focus.

Similar to the Mode property, different dependency properties have different default UpdateSourceTrigger values. The default value for most dependency properties is PropertyChanged, while the Text property has a default value of LostFocus. This means that source updates usually happen whenever the target property changes, which is fine for CheckBoxes and other simple controls. However, for text fields, updating after every keystroke can diminish performance and it denies the user the usual opportunity to backspace and fix typing errors before committing to the new value. That is why the Text property has a default value of LostFocus instead of PropertyChanged.

See the UpdateSourceTrigger property page for information about how to find the default UpdateSourceTrigger value of a dependency property.

The following table provides an example scenario for each UpdateSourceTrigger value using the TextBox as an example:

UpdateSourceTrigger value

When the Source Value Gets Updated

Example Scenario for TextBox

LostFocus (default for TextBox.Text)

When the TextBox control loses focus

A TextBox that is associated with validation logic (see Data Validation section)

PropertyChanged

As you type into the TextBox

TextBox controls in a chat room window

Explicit

When the application calls UpdateSource

TextBox controls in an editable form (updates the source values only when the user clicks the submit button)

Page and Navigation

This is one of the amazing features in WPF; this is the major component, which helps in reducing memory, increasing application speed, reduces network bandwidth and be a critical component to success of any application while in production.

There are lot of cool features in web page development like Stateless, low memory consumption as only one page is loaded in the application at a time, the content will be static content in HTML format with JS scripts, this are the features which makes the web technologies like ASP.NET  as the obvious choice for internet or intranet based application.

Microsoft has provided the same features in WPF and user will have the option to do the same with Page, Navigation and other components and achieve all those benefits and make the ideal choice for both web and windows development.

Windows Presentation Foundation (WPF) supports browser-style navigation that can be used in two types of applications: standalone applications and XAML browser applications (XBAPs). To package content for navigation, WPF provides the Page class. You can navigate from one Page to another declaratively, by using a Hyperlink, or programmatically, by using the NavigationService. WPF uses the journal to remember pages that have been navigated from and to navigate back to them.

Page, Hyperlink, NavigationService, and the journal form the core of the navigation support offered by WPF. This overview explores these features in detail before covering advanced navigation support that includes navigation to lose Extensible Application Mark-up Language (XAML) files, HTML files, and objects.

In WPF, you can navigate to several content types that include .NET Framework objects, custom objects, enumeration values, user controls, XAML files, and HTML files. However, you'll find that the most common and convenient way to package content is by using Page. Furthermore, Page implements navigation-specific features to enhance their appearance and simplify development.

Using Page, you can declaratively implement a navigable page of XAML content by using mark-up like the following.

XAML

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" />
Colourised in 0ms

A Page that is implemented in XAML markup has Page as its root element and requires the WPF XML namespace declaration. The Page element contains the content that you want to navigate to and display. You add content by setting the Page.Content property element, as shown in the following markup.

XAML
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
  <Page.Content>
    <!-- Page Content -->
    Hello, Page!
  </Page.Content>
</Page>
Colourised in 2ms

Page.Content can only contain one child element; in the preceding example, the content is a single string, "Hello, Page!" In practice, you will usually use a layout control as the child element (see Layout System) to contain and compose your content.

The child elements of a Page element are considered to be the content of a Page and, consequently, you don't need to use the explicit Page.Content declaration. The following markup is the declarative equivalent to the preceding sample.

Programmatic Navigation to a Page Object

The following example shows how to use the NavigationService to programmatically navigate to a Page. Programmatic navigation is required because the Page that is being navigated to can only be instantiated using a single, non-default constructor. The Page with the non-default constructor is shown in the following markup and code.

XAML
<Page
    x:Class="SDKSample.PageWithNonDefaultConstructor"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="PageWithNonDefaultConstructor">

  <!-- Content goes here -->

</Page>
Colourised in 2ms
C#
using System.Windows.Controls; // Page

namespace SDKSample
{
    public partial class PageWithNonDefaultConstructor : Page
    {
        public PageWithNonDefaultConstructor(string message)
        {
            InitializeComponent();

            this.Content = message;
        }
    }
}
Colourised in 6ms

The Page that navigates to the Page with the non-default constructor is shown in the following markup and code.

XAML
<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.NSNavigationPage">

  <Hyperlink Click="hyperlink_Click">
    Navigate to Page with Non-Default Constructor
  </Hyperlink>

</Page>
Colourised in 3ms
C#
using System.Windows; // RoutedEventArgs
using System.Windows.Controls; // Page
using System.Windows.Navigation; // NavigationService

namespace SDKSample
{
    public partial class NSNavigationPage : Page
    {
        public NSNavigationPage()
        {
            InitializeComponent();
        }

        void hyperlink_Click(object sender, RoutedEventArgs e)
        {
            // Instantiate the page to navigate to
            PageWithNonDefaultConstructor page = new PageWithNonDefaultConstructor("Hello!");

            // Navigate to the page, using the NavigationService
            this.NavigationService.Navigate(page);
        }
    }
}
Colourised in 13ms

When the Hyperlink on this Page is clicked, navigation is initiated by instantiating the Page to navigate to using the non-default constructor and calling the NavigationService.Navigate method. Navigate accepts a reference to the object that the NavigationService will navigate to, rather than a pack URI.

Programmatic Navigation with a Pack URI

If you need to construct a pack URI programmatically (when you can only determine the pack URI at run time, for example), you can use the NavigationService.Navigate method. This is shown in the following example.

XAML
<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.NSUriNavigationPage">
  <Hyperlink Click="hyperlink_Click">Navigate to Page by Pack URI</Hyperlink>
</Page>
Colourised in 3ms
C#
using System; // Uri, UriKind
using System.Windows; // RoutedEventArgs
using System.Windows.Controls; // Page
using System.Windows.Navigation; // NavigationService

namespace SDKSample
{
    public partial class NSUriNavigationPage : Page
    {
        public NSUriNavigationPage()
        {
            InitializeComponent();
        }

        void hyperlink_Click(object sender, RoutedEventArgs e)
        {
            // Create a pack URI
            Uri uri = new Uri("AnotherPage.xaml", UriKind.Relative);

            // Get the navigation service that was used to 
            // navigate to this page, and navigate to 
            // AnotherPage.xaml
            this.NavigationService.Navigate(uri);
        }
    }
}
Colourised in 19ms

Refreshing the Current Page

A Page is not downloaded if it has the same pack URI as the pack URI that is stored in the NavigationService.Source property. To force WPF to download the current page again, you can call the NavigationService.Refresh method, as shown in the following example.

XAML
<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.NSRefreshNavigationPage">
 <Hyperlink Click="hyperlink_Click">Refresh this page</Hyperlink>
</Page>
Colourised in 5ms
C#
using System.Windows; // RoutedEventArgs
using System.Windows.Controls; // Page
using System.Windows.Navigation; // NavigationService

namespace SDKSample
{
    public partial class NSRefreshNavigationPage : Page
    {
        ...

        void hyperlink_Click(object sender, RoutedEventArgs e)
        {
            // Force WPF to download this page again
            this.NavigationService.Refresh();
        }
    }
Colourised in 9ms

Navigation Lifetime

There are many ways to initiate navigation, as you've seen. When navigation is initiated, and while navigation is in progress, you can track and influence the navigation using the following events that are implemented by NavigationService:

  • Navigating. Occurs when a new navigation is requested. Can be used to cancel the navigation.
  • NavigationProgress. Occurs periodically during a download to provide navigation progress information.
  • Navigated. Occurs when the page has been located and downloaded.
  • NavigationStopped. Occurs when the navigation is stopped (by calling StopLoading), or when a new navigation is requested while a current navigation is in progress.
  • NavigationFailed. Occurs when an error is raised while navigating to the requested content.
  • LoadCompleted. Occurs when content that was navigated to is loaded and parsed, and has begun rendering.
  • FragmentNavigation. Occurs when navigation to a content fragment begins, which happens:
    • Immediately, if the desired fragment is in the current content.
    • After the source content has been loaded, if the desired fragment is in different content.

The navigation events are raised in the order that is illustrated by the following figure.

In general, a Page isn't concerned about these events. It is more likely that an application is concerned with them and, for that reason, these events are also raised by the Application class:

Every time NavigationService raises an event, the Application class raises the corresponding event. Frame and NavigationWindow offer the same events to detect navigation within their respective scopes.

Programming Guidelines for improving performance

Use asynchronous programming where possible to improve performance, this can lead to performance degradations if not properly used.

Write code smartly, use objects where it is necessary, and declare only in the scope.

Avoid mistakes like:

bool test = false;
//Some Processing
if (test == true)
{
  //some processing
}
Colourised in 1ms

We can write instead:

if (test)
{
  //some processing
}
Colourised in 1ms

Use centralized cache so that disposal of objects are easy similar to WeakReference. Dispose static objects and event when not required by assigning to null. Use LINQ or lambda expressions carefully avoid programming mistake which is similar to SQL joins and can take long time if not properly used. Try to do without recursion and implement while loop to exhibit same behaviour. Avoid using delegate and event, use Action command from .NET 4.0 and higher versions and release those command immediately after use. Build application with proper design from the start, which helps to follow later and can provide large benefits.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here