Click here to Skip to main content
13,589,607 members
Click here to Skip to main content
Add your own
alternative version

Tagged as


13 bookmarked
Posted 23 Apr 2013
Licenced CPOL

Displaying Busy Control in WPF using MVVM

, 23 Apr 2013
Rate this:
Please Sign up or sign in to vote.
Displaying an adorner that contains a control on top of another control in WPF


One of the worst Windows applications from the user experience perspective is the application that when clicking on something, it just hangs and "freezes" and becomes unresponsive for a certain period of time and then it just becomes alive again. This usually happens when a time-consuming task (lengthy calculations, database access, I/O access, etc.) was executed on the main thread, making the application unusable until the task has finished executing.

To avoid this scenario, all the processing should be executed on a separate thread, leaving the main thread to deal only with a UI specific stuff. We still should let the user know in some way (by displaying a progress bar, darkening the window, ...) that a task is being executed even though the task is still executed on a separate thread.

My personal favorite is darkening the main window and displaying a message in the middle of the screen, something like:

Sample Image - maximum width is 600 pixels

To achieve this, I place a user control on top of the window as an adorner, and then by using attached properties on the window, I display or hide the adorner accordingly.

To be able to use any user control as an adorner, first we need to create a class that inherits from Adorner class and override few methods. The class looks like:

public  class  ControlAdorner  : Adorner
    private  readonly  FrameworkElement  mAdorningElement;
    private  AdornerLayer  mLayer;

    public  ControlAdorner(FrameworkElement  adornedElement, FrameworkElement  adorningElement)
        : base (adornedElement)
        mAdorningElement = adorningElement;

        if  (adorningElement != null )

    protected  override  int  VisualChildrenCount
        get  { return  mAdorningElement != null  ? 1 : 0; }

    protected  override  System.Windows.Media.Visual  GetVisualChild(int  index)
        if  (index == 0 && mAdorningElement != null )
            return  mAdorningElement;

        return  base .GetVisualChild(index);

    protected  override  Size  ArrangeOverride(Size  finalSize)
        if  (mAdorningElement != null )
            mAdorningElement.Arrange(new  Rect
            (new  Point (0, 0), AdornedElement.RenderSize));

        return  finalSize;

    public  void  SetLayer(AdornerLayer  layer)
        mLayer = layer;
        mLayer.Add(this );

    public  void  RemoveLayer()
        if  (mLayer != null )
            mLayer.Remove(this );

The next step is to create the attached property that will display/hide the adorner. The attached property implementation looks like:

public  class  AdornerBehaviour
    public  static  readonly  DependencyProperty  ShowAdornerProperty =
    DependencyProperty .RegisterAttached("ShowAdorner" , typeof (bool ),
    typeof (AdornerBehaviour ), new  UIPropertyMetadata (false , OnShowAdornerChanged));
    public  static  readonly  DependencyProperty  ControlProperty =
    DependencyProperty .RegisterAttached("Control" , typeof (FrameworkElement ),
    typeof (AdornerBehaviour ), new  UIPropertyMetadata (null ));
    private  static  readonly  DependencyProperty  CtrlAdornerProperty =
    DependencyProperty .RegisterAttached("CtrlAdorner" , typeof (ControlAdorner ),
    typeof (AdornerBehaviour ), new  UIPropertyMetadata (null ));

    public  static  bool  GetShowAdorner(DependencyObject  obj)
        return  (bool )obj.GetValue(ShowAdornerProperty);

    public  static  void  SetShowAdorner(DependencyObject  obj, bool  value)
        obj.SetValue(ShowAdornerProperty, value);

    public  static  FrameworkElement  GetControl(DependencyObject  obj)
        return  (FrameworkElement )obj.GetValue(ControlProperty);

    public  static  void  SetControl(DependencyObject  obj, UIElement  value)
        obj.SetValue(ControlProperty, value);

    private  static  void  OnShowAdornerChanged
    (DependencyObject  d, DependencyPropertyChangedEventArgs  e)
        if  (d is  FrameworkElement )
            if  (e.NewValue != null )
                FrameworkElement  adornedElement = d as  FrameworkElement ;
                bool  bValue = (bool )e.NewValue;
                FrameworkElement  adorningElement = GetControl(d);

                ControlAdorner  ctrlAdorner =
                   adornedElement.GetValue(CtrlAdornerProperty) as  ControlAdorner ;
                if  (ctrlAdorner != null )

                if  (bValue && adorningElement != null )
                    ctrlAdorner = new  ControlAdorner (adornedElement, adorningElement);
                    var  adornerLayer = AdornerLayer .GetAdornerLayer(adornedElement);
                    d.SetValue(CtrlAdornerProperty, ctrlAdorner);

