.Net, C#, RX

Dealing with RX Exception, “Failed to start monitoring system clock changes”

With some pain we recently uncovered a risk in using Observable.Timer(...) in Reactive Extensions.

The system is a WPF real-time trading system, utilising RX heavily.  Some of our users access the system via Citrix, and it was these users who first started experiencing the issue.  Sporadically a thread pool callback would cause the system to crash with an unhandled exception.  The exception being thrown from inside RX:


System.InvalidOperationException: Failed to start monitoring system clock changes.
at System.Reactive.PlatformServices.PeriodicTimerSystemClockMonitor.NewTimer()
at System.Reactive.PlatformServices.PeriodicTimerSystemClockMonitor.TimeChanged()
at System.Reactive.Concurrency.ConcurrencyAbstractionLayerImpl.PeriodicTimer.Tick(Object state)
at System.Threading.TimerQueueTimer.CallCallbackInContext(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.TimerQueueTimer.CallCallback()
at System.Threading.TimerQueueTimer.Fire()
at System.Threading.TimerQueue.FireQueuedTimerCompletion(Object state)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

Being on Citrix I started hypothesising that this might be some kind of CPU load issue. Then we had another “normal” desktop user encounter the exception. Her application kept crashing and upon investigation I found another process on her 4 core box taking 25% CPU. Killing that process-which seemed to have gone rogue-suddenly cleared our application of the RX error. So again, it pointed to CPU bound slowness.

The actual RX source which throws the exception can be seen here, inside the NewTimer method.

If you use Observable.Timer(...) RX will internally create a new PeriodicTimerSystemClockMonitor instance and subscribe to its SystemClockChanged event. And this class creates a timer to raise the event. Everytime this timer calls back into TimeChanged a time threshold is checked. If the callback was too slow, a new timer will be generated within NewTimer. Again, the length of time it takes to create this timer is checked. If the SYNC_MAXDELTA milliseconds threshold is broken, another attempt is made. The loop allows for 100 attempts. If after this time the timer hasn’t been created within the allowed time threshold the offending InvalidOperationException is thrown.

At which point your application will die.

It took a few attempts of reading the code before I understood this; it is not immedietely easy to get this set-up in debug. I wanted to add some logging to give us an idea of how slow the timer recreation was. To achieve this I had implement a custom IPlatformEnlightenmentProvider (and set via: PlatformEnlightenmentProvider.Current = new CustomPlatformEnlightenmentProvider(); ), which unfortunately involved some reflection so I could instantiate existing classes internal to RX. But now I am able to get RX to use a ConfigurablePeriodicTimerSystemClockMonitor where I can get some logging going and experiemnt with the time thresholds.

The two classes are at the end of the article. The important thing is I can see when RX decides the callback is too slow and that a new timer is required. And then, when the exception is finally thrown inside NewTimer, I can see how slow the timer creation operation was:

if (n >= _syncMaxRetries)
{
    _logger.Warning("Failed to start monitoring system clock changes (Configurable Impl). diff={0}", diff);
    throw new InvalidOperationException(
        "Failed to start monitoring system clock changes (Configurable Impl).");
}

With all this in place I sat back and waited for the crash reports to come in. The first exception report looked like this:

Failed to start monitoring system clock changes (Configurable Impl). diff=489.0552

So in this case, a call which RX wants to happen within 10ms is taking nearly half a second. As of writing I have questions outstanding with our Citrix team, CPU usage/spikes/load, mem etc. I am also pondering other things: did a gen2 GC collect kick in? What other process are running? Do we also have a memory leak? etc etc. Perhaps clutching at a few straws 🙂

So what’s next?

I’ve got options, mainly two, but I don’t particularly like either:

  • Make the time check much more relaxed. But how relaxed? There is no line in the sand here…
  • Remove all usages of Observable.Timer. And stand guard over every developers’ check-ins for the application’s lifetime?!

Right now we are still contemplating our next step, collating information. I’ll try an update this post with our final approach. I will also try and solicit a response from the RX team for their opinion on this.

UPDATE: Solution From Microsoft

Kudos to the RX team at Microsft who very quickly came back with a possible solution. There’s a couple of gotchas, but its very workable. The suggestion is to “create a custom system clock monitor using SystemEvents.TimeChanged“.

So we rely on the Win32 event to notify RX of changes to the system clock, instead of the more complicated PeriodicTimerSystemClockMonitor which has all the time checks and constraints at the root of the problem we are seeing.

There’s a couple of small issues:

  • We will still have to use our custom IPlatformEnlightenmentProvider, which uses reflection to instantiate RX internal classes. This leaves us slightly vulnerable to future re-workings to the innards of RX. UPDATE: dealt with; see UPDATE 2 below.
  • The solution requires a message pump (which apparently is why RX doesn’t use this method by default). Luckily for us, being a WPF application, we have one.

So I’ve created a new class:

public class SystemEventsSystemClockMonitor : INotifySystemClockChanged
{
    private int _refCount;
    private EventHandler<SystemClockChangedEventArgs> _systemClockChanged;

    public event EventHandler<SystemClockChangedEventArgs> SystemClockChanged
    {
        add
        {
            AddRef();
            _systemClockChanged += value;
        }
        remove
        {
            RemoveRef();
            _systemClockChanged -= value;
        }
    }

    protected virtual void OnSystemClockChanged(SystemClockChangedEventArgs e)
    {
        var handler = _systemClockChanged;
        if (handler != null) handler(this, e);
    }

    private void AddRef()
    {
        if (Interlocked.Increment(ref _refCount) == 1)
        {
            SystemEvents.TimeChanged += SystemEventsOnTimeChanged;
        }
    }

    private void RemoveRef()
    {
        if (Interlocked.Decrement(ref _refCount) == 0)
        {
            SystemEvents.TimeChanged -= SystemEventsOnTimeChanged;
        }
    }

    private void SystemEventsOnTimeChanged(object sender, EventArgs eventArgs)
    {
        OnSystemClockChanged(new SystemClockChangedEventArgs());
    }
}

Then inside our CustomPlatformEnlightenmentProvider I can return it when asked inside GetService. I haven’t reflected that change in the implementation listed below so beware, understand what’s happening, and choose your INotifySystemClockChanged implementation wisely before using this in your system…

UPDATE 2: Slight improvement…

I’ve only just spotted that the RX factory method CurrentPlatformEnlightenmentProvider.GetService() is marked as virtual. So I can inherit from this, override and provide my custom class where applicable. This resolves any issue I had regarding reflection. Now the enlightenment provider is pretty simple:

public class CustomPlatformEnlightenmentProvider : CurrentPlatformEnlightenmentProvider
{
    public override T GetService<T>(object[] args)
    {
        var t = typeof(T);
        if (t == typeof (INotifySystemClockChanged))            
            return (T)(object)new SystemEventsSystemClockMonitor();            

        return base.GetService<T>(args);
    }
}

Happy days…

Customised RX classes, from before Microsoft proposed solution, which were used during investigation:

public class CustomPlatformEnlightenmentProvider : IPlatformEnlightenmentProvider
{
    private readonly ILogger _logger;
    private readonly bool _useCustomImplementations;

    public CustomPlatformEnlightenmentProvider(ILogger logger)
    {
        if (logger == null) throw new ArgumentNullException("logger");
        
        _logger = logger;

        _useCustomImplementations = Session.IsRunningRemotely || Debugger.IsAttached;
        if (_useCustomImplementations)
            _logger.Info("Platform enlightenment will run ConfigurablePeriodicTimerSystemClockMonitor.");
    }

    public T GetService<T>(params object[] args) where T : class
    {
        var t = typeof(T);
       
        if (t == typeof(IExceptionServices))
        {
            var type = Type.GetType("System.Reactive.PlatformServices.ExceptionServicesImpl, System.Reactive.PlatformServices", true);                
            return (T)Activator.CreateInstance(type);
        }

        if (t == typeof(IConcurrencyAbstractionLayer))
        {
            var type = Type.GetType("System.Reactive.Concurrency.ConcurrencyAbstractionLayerImpl, System.Reactive.PlatformServices", true);                
            return (T)Activator.CreateInstance(type);
        }

        if (t == typeof(IScheduler) && args != null)
        {
            switch ((string)args[0])
            {
                case "ThreadPool":
                    return (T)(object)ThreadPoolScheduler.Instance;
                case "TaskPool":
                    return (T)(object)TaskPoolScheduler.Default;
                case "NewThread":
                    return (T)(object)NewThreadScheduler.Default;
            }
        }

        if (t == typeof(INotifySystemClockChanged))
        {
            return (T) (_useCustomImplementations
                ? new ConfigurablePeriodicTimerSystemClockMonitor(
                    TimeSpan.FromSeconds(1), 
                    _logger,
                    syncMaxRetries: 100,
                    syncMaxDelta: 10)
                : (INotifySystemClockChanged) new PeriodicTimerSystemClockMonitor(TimeSpan.FromSeconds(1)));
        }


#if HAS_TPL46
        if (t == typeof(ITaskServices))
        {
            return (T)(object)new TaskServicesImpl();
        }
#endif

        if (t == Type.GetType("System.Reactive.Linq.IQueryServices, System.Reactive.Linq"))
        {
            //
            // We perform this Debugger.IsAttached check early rather than deferring
            // the decision to intercept query operator methods to the debugger
            // assembly that's dynamically discovered here. Also, it's a reasonable
            // expectation it'd be pretty hard to turn on interception dynamically
            // upon a debugger attach event, so we should make this check early.
            //
            // In the initial release of v2.0 (RTM), we won't have the corresponding
            // debugger assembly available yet, so the dynamic load would always
            // fail. We also don't want to take the price of (an attempt to) a dynamic
            // assembly load for the regular production case.
            //
            if (Debugger.IsAttached)
            {
#if NETCF35
                var name = "System.Reactive.Linq.QueryDebugger, System.Reactive.Debugger";
#else
#if (CRIPPLED_REFLECTION && HAS_WINRT)
                var ifType = t.GetTypeInfo();
#else
                var ifType = t;
#endif
                var asm = new AssemblyName(ifType.Assembly.FullName);
                asm.Name = "System.Reactive.Debugger";
                var name = "System.Reactive.Linq.QueryDebugger, " + asm.FullName;
#endif
                var dbg = Type.GetType(name, false);
                if (dbg != null)
                    return (T)(object)Activator.CreateInstance(dbg);
            }
        }            

        return null;
    }
}

public class ConfigurablePeriodicTimerSystemClockMonitor : INotifySystemClockChanged
{
    private readonly TimeSpan _period;
    private readonly ILogger _logger;
    private readonly SerialDisposable _timer;

    private DateTimeOffset _lastTime;
    private EventHandler<SystemClockChangedEventArgs> _systemClockChanged;

    private readonly int _syncMaxRetries = 100;
    private readonly double _syncMaxDelta = 10;
    private readonly int _maxError = 100;

    /// <summary>
    /// Creates a new monitor for system clock changes with the specified polling frequency.
    /// </summary>
    /// <param name="period">Polling frequency for system clock changes.</param>
    /// <param name="logger"></param>
    /// <param name="syncMaxRetries"></param>
    /// <param name="syncMaxDelta"></param>
    /// <param name="maxError"></param>
    public ConfigurablePeriodicTimerSystemClockMonitor(TimeSpan period, ILogger logger, int syncMaxRetries = 100, int syncMaxDelta = 10, int maxError = 100)
    {
        if (logger == null) throw new ArgumentNullException("logger");

        _period = period;
        _logger = logger;
        _syncMaxRetries = syncMaxRetries;
        _syncMaxDelta = syncMaxDelta;
        _maxError = maxError;

        _timer = new SerialDisposable();
    }

    /// <summary>
    /// Event that gets raised when a system clock change is detected.
    /// </summary>
    public event EventHandler<SystemClockChangedEventArgs> SystemClockChanged
    {
        add
        {
            NewTimer();

            _systemClockChanged += value;
        }

        remove
        {
            _systemClockChanged -= value;

            _timer.Disposable = Disposable.Empty;
        }
    }

    private void NewTimer()
    {
        _timer.Disposable = Disposable.Empty;

        double diff;
        var n = 0;
        do
        {
            _lastTime = SystemClock.UtcNow;
            _timer.Disposable = PlatformEnlightenmentProvider.Current.GetService<IConcurrencyAbstractionLayer>().StartPeriodicTimer(TimeChanged, _period);
            diff = Math.Abs((SystemClock.UtcNow - _lastTime).TotalMilliseconds);
        } while (diff > _syncMaxDelta && ++n < _syncMaxRetries);

        _logger.Info("Took {0} attempts to start new timer.", n);

        if (n >= _syncMaxRetries)
        {
            _logger.Warning("Failed to start monitoring system clock changes (Configurable Impl). diff={0}", diff);
            throw new InvalidOperationException(
                "Failed to start monitoring system clock changes (Configurable Impl).");
        }
    }

    private void TimeChanged()
    {
        var now = SystemClock.UtcNow;
        var diff = now - (_lastTime + _period);
        if (Math.Abs(diff.TotalMilliseconds) >= _maxError)
        {
            var scc = _systemClockChanged;
            if (scc != null)
                scc(this, new SystemClockChangedEventArgs(_lastTime + _period, now));

            _logger.Warning("Clock Monitor exceeded max error, initiating new timer. Vars: now={0}, _lastTime={1}, diff={2}", now.ToString("O"), _lastTime.ToString("O"), diff);

            NewTimer();
        }
        else
        {
            _lastTime = SystemClock.UtcNow;
        }
    }
}

 

.Net, C#, MahApps, UI, WPF, xaml

Using MahApps Dialog Boxes in a MVVM Setup

Finally, after a couple of years of take, take, take; I’ve made a contribution to MahApps.  Working in a financial institution it’s not always easy to commit back to open source projects, so with a little bit of out-of-hours work I’ve solved a little problem I’ve seen a few people asking: “how do you use MahApps dialog boxes in an MVVM setup?”  And now my conscience is clear. 😉

Now You Can Launch a Dialog Box From a View Model.

There’s a couple of simple things you have to do:

1) Use an attached property in your Window to register your view model with the dialog sub-system.

Assuming your View’s DataContext is set to the view model from where you want to launch the dialog, add these attributes:


<Controls:MetroWindow 

        xmlns:Dialog="clr-namespace:MahApps.Metro.Controls.Dialogs;assembly=MahApps.Metro" 
        Dialog:DialogParticipation.Register="{Binding}"
 >

2) Grab & Use DialogCoordinator to open dialogs.

You can instantiate DialogCoordinator directly, or, good citizens will probably want to inject in the interface IDialogCoordinator into their view model.  This will play nicely with TDD, and is agnostic to whatever DI framework you may be using.

Without a DI framework you could just do something like this:


new MainWindowViewModel(DialogCoordinator.Instance);

Opening up a dialog from your view model is now easy, using the IDialogCoordinator instance.  To most methods the first parameter named “context” will typically be your view model.  This is how the coordinator will match the view model to the window (with what was registered in step 1) and display the dialog.  If you have multiple windows open, the dialog will display on the correct window.  Show your dialog from inside your view model just like this:


_dialogCoordinator.ShowMessageAsync(this, "Message from VM", "MVVM based dialogs!")

If you want to see this in action and follow the code through open up the MahApps MetroDemo project (part of the MahApps source code), and launch from the “Dialogs” Menu:

Dialogs via MVVM in MahApps
Dialogs via MVVM in MahApps

This should make it into release 1.2.0.

.Net, C#, Material Design, UI, UX, WPF, xaml

Material Design Themed TimePicker and Clock Controls for WPF

I’ve managed to get the existing WPF controls; DatePicker & Calendar themed as part of Material Design in XAML Toolkit as described in this blog post.

But the fun part was cranking a couple of brand new controls to build the Material Design time picker experience:

  • TimePicker
  • Clock

These are sibling controls to the existing DatePicker and Calendar controls.  I wanted to keep the API experience similar so you can dive straight in without any kind of learning curve.  The Clock can be used in isolation, or use the DatePicker for an easy picker/popup/drop down behaviour.

Here’s a static glimpse at the picker:

Material Design Time Picker

And here’s a gif of the clock in action:

Material Design Clock Demo

There’s nothing complicated about using these, but you will need to get Material Design In XAML Toolkit referenced and set up in your app. Follow the initial tutorial, and head over to GitHub to download the source/examples project.

.Net, C#, Material Design, UI, UX, WPF, xaml

Material Design DatePicker/Calendar Style for WPF

Howdi,

After a bit of toil I have the DatePicker and Calendar WPF control styles done for Material Design in XAML Toolkit. I hope you guys like it!

(Edit: TimePicker & Clock now also available, blogged here)
Material Design templates for DatePicker/Calendar primitive controls.
Material Design templates for DatePicker/Calendar primitive controls.

Please note that the behaviour is not quite identical to that which you might see on Android. These are templates for the existing WPF DatePicker and Calendar primitive controls, and thus, some of the behaviour around month/year selection is driven by the nature of those controls. There is no modal dialog, as I don’t want these templates to get confused with any requirement/API used to manage dialogs in WPF.

I must say that I believe that it is testament to the original design of WPF/XAML – which is now a mature technology – that I could slot these styles in pretty much seamlessly for a control whose code base is around 8 years old. Note that some extra code has gone in to the Material Design Toolkit, bit this is wrapped inside the new templates and thus if you consume these templates you need never concern yourself with it.

Getting started:

If you haven’t taken a look at Material Design in XAML Toolkit yet (or indeed Dragablz) here is a blog post to get started, or download the source from GitHub and fire up the demo projects:

  • MaterialDesignColors.WpfExample
  • MahMaterialDragablzMashUp

Thanks due:

.Net, C#, Material Design, UI, UX, WPF, xaml

Material Design In XAML – Mash Up!

I have previously posted about the Material Design theme for Dragablz.  In this post I will describe how I arrived at this application mock-up, by combining Dragablz, Material Design in XAML Toolkit, and MahApps:

Material Design Demo
Material Design Demo

My initial task when creating that style was to create a separate, and composable way to define the Material Design colour palette for your application.  Making the separation between the colours and the Dragablz Material Design theme immediately paid benefit.  Being a big fan of MahApps and I was easily able to take things a step further and use the palette in conjunction with a MahApps MetroWindow. Encouraging MahApps to pick up my Material Design palette turned out to be easy because of the way the MahApps guys had also separated out their accents.  Very quickly, I had a MahApps MetroWindow up and running, using MahApps themed controls, the Dragablz Material Design theme, and all of which were using the Material Design palette.  It looked pretty good straight away.

I’ve previously posted on how to choose a Material Design palette, but for a refresher, take a look at this App.xaml.

In addition to the Material Design palette, you need to set a base theme; light or dark.  So add this resource dictionary to your App.xaml:

<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />  

Getting MahApps to use the Material Design palette only takes a few extra lines in your App.xaml.  Firstly, merge in some of the usual MahApps dictionaries:

<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />

Then, where you specify the primary Material Design colour, setup the MahApps brushes, but instead of pulling in one of the MahApps accent dictionaries, configure them manually, to use the Material Design palette:

<SolidColorBrush x:Key="HighlightBrush" Color="{StaticResource Primary700}" options:Freeze="True" />
<SolidColorBrush x:Key="AccentColorBrush" Color="{StaticResource Primary500}" options:Freeze="True" />
<SolidColorBrush x:Key="AccentColorBrush2" Color="{StaticResource Primary400}" options:Freeze="True" />
<SolidColorBrush x:Key="AccentColorBrush3" Color="{StaticResource Primary300}" options:Freeze="True" />
<SolidColorBrush x:Key="AccentColorBrush4" Color="{StaticResource Primary200}" options:Freeze="True" />
<SolidColorBrush x:Key="WindowTitleColorBrush" Color="{StaticResource Primary700}" options:Freeze="True" />
<SolidColorBrush x:Key="AccentSelectedColorBrush" Color="{StaticResource Primary500Foreground}" options:Freeze="True" />

For a complete example see this App.xaml.

Any controls added to your Window (or Dragablz TabablzControl) will now default to MahApps styles, but use the Material Design palette, leaving your application looking pretty good. Having got to this point myself, I couldn’t help but start playing around a bit further with some Material Design. I created a list box with a few cards and the result looked pretty promising:

MaterialDesignEarlyPrototype

It wasn’t long before I went even further and started styling a whole bunch of controls, and ended up with these:

MaterialDesignDemo2

I’ve packaged all these themes (and will continue to add to) on NuGet:

Install-Package MaterialDesignThemes

Where appropriate in your app you can include one or more of the contained resource dictionaries and use the Material Design style for a control in place of the MahApps. All of your other controls will still use the MahApps themes, meaning your application should always look great. A thorough-bred mash-up 🙂

To select the appropriate resource dictionary and style name the best thing to do is download the source/demo solution from GitHub and run the two projects in the solution:

  • MahMaterialDragablzMashUp
  • MaterialDesignColors.WpfExample

Or, take a look at this MainWindow.cs.

Hope that all helps you get a good looking application up and running quickly!

As an end note I must mention this great piece of styling in WinForms, which inspired me to create the Material Design theme for Dragablz in the first place.

.Net, C#, Material Design, UI, UX, WinApi, WPF, xaml

How to use the Material Design theme with Dragablz Tab Control

In this post I will demonstrate how to – very quickly – combine Dragablz and MaterialDesignColors in WPF to create a great looking control which supports full tear out and can use the Google Material Design colour palette.

Dragablz Tab Contrtol and Material Design
Dragablz Tab Contrtol and Material Design

Start a new WPF project.  We rely on two NuGet packages, so get them installed straight away.  Install from the Package Manager tool in Visual Studio, or, from the NuGet console run these commands:

Install-Package Dragablz
Install-Package MaterialDesignColors

In the MainWindow.xaml, setup a simple usage of Dragablz TabablzControl:

<Window x:Class="MaterialDesignTabExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:dragablz="clr-namespace:Dragablz;assembly=Dragablz"
        Title="Material Design Demo" Height="350" Width="525">
    <dragablz:TabablzControl>
        <dragablz:TabablzControl.InterTabController>
            <dragablz:InterTabController />
        </dragablz:TabablzControl.InterTabController>
        <TabItem Header="HELLO">
            <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">Hello World</TextBlock>
        </TabItem>
        <TabItem Header="MATERIAL">
            <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">Material Design</TextBlock>
        </TabItem>
        <TabItem Header="DESIGN">
            <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">Looks Quite Nice</TextBlock>
        </TabItem>
    </dragablz:TabablzControl>
</Window>

Already if you run this project you will have a tab control that supports Chrome-style tearing out of tabs. But it wont look too good. So, the next step is to bring in the Material Design colours, and tell Dragablz to use the Material Design style.

Open up your App.xaml. We have to merge in three dictionaries.  The first two are to set up your Material Design colour palette.  The MaterialDesignColors assembly contains a ResourceDictionary for each color (a collection of hues and accents).  To create a full palette we need to bring in a primary colour, set up some hue brushes, and then bring in a secondary color for our accent color.  The third resource dictionary is to include the Dragablz theme for Material Design.  Finally we instruct our tab control to use the correct style.

Don’t worry, it’s not too complicated.  The full App.xaml is below:

<Application x:Class="MaterialDesignColors.WpfExample.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:dragablz="clr-namespace:Dragablz;assembly=Dragablz"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <!-- primary color -->
                <ResourceDictionary>
                    <!-- include your primary palette -->
                    <ResourceDictionary.MergedDictionaries>
                        <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/MaterialDesignColor.Indigo.xaml" />
                    </ResourceDictionary.MergedDictionaries>
                    <!--
                            include three hues from the primary palette (and the associated forecolours).
                            Do not rename, keep in sequence; light to dark.
                        -->
                    <SolidColorBrush x:Key="PrimaryHueLightBrush" Color="{StaticResource Primary100}"/>
                    <SolidColorBrush x:Key="PrimaryHueLightForegroundBrush" Color="{StaticResource Primary100Foreground}"/>
                    <SolidColorBrush x:Key="PrimaryHueMidBrush" Color="{StaticResource Primary500}"/>
                    <SolidColorBrush x:Key="PrimaryHueMidForegroundBrush" Color="{StaticResource Primary500Foreground}"/>
                    <SolidColorBrush x:Key="PrimaryHueDarkBrush" Color="{StaticResource Primary700}"/>
                    <SolidColorBrush x:Key="PrimaryHueDarkForegroundBrush" Color="{StaticResource Primary700Foreground}"/>
                </ResourceDictionary>

                <!-- secondary colour -->
                <ResourceDictionary>
                    <!-- include your secondary pallette -->
                    <ResourceDictionary.MergedDictionaries>
                        <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/MaterialDesignColor.Yellow.xaml" />
                    </ResourceDictionary.MergedDictionaries>

                    <!-- include a single secondary accent color (and the associated forecolour) -->
                    <SolidColorBrush x:Key="SecondaryAccentBrush" Color="{StaticResource Accent200}"/>
                    <SolidColorBrush x:Key="SecondaryAccentForegroundBrush" Color="{StaticResource Accent200Foreground}"/>
                </ResourceDictionary>

                <!-- Include the Dragablz Material Design style -->
                <ResourceDictionary Source="pack://application:,,,/Dragablz;component/Themes/materialdesign.xaml"/>                

            </ResourceDictionary.MergedDictionaries>

            <!-- tell Dragablz tab control to use the Material Design theme -->
            <Style TargetType="{x:Type dragablz:TabablzControl}" BasedOn="{StaticResource MaterialDesignTabablzControlStyle}" />
        </ResourceDictionary>
    </Application.Resources>
</Application>

And that’s it. Fire up your baby and you are done. You can change the colours by changing the two colour resource dictionaries which are referenced. You can also tweak the hues, but do not change the brush names.  Dragablz will be looking for these.

Links:

Enjoy!

.Net, C#, UI, WPF

MDI in WPF via Dragablz

Dragablz is more than just a Chrome style TabControl for WPF.  Via it’s Layout control it provides docking and tool windows.  Taking the tool windows a step further, they can be used to provide an MDI effect in WPF.  Even better, the MDI environment can reside inside a tab, which, when coupled with Dragablz other tear out and docking features can provide very rich UI Window management for the user.

There’s a couple of properties of the Layout control to consider:

  • FloatingItems – allows any items to be floated on top of the Layout’s content.
  • FloatingItemsSource – allows any items to be floated on top of the Layout’s content.

And a selection of RoutedCommand’s to help out with management of items floated on the Layout:

  • UnfloatItemCommand –
  • MaximiseFloatingItem
  • RestoreFloatingItem
  • TileFloatingItemsCommand
  • TileFloatingItemsVerticallyCommand
  • TileFloatingItemsHorizontallyCommand

Here’s a snippet of an MDI layout from the Dragablz demo on GitHub:

<DockPanel>
    <StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
        <Button Command="{x:Static dockablz:Layout.TileFloatingItemsCommand}"
                CommandTarget="{Binding ElementName=MdiLayout}">Tile Grid</Button>
        <Button Command="{x:Static dockablz:Layout.TileFloatingItemsVerticallyCommand}"
                CommandTarget="{Binding ElementName=MdiLayout}">Tile Horizontal</Button>
        <Button Command="{x:Static dockablz:Layout.TileFloatingItemsHorizontallyCommand}"
                CommandTarget="{Binding ElementName=MdiLayout}">Tile Vertical</Button>
    </StackPanel>
    <dockablz:Layout x:Name="MdiLayout" 
                     FloatingItemHeaderMemberPath="Name"
                     FloatingItemDisplayMemberPath="SimpleContent">            
        <dockablz:Layout.FloatingItems>                
            <dragablzDemo:SimpleViewModel Name="One" SimpleContent="MDI Child One" />                
            <dragablzDemo:SimpleViewModel Name="Two" SimpleContent="MDI Child Two" />                
            <dragablzDemo:SimpleViewModel Name="Three" SimpleContent="MDI Child Three" />
        </dockablz:Layout.FloatingItems>
    </dockablz:Layout>
</DockPanel>

And to illustrate what’s achievable, here’s an MDI layout, inside a tear-able tab:

MDI, operating within a tab.
MDI, operating within a tab.

Links to Dragablz:

.Net, C#, UI, WPF

Dragablz Meets MahApps

Dragablz is getting quite feature rich now, so I have created a demo project to illustrate it in use with another UI library, MahApps.  If you haven’t used MahApps with WPF, it’s a great Metro/ModernUI style and control library to bring your apps bang up to date.

Off the bat, if you are going to use Dragablz and MahApps together you will have to make a decision: use the MahApps MetroWindow, or the Dragablz DragablzWindow (or indeed your own)?

Each option has its advantages.  Primarily; MetrowWindow is a rich Window, with flyouts & custom Window commands, and the DragablzWindow supports transparency to provide a better dragging effect.  See the two gifs for illustration of this point.

Code and XAML-wise there is very little difference.  The demo project on GitHub shows that very little change is required to use Dragablz and MahApps together regardless of how you choose to do it.

Download the project, build it in Visual Studio, and run both applications (DragablzWindowApp & MahAppsWindowApp).  You will see the differences illustrated above, and you will also see very little difference in the XAML required.  The MainWindow.xaml file for each project is almost identical:

It’s also worth checking out the app.xaml to illustrate some of the styling info required.

 

 

 

.Net, C#, UI, WinApi, WPF

Getting Windows Snap to Play with WPF Borderless Windows

In making the Dragablz library I quickly realised I needed be able to push the tabs higher up the window as we see in Chrome, and also, to achieve the IE affect, I really needed Window transparency. Therefore I introduced DragablzWindow.

DragablzWindowSnap

The easiest way to do the above is set the WindowStyle to None. But this has immediate draw backs: no dragging and resizing. Getting the dragging up and running is pretty easy and well illustrated on the web:

MouseLeftButtonDown += (s, e) => DragMove();

But this only partially works with Windows Snap. The Window will snap; left, right, top/maximised. But you cant drag the maximised window down to restore it.

Snap Attack

So I had to blend some aspects of WPF and WinApi to achieve the full effect.

In the XAML template for DragablzWindow I placed a Thumb control behind the content. Note how the hit test is off:

<Thumb Style="{StaticResource InvisibleThumbStyle}"
       IsHitTestVisible="False"
       x:Name="PART_WindowRestoreThumb"/>
<ContentPresenter Margin="4"/>

The hit test is off so it doesn’t interfere with our DragMove. Until the Window becomes maximised. Once the Window becomes maximised we enable the thumb and listen to it’s drag delta. Monitoring the drag delta is where we perform our trick, sending a Windows message to restart the drag as usual, handing back off the Thumb, to an Api instigated drag. Basically a slight re-working of what happens inside Windows.DragMove:

private void WindowMoveThumbOnDragDelta(object sender, DragDeltaEventArgs dragDeltaEventArgs)
{
    if (WindowState != WindowState.Maximized ||
        (!(Math.Abs(dragDeltaEventArgs.HorizontalChange) > 2) &&
         !(Math.Abs(dragDeltaEventArgs.VerticalChange) > 2))) return;

    WindowState = WindowState.Normal;
    Native.SendMessage(CriticalHandle, WindowMessage.WM_LBUTTONUP, IntPtr.Zero, IntPtr.Zero);
    Native.SendMessage(CriticalHandle, WindowMessage.WM_SYSCOMMAND, (IntPtr)SystemCommand.SC_MOUSEMOVE, IntPtr.Zero);
}

Try this on for Resize

To make the Window resizable we get back to the WPF side of things, using another Thumb, this time laid over the content (instead of under). Applying a custom clip, we can make the thumb only hit-able around the border of the Window, leaving the behaviour of the remaining content intact:

protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
    var resizeThumb = GetTemplateChild(WindowResizeThumbPartName) as Thumb;
    if (resizeThumb != null)
    {
        var outerRectangleGeometry = new RectangleGeometry(new Rect(sizeInfo.NewSize));
        var innerRectangleGeometry =
            new RectangleGeometry(new Rect(ResizeMargin, ResizeMargin, sizeInfo.NewSize.Width - ResizeMargin * 2, sizeInfo.NewSize.Height - ResizeMargin*2));
        resizeThumb.Clip = new CombinedGeometry(GeometryCombineMode.Exclude, outerRectangleGeometry,
            innerRectangleGeometry);
    }

    base.OnRenderSizeChanged(sizeInfo);
}

We must now handle the sizing manually, based on how the user drags the thumb around. It’s worth seeing the source code to see how that’s handled.

The Result

A Window which supports:

  • Transparancy
  • Dragging
  • Resizing
  • Snapping
  • And, all of the cool tab features of Dragablz!

DragablzWindowSnap

Source Code

The DragablzWindow is part of the Dragablz project on GitHub. And the style is here.

 

.Net, C#, UI, WPF

Tool Window Enhancements

Time for another quick look at what’s happening with tool windows in Dragablz.

You can now take a tab, tear it out, and then drop it straight back in, but as a tool window…neat!  The tool window can then be popped out, back into a first class window and tab control of it’s own.

DragInAndOutOfToolWindows

At some point I will try and get floating tabs on the tool window layer, so you can organise even further, but still in the user-friendly manner I am trying to push in Dragablz.

Also, soon I hope to create a nice demo app mixing in a Modern UI theme courtesy of MahApps, demonstrating how to really re-ignite the power of desktop apps, so keep an eye out.

If you like this library please help motivate me and star it on GitHub!