Daniel Vaughan

.NET Adventures

Calcium now on Twitter

clock March 5, 2010 23:56 by author Daniel Vaughan

Calcium SDK development news can now be found in 140 characters or less.

 



Article Published: Context Sensitive History. Part 1 of 2

clock February 24, 2010 22:13 by author Daniel Vaughan

A Desktop and Silverlight user action management system, with undo, redo, and repeat. Allowing actions to be monitored, and grouped according to a context (such as a UI control), executed sequentially or in parallel, and even to be rolled back on failure.

A 'task' is the term I use to describe application work units,
instigated by the user or the system.

The main features of the task management system provided in this article are:

  • Tasks can be undone, redone, and repeated.
  • Task execution may be cancelled.
  • Composite tasks allow sequential and parallel execution of tasks with automatic rollback on failure of an individual task.
  • Tasks can be associated with a context, such as a UserControl, so that the undo, redo, and repeat actions can be, for example, enabled according to UI focus.
  • Tasks can be global, having no context association.
  • The task system can be wired to ICommands.
  • Tasks can be chained, in that one task can use the Task Service to perform another.
  • Return to a point in history by specifying an undo point.
  • Coherency in the system is preserved by disallowing the execution of tasks outside of the Task Service.
  • Task Model compatible with both the Silverlight and Desktop CLRs

View Article



Silverlight YouTube Jukebox

clock February 22, 2010 16:24 by author Daniel Vaughan

My better half just published an article on creating a YouTube video viewer with Silverlight 4 and RIA Services. I may be a bit biased, but I think it's great!



ViewModel Active Awareness in a Prism Based Application

clock February 5, 2010 15:13 by author Daniel Vaughan

Yesterday, while chatting with the highly talented Jeremiah Morrill and other WPF Disciples about some MVVM subtleties (for the full post see here), Jeremiah briefly touched on the topic of providing ViewModels with the awareness of being active or inactive within a Prism based application. I wanted to explore this further, and decided to integrate this functionality into Calcium. What I provide here isn't rocket science, and merely serves to illustrate one of indeed many design approaches that could be applied to accomplish the same thing.

For this I had two goals. The first, to provide the capability without coupling the ViewModel to the View. That is, without requiring the ViewModel to have a reference to the View. The second, to not depend on a base class for the functionality; forever tying the developer to my base class implementation (ViewModelBase). So, indeed, I chose an interface based approach. To be Prism-esque I have adapted Jeremiah's approach which was to implement Prism's IActiveAware interface on my base view class. I then feed an intermediary object to the ViewModel via an interface named IViewAware. The intermediary object is an instance of ActiveAwareUIElementAdapter. This class is used to provide a UIElement instance with Prisms IActiveAware interface. It does so by monitoring its Got and LostFocus events.

 

ActiveAwareUIElementAdapter

 

/// <summary>
/// Wraps a <see cref="UIElement"/> to provide an <see cref="IActiveAware"/>
/// implementation based on its focus state.
/// </summary>
public class ActiveAwareUIElementAdapter : IActiveAware
{
    bool active;

    public ActiveAwareUIElementAdapter(UIElement uiElement)
    {
        ArgumentValidator.AssertNotNull(uiElement, "uiElement");
        uiElement.GotFocus += OnGotFocus;
        uiElement.LostFocus += OnLostFocus;
    }

    void OnLostFocus(object sender, RoutedEventArgs e)
    {
        IsActive = false;
    }

    void OnGotFocus(object sender, RoutedEventArgs e)
    {
        IsActive = true;
    }

    public bool IsActive
    {
        get
        {
            return active;
        }
        set
        {
            if (active != value)
            {
                active = value;
            }
            OnIsActiveChanged(EventArgs.Empty);
        }
    }

    #region event IsActiveChanged

    event EventHandler isActiveChanged;

    public event EventHandler IsActiveChanged
    {
        add
        {
            isActiveChanged += value;
        }
        remove
        {
            isActiveChanged -= value;
        }
    }

    protected void OnIsActiveChanged(EventArgs e)
    {
        if (isActiveChanged != null)
        {
            isActiveChanged(this, e);
        }
    }

    #endregion
}

We then use this class within any IView UIElement implementation, but in particular the base ViewControl class. We instantiate the ActiveAwareUIElement adapter within the view's constructor, and pass it the instance of the view itself. The ActiveAwareUIElement then simply subscribes to the GotFocus and LostFocus events of the view, which is of course a UIElement.

 

ViewControl Implementation

 

/// <summary>
/// The base class for <see cref="IView"/>s.
/// </summary>
public class ViewControl : UserControl, IView, IActiveAware /* (not abstract for Blendability) */
{
    #region ViewModel Dependency Property

    public static DependencyProperty ViewModelProperty = DependencyProperty.Register(
        "ViewModel", typeof(IViewModel), typeof(ViewControl), new PropertyMetadata(null, OnViewModelChanged));

    static void OnViewModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var viewControl = (ViewControl)d;
        viewControl.SetViewAwareAssociations((IViewModel)e.OldValue, (IViewModel)e.NewValue);
    }

    [Description("The view model for this view.")]
#if !SILVERLIGHT
    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
#endif
    public IViewModel ViewModel
    {
        get
        {
            return (IViewModel)GetValue(ViewModelProperty);
        }
        set
        {
            SetValue(ViewModelProperty, value);
        }
    }

    #endregion

    /// <summary>
    /// Initializes a new instance of the <see cref="ViewControl"/> class.
    /// </summary>
    public ViewControl()
    {
        Loaded += OnLoaded;
        activeAwareUIElementAdapter = new ActiveAwareUIElementAdapter(this); 
    }

    bool alreadyLoaded;

    void OnLoaded(object sender, RoutedEventArgs e)
    {
        if (!alreadyLoaded)
        {
            alreadyLoaded = true;
            OnViewLoaded(e);
        }
    }

    #region ViewLoaded event

    event EventHandler<EventArgs> viewLoaded;

    /// <summary>
    /// Occurs when the view has been loaded.
    /// </summary>
    public event EventHandler<EventArgs> ViewLoaded
    {
        add
        {
            viewLoaded += value;
        }
        remove
        {
            viewLoaded -= value;
        }
    }

    /// <summary>
    /// Closes the view.
    /// </summary>
    /// <param name="force">if set to <c>true</c> the control will be forced
    /// to close even if e.g., there is unsaved data and the user chooses 
    /// to cancel the closure.</param>
    /// <returns></returns>
    public virtual bool Close(bool force)
    {
        var viewService = ServiceLocatorSingleton.Instance.GetInstance<IViewService>();
        return viewService.CloseView(this, force);
    }

    /// <summary>
    /// Raises the <see cref="E:ViewLoaded"/> event.
    /// </summary>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void OnViewLoaded(EventArgs e)
    {
        if (viewLoaded != null)
        {
            viewLoaded(this, e);
        }
    }
    #endregion

    /// <summary>
    /// Gets a value indicating whether the control is in a designer.
    /// </summary>
    /// <value><c>true</c> if design time; otherwise, <c>false</c>.</value>
    protected bool DesignTime
    {
        get
        {
            return DesignerProperties.GetIsInDesignMode(this);
        }
    }

    #region IActiveAware and related

    void SetViewAwareAssociations(IViewModel oldViewModel, IViewModel newViewModel)
    {
        var oldViewAware = oldViewModel as IViewAware;
        var newViewAware = newViewModel as IViewAware;
        if (oldViewAware != null)
        {
            oldViewAware.DetachActiveAware();
        }

        if (newViewAware != null)
        {
            newViewAware.Attach(activeAwareUIElementAdapter);
        }
    }

    readonly ActiveAwareUIElementAdapter activeAwareUIElementAdapter;

    bool IActiveAware.IsActive
    {
        get
        {
            return activeAwareUIElementAdapter.IsActive;
        }
        set
        {
            activeAwareUIElementAdapter.IsActive = value;
        }
    }

    event EventHandler IActiveAware.IsActiveChanged
    {
        add
        {
            activeAwareUIElementAdapter.IsActiveChanged += value;
        }
        remove
        {
            activeAwareUIElementAdapter.IsActiveChanged -= value;
        }
    }

    #endregion
}

We see that the dependency property ViewModel, when changed, prompts the attachment of the ActiveAwareUIElement instance to the ViewModel. The mechanism for performing this is via the IViewAware implementation. If an IViewModel wishes to be aware of its view's state, in particular when it becomes active or inactive; without having to have a direct reference to the view, then it can implement the IViewAware interface.

 

IViewAware Interface


/// <summary>
/// Provides for advanced presentation behaviour in a <see cref="IViewModel"/>s.
/// </summary>
public interface IViewAware
{
    /// <summary>
    /// Attaches the specified active aware instance so that changes in the <see cref="IActiveAware.IsActive"/>
    /// state can be monitored.
    /// </summary>
    /// <param name="activeAware">The active aware.</param>
    void Attach(IActiveAware activeAware);

    /// <summary>
    /// Detaches the active aware instance. Changes in the <see cref="IActiveAware.IsActive"/>
    /// state will no longer be monitored.
    /// </summary>
    void DetachActiveAware();
}

The ViewModel base class implementation is provided next in full:

/// <summary>
/// A base implementation of the <see cref="IViewModel"/> interface.
/// </summary>
public abstract class ViewModelBase : IViewModel, INotifyPropertyChanged, IViewAware
{
    IActiveAware activeAwareInstance;

    protected ViewModelBase()
    {
        notifier = new PropertyChangeNotifier(this);
    }

    #region Title Property

    object title;

    [Description("The text to display on a tab.")]
#if !SILVERLIGHT
    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
#endif        
    public object Title
    {
        get
        {
            return title;
        }
        set
        {
            notifier.Assign("Title", ref title, value);
        }
    }

    #endregion

    #region Property Change Notification
    readonly PropertyChangeNotifier notifier;

    protected PropertyChangeNotifier Notifier
    {
        get
        {
            return notifier;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged
    {
        add
        {
            notifier.PropertyChanged += value;
        }
        remove
        {
            notifier.PropertyChanged -= value;
        }
    }

    protected AssignmentResult Assign<TProperty>(
        string propertyName, ref TProperty property, TProperty newValue)
    {
        return notifier.Assign(propertyName, ref property, newValue);
    }

    #endregion

    #region Active Aware

    void IViewAware.Attach(IActiveAware activeAware)
    {
        ReplaceActiveAware(activeAware);
    }

    void IViewAware.DetachActiveAware()
    {
        ReplaceActiveAware(null);
    }

    void ReplaceActiveAware(IActiveAware activeAwareInstance)
    {
        if (this.activeAwareInstance != null)
        {
            this.activeAwareInstance.IsActiveChanged -= OnIsActiveChanged;
        }
        this.activeAwareInstance = activeAwareInstance;
        if (activeAwareInstance != null)
        {
            activeAwareInstance.IsActiveChanged += OnIsActiveChanged;
        }
    }

    bool lastActiveState;

    void OnIsActiveChanged(object sender, EventArgs e)
    {
        Notifier.NotifyChanged("Active", lastActiveState, Active);
        lastActiveState = Active;
    }

    /// <summary>
    /// Gets a value indicating whether this instance is being notified 
    /// of when it becomes active or inactive, 
    /// this may occur for example when its view gains focus or loses focus.
    /// </summary>
    /// <value><c>true</c> if monitoring the active state 
    /// of its view; otherwise, <c>false</c>.</value>
    public bool ActiveAware
    {
        get
        {
            return activeAwareInstance != null;
        }
    }

    /// <summary>
    /// Gets a value indicating whether this <see cref="ViewModelBase"/> 
    /// is active within the user interface.
    /// </summary>
    /// <value><c>true</c> if active; otherwise, <c>false</c>.</value>
    public bool Active
    {
        get
        {
            return activeAwareInstance != null ? activeAwareInstance.IsActive : false;
        }
    }

    #endregion

    public override string ToString()
    {
        return title != null ? title.ToString() : base.ToString();
    }
}

So there it is. Just one way to provide a ViewModel with active awareness. Please be aware that this code is preliminary and may be subject to change. The full source code will be available via the Calcium source download page soon.

 

Thanks to Kent Boogaart for his post on MVVM Infrastructure ActiveAwareCommand which the ActiveAwareUIElementAdapter was inspired from.



CodeProject MVP 2010

clock January 12, 2010 11:54 by author Daniel Vaughan

CodeProject MVPI usually hear about big community news from the WPF Disciples group. Somehow everything gets announced there. Today was no different when I read the announcement and congratulations for receiving the CodeProject MVP Award for 2010. That's fantastic news for me, as it is a *huge* honour. I send out my congratulations to Sacha Barber, Pete O'Hanlon, Josh Smith, and to the other 40 people awarded this year. Not bad for a site with over 6.5 million members.

CodeProject is a way of life for many developers, including myself. Thank you CodeProject.



Synchronous Invocation of Delegates with the Silverlight Dispatcher

clock January 10, 2010 18:14 by author Daniel Vaughan

Introduction

In this post I would like to briefly discuss the System.Windows.Threading.Dispatcher class, and the significant differences between its Silverlight and Desktop CLR implementations. We are going to look at solving two things:

  1. Consuming the UI’s Dispatcher in Silverlight before a page has been instanciated.
  2. Allowing for synchronous invocation of delegates on the UI thread.

Background

Recently my good friend Sacha Barber published an article, and in the comments of which we briefly touched on a cross threading issue that we have both experienced with the Silverlight Dispatcher class. I thought it was about time that I wrote some of this stuff up. This is the result.

Silverlight Thread Affinity

When working with Silverlight, one has to contend with the usual single threaded apartment model (STA) that is also present when working with WPF or Windows Forms. This means that one must interact with UI components, in particular DependencyObject derived types, from the thread in which they were created on. Fortunately Silverlight/WPF/Windows Forms includes infrastructure that makes acquiring and invoking calls on the UI thread simpler; specifically the System.Windows.Threading.Dispatcher, which is a prioritized message loop that handles thread affinity.

There is an excellent article describing the Dispatcher in detail.

Consuming the UI’s Dispatcher

In Silverlight a Dispatcher becomes associated with the main page during initialization, thereby making it available via the Applications RootVisual property like so:

Application.Current.RootVisual.Dispatcher

We can consume the Dispatcher this way, as long as we do so after the RootVisual has been defined. But in the case where we would like to consume the Dispatcher from the get-go, it leaves us out in the cold. Fortunately though, the Silverlight Dispatcher instance is also available via the System.Windows.Deployment.Current.Dispatcher property. This instance is defined when the Application starts, thereby making it possible to commence asynchronous operations before the first page is instanciated.

Synchronous Invocation of Delegates on the UI Thread

The Silverlight Dispatcher is geared for asynchronous operations. As we can see from the following image, unlike the Desktop CLR Dispatcher, the Silverlight Dispatcher class’s Invoke method overloads have internal visibility.

It has to be said that the Desktop CLR Dispatcher, when compared with the Silverlight version, as with many other classes, has a much richer API. In order to provide a means to synchronously invoke a delegate on the UI thread we need another approach. The approach I have taken is to utilize the System.Windows.Threading.DispatcherSynchronizationContext

By using the Post and Send methods of the DispatcherSynchronizationContext we are able to regain the synchronous Invoke capabilities within the Silverlight environment.

I have rolled this up into a set of reusable classes, located in my core Silverlight library, which you can find in the DanielVaughan.Silverlight project in the Calcium http://www.calciumsdk.net download.

/// <summary>
/// Singleton class providing the default implementation 
/// for the <see cref="ISynchronizationContext"/>, specifically for the UI thread.
/// </summary>
public class UISynchronizationContext : ISynchronizationContext
{
    DispatcherSynchronizationContext context;
    Dispatcher dispatcher;
    
    #region Singleton implementation

    static readonly UISynchronizationContext instance = new UISynchronizationContext();
    
    /// <summary>
    /// Gets the singleton instance.
    /// </summary>
    /// <value>The singleton instance.</value>
    public static ISynchronizationContext Instance
    {
        get
        {
            return instance;
        }
    }

    #endregion

    public void Initialize()
    {
        EnsureInitialized();
    }

    readonly object initializationLock = new object();

    void EnsureInitialized()
    {
        if (dispatcher != null && context != null)
        {
            return;
        }

        lock (initializationLock)
        {
            if (dispatcher != null && context != null)
            {
                return;
            }

            try
            {
                dispatcher = Deployment.Current.Dispatcher;
                context = new DispatcherSynchronizationContext(dispatcher);
            }
            catch (InvalidOperationException)
            {
                /* TODO: Make localizable resource. */
                throw new ConcurrencyException("Initialised called from non-UI thread."); 
            }
        }
    }

    public void Initialize(Dispatcher dispatcher)
    {
        ArgumentValidator.AssertNotNull(dispatcher, "dispatcher");
        lock (initializationLock)
        {
            this.dispatcher = dispatcher;
            context = new DispatcherSynchronizationContext(dispatcher);
        }
    }

    public void InvokeAsynchronously(SendOrPostCallback callback, object state)
    {
        ArgumentValidator.AssertNotNull(callback, "callback");
        EnsureInitialized();

        context.Post(callback, state);
    }

    public void InvokeAsynchronously(Action action)
    {
        ArgumentValidator.AssertNotNull(action, "action");
        EnsureInitialized();

        if (dispatcher.CheckAccess())
        {
            action();
        }
        else
        {
            dispatcher.BeginInvoke(action);
        }
    }

    public void InvokeSynchronously(SendOrPostCallback callback, object state)
    {
        ArgumentValidator.AssertNotNull(callback, "callback");
        EnsureInitialized();

        context.Send(callback, state);
    }

    public void InvokeSynchronously(Action action)
    {
        ArgumentValidator.AssertNotNull(action, "action");
        EnsureInitialized();

        if (dispatcher.CheckAccess())
        {
            action();
        }
        else
        {
            context.Send(delegate { action(); }, null);
        }
    }

    public bool InvokeRequired
    {
        get
        {
            EnsureInitialized();
            return !dispatcher.CheckAccess();
        }
    }
}

A further advantage of using either a Silverlight or Desktop CLR implementation of the ISynchronizationContext is that we are able to write CLR agnostic code. That is, code that was written for the Desktop CLR can be easily moved to the Silverlight.

Using the code:

UISynchronizationContext.Instance.InvokeSynchronously(delegate
                                {
/* Code to execute on the UI thread. */
                                });

Conclusion

In this post we have looked at consuming the UI’s Dispatcher in Silverlight as soon as an Application starts. We also saw how it is possible in Silverlight to accomplish synchronous invocation of delegates on the UI thread.

The full source shown in this article is available on the Calcium Codeplex site

 

 

 



Calcium wins again!

clock December 22, 2009 17:54 by author Daniel Vaughan

I'm pleased to report that the article Calcium Part 3 has won the Best Overall Article award for November 2009.

The article covers a lot of the VS templating work I did for Calcium in the last release. Thanks to those who voted, and to all those who have been supporting the project by providing comments and feedback.

 



Clog Project Source Integrated into Calcium

clock December 2, 2009 17:44 by author Daniel Vaughan

I am pleased to announce that the Clog project has been fully integrated into Calcium. The source code for both the Silverlight and Desktop CLR Clog projects is now located along with the Calcium source code on Codeplex. Why did I take this step? The reason is that there are shared projects across Clog and Calcium, and maintaining two codebases would not be a good thing. One of my goals when publishing software is to make things easy for you. So, a single point of the latest source seems to makes sense. Please note that I will still be releasing Clog binaries on the dedicated Clog Codeplex site. However, the most up to date Clog source can be found with Calcium.



Nice List of MVVM Frameworks

clock December 2, 2009 15:41 by author Daniel Vaughan

Many of the Disciples and others have released various frameworks for building Model-View-ViewModel WPF and Silverlight apps. Jeremy Alles has prepared a very nice list of MVVM frameworks, and presented it in a Silverlight viewer.



ALT.NET Swiss group

clock November 26, 2009 21:47 by author Daniel Vaughan

Last night I had the pleasure of speaking at the ALT.NET Swiss group in Geneva. I spoke on composite applications, Prism, Calcium, and T4 Generated Metadata. Valeriu Caraulean spoke on MVVM, BLToolkit and Caliburn. Thanks to Frédéric SCHÄFER for organising the event, and to Atif Aziz and Cargill International SA for the location.

Catch us at the next meeting!



About the author

Daniel VaughanDaniel Vaughan is a software developer with a decade of commercial experience across a wide range of industries including e-commerce, multimedia, and finance. While originally from Australia and the UK, Daniel is currently based in Geneva Switzerland; working with WPF, WCF, and WF within the finance industry. In his spare time Daniel likes to spend time thinking up novel ideas, such as employing neural networks to predict user navigation behaviour in WPF applications, and a grid computing framework for Silverlight. Daniel is also the creator of a number of open-source projects including Calcium, and Clog. E-mail me Send mail

 

I am an Insider

WPF and Silverlight Insiders


I am a WPF Disciple

Disciple

 

CodeProject MVP

RecentComments

Comment RSS

Sign in