The last step is to create the user control that will be used as an adorner. The XAML for the user control looks like:

<UserControl x:Class="CCRM.CurveMonitor.WPF.Views.BusyCtrl" 







              d:DesignWidth="300" Background="#20000000"> 
     <Border Width="260" Height="120" 

     CornerRadius="12" HorizontalAlignment="Center" 

                 <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0" > 
                     <GradientStop Color="#FF4B4B4B" Offset="0.897"/> 
                     <GradientStop Color="#FF6E6E6E" Offset="1"/> 
                     <GradientStop Color="#FF4B4B4B" Offset="0.103"/> 
                     <GradientStop Color="#FF6E6E6E" Offset="0"/> 
             <TextBlock FontSize="24" Foreground="White" 

             Text="Loading" HorizontalAlignment="Center" 


As you can see, we have made the control semi-transparent by setting the background to the value of #20000000 (first 2 bytes are for alpha, then next 2 bytes for the red, next 2 bytes for green and last 2 bytes for blue). Now, to use the control adorner in our main window, on window's XAML, we add the following:

 <Window x:Class="Test.MainWindow"
        Title="MainWindow" Height="350" Width="525">

        <BusyControl x:Key="BusyControl" />
    <Grid b:AdornerBehaviour.ShowAdorner="{Binding IsBusy}"
    b:AdornerBehaviour.Control="{StaticResource BusyControl}">

Now whenever we set the IsBusy boolean property to true in the ViewModel of the main window, the adorner will be displayed, and when the IsBusy property is set to false, the adorner will be hidden.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Fitim Skenderi
Software Developer (Senior)
United Kingdom United Kingdom
No Biography provided

You may also be interested in...


Comments and Discussions

GeneralMy vote of 5 Pin
Member 105253171-Jul-15 3:57
memberMember 105253171-Jul-15 3:57 
GeneralRe: My vote of 5 Pin
Fitim Skenderi1-Jul-15 4:07
memberFitim Skenderi1-Jul-15 4:07 
BugIssue when 'AdornedElement' is not loaded. Pin
Lucky Phil12-Dec-13 11:48
memberLucky Phil12-Dec-13 11:48 
GeneralRe: Issue when 'AdornedElement' is not loaded. Pin
Fitim Skenderi1-Jul-15 4:08
memberFitim Skenderi1-Jul-15 4:08 
GeneralMy vote of 5 Pin
Oleksandr Kulchytskyi23-Apr-13 23:10
memberOleksandr Kulchytskyi23-Apr-13 23:10 
GeneralRe: My vote of 5 Pin
Fitim Skenderi25-Apr-13 3:19
memberFitim Skenderi25-Apr-13 3:19 
QuestionKeyboard navigation Pin
springy7623-Apr-13 21:51
memberspringy7623-Apr-13 21:51 
AnswerRe: Keyboard navigation Pin
Fitim Skenderi24-Apr-13 9:36
memberFitim Skenderi24-Apr-13 9:36 
GeneralNice Tip Pin
FloppyMan23-Apr-13 18:49
memberFloppyMan23-Apr-13 18:49 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web04-2016 | 2.8.180615.1 | Last Updated 23 Apr 2013
Article Copyright 2013 by Fitim Skenderi
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid