Showing posts with label wpf. Show all posts
Showing posts with label wpf. Show all posts

Friday, 3 April 2020

User friendly and Flexible numeric textbox for decimal numbers in WPF

Adapting WPF to allow a numeric textbox in WPF sounds very trivial, but it is not! A user friendly textbox in WPF couldhave different aspects. It could be possible to: - Only allow numbers or decimal separator - Possible to specify number of digits for integer part and number of digits for decimal part - Specify an empty default value - Still rely on default components such as WPF Textbox The following WPF Converter allows to restrict user input using ConvertBack method. Usually a developer implements the Convert method to transform output, here we use ConvertBack to filter input to only allow numbers or decimal separator.

NumericFormatConverter


using Hemit.OpPlan.Common;
using System;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Windows.Data;
namespace Hemit.OpPlan.Client.Infrastructure.Converters
{
    public class NumericFormatConverter : IValueConverter
    {
        public int IntegerLength { get; set; }
        public int DecimalLength { get; set; }
        public string DefaultValue { get; set; }
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return value;       
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null)
                return DefaultValue;
            string adjustedValue = AdjustValueToAcceptingFormat(value.ToString());
            return adjustedValue;
        }
        private string AdjustValueToAcceptingFormat(string value)
        {
            if (string.IsNullOrEmpty(value))
                return DefaultValue;
            char decimalSeparator = Thread.CurrentThread?.CurrentCulture?.NumberFormat?.NumberDecimalSeparator.ToCharArray().First() ?? ',';
            string[] compounds = value.Split(new[] { decimalSeparator });
            if (compounds.Length <= 0)
            {
                return DefaultValue; //default to zero
            }
            if (compounds.Length == 1)
            {
                return NumericDigits(compounds[0], decimalSeparator);
            }
            return $"{NumericDigits(compounds[0], decimalSeparator).Truncate(3)}{decimalSeparator}{NumericDigits(compounds[1], decimalSeparator).Truncate(1)}";
        }
        private static string NumericDigits(string input, char decimalSeparator)
        {
            return string.Join("", input.ToCharArray().Where(ch => Char.IsDigit(ch) || ch == decimalSeparator)).Truncate(3);
        }
    }
}

If you rely on MVVM, you can bind up a numeric value with a proxy property with datatype string for flexible input.

   [State]
   [NotifyPropertyChanged(true)]
   [AffectsOtherProperty("BodyMassIndex")]
   [Range(0.0, 500, ErrorMessage = @"Max Weight is surpassed")]
   public double? Weight { get; set; }

   private string _weightInputValue;

   public string WeightInputValue
   {
       get { return _weightInputValue; }
       set
       {
           if (_weightInputValue != value)
           {
               _weightInputValue = value;
               double weight;
               if (double.TryParse(_weightInputValue, out weight))
               {
                   Weight = weight;
               }
               RaisePropertyChanged(() => WeightInputValue);
           }
       }
   }

Never mind the Postsharp aspects for State, NotifyPropertyChanged and AffectsOtherProperty listed here, they are not necessary in your use case. But shows a real world scenario. In WPF frontend you can then bind up the WPF converter like this:

      <TextBlock Grid.Row="7" Grid.Column="2" Margin="2" Text="Vekt (kg)" VerticalAlignment="Center" HorizontalAlignment="Left" />
                            <TextBox Grid.Row="7" Grid.Column="4" MaxLength="5" Height="24" behaviors:TextBoxRegExBehavior.RegularExpressionProperty="^\d+[,|.]*\d*$" FontWeight="Normal"
                             HorizontalAlignment="Left"
                             behaviors:TextBoxRegExBehavior.MaxLength="5" behaviors:TextBoxRegExBehavior.MustParseToType="{x:Type sys:Double}" behaviors:TextBoxRegExBehavior.EmptyValue="0" 
                             Margin="2,2,2,2" Width="40" Text="{Binding WeightInputValue, Converter={StaticResource numericFormatConverter}, ConverterCulture={x:Static gl:CultureInfo.CurrentCulture}, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=true}" 
                             Style="{StaticResource ReadOnlyTextBoxStyleHidingZero}" IsReadOnly="{Binding IsEditMode, Converter={StaticResource invertedBoolConverter}}" TabIndex="35" />

Again, much custom stuff here, but the key thing to notice is that you only need to make sure you bind against the proxy property of type string, the WPF converter numericFormatConverter handles the formatting of the input.
   <converters:NumericFormatConverter x:Key="numericFormatConverter" IntegerLength="3" DecimalLength="1" DefaultValue=""></converters:NumericFormatConverter>

Thursday, 9 August 2018

Detect USB drives in a WPF application



We can use the class System.IO.DriveInfo to retrieve all the drives on the system and look for drives where the DriveType is Removable. In addition, the removable drive (USB usually) must be ready, which is accessible as the property IsReady. First off, we define a provider to retrieve the removable drives:
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;

    namespace TestPopWpfWindow
    {

    public static class UsbDriveListProvider
    {


        public static IEnumerable<DriveInfo> GetAllRemovableDrives()
        {
            var driveInfos = DriveInfo.GetDrives().AsEnumerable();
            driveInfos = driveInfos.Where(drive => drive.DriveType == DriveType.Removable);
            return driveInfos;
        }

    }
}

Let us use the MVVM pattern also, so we define a ViewModelbase class, implementing INotifyPropertyChanged.
using System.ComponentModel;

namespace TestPopWpfWindow
{

    public class ViewModelBase : INotifyPropertyChanged
    {

        public event PropertyChangedEventHandler PropertyChanged;

        public void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }


    }
}
It is also handy to have an implemetation of ICommand:
    using System;
    using System.Windows.Input;

    namespace TestPopWpfWindow
    {

        public class RelayCommand : ICommand
        {

            private Predicate<object> _canExecute;

            private Action<object> _execute;  


            public RelayCommand(Predicate<object> canExecute, Action<object> execute)
            {
                _canExecute = canExecute;
                _execute = execute;
            }

            public bool CanExecute(object parameter)
            {
                return _canExecute(parameter); 
            }

            public event EventHandler CanExecuteChanged;

            public void Execute(object parameter)
            {
                _execute(parameter); 
            }

        }
    }

We also set the DataContext of MainWindow to an instance of a demo view model defined afterwards:
namespace TestPopWpfWindow
{

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        public MainWindow()
        {
            InitializeComponent();
            DataContext = new UsbDriveInfoDemoViewModel();
        }

    }
}

We then define the view model itself and use System.Management.ManagementEventWatcher to look for changes in the drives mounted onto the system.
  using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Management;
    using System.Windows;
    using System.Windows.Input;

    namespace TestPopWpfWindow
    {

        public class UsbDriveInfoDemoViewModel : ViewModelBase, IDisposable
        {

            public UsbDriveInfoDemoViewModel()
            {
                DriveInfos = new List<DriveInfo>();
                ReloadDriveInfos();
                RegisterManagementEventWatching(); 
                TargetUsbDrive = @"E:<"; 
                AccessCommand = new RelayCommand(x => true, x => MessageBox.Show("Functionality executed."));
            }

            public int UsbDriveCount { get; set; }

            private string _targetUsbDrive;

            public string TargetUsbDrive
            {
                get { return _targetUsbDrive; }
                set
                {
                    if (_targetUsbDrive != value)
                    {
                        _targetUsbDrive = value; 
                        RaisePropertyChanged("TargetUsbDrive");
                        RaisePropertyChanged("DriveInfo");
                    }
                }
            }

            public ICommand AccessCommand { get; set; }

            private void ReloadDriveInfos()
            {
                var usbDrives = UsbDriveListProvider.GetAllRemovableDrives();

                Application.Current.Dispatcher.Invoke(() =>
                {
                    DriveInfos.Clear();

                    foreach (var usbDrive in usbDrives)
                    {
                        DriveInfos.Add(usbDrive);
                    }
                    UsbDriveCount = DriveInfos.Count;
                    RaisePropertyChanged("UsbDriveCount");
                    RaisePropertyChanged("DriveInfos");
                }); 
            }

            public List<DriveInfo> DriveInfos { get; set; }

            private ManagementEventWatcher _watcher;

            private void RegisterManagementEventWatching()
            {
                _watcher = new ManagementEventWatcher();
                var query = new WqlEventQuery("SELECT * FROM Win32_VolumeChangeEvent");
                _watcher.EventArrived += watcher_EventArrived;
                _watcher.Query = query;
                _watcher.Start();
            }

            private void watcher_EventArrived(object sender, EventArrivedEventArgs e)
            {
                Debug.WriteLine(e.NewEvent);
                ReloadDriveInfos();
            }



            public void Dispose()
            {
                if (_watcher != null)
                {
                    _watcher.Stop();
                    _watcher.EventArrived -= watcher_EventArrived;
                }
            }

        }

    }

We also define a WPF multi-converter next to enable the button:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Windows.Data;

namespace TestPopWpfWindow
{

    public class UsbDriveAvailableEnablerConverter : IMultiValueConverter
    {

        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if (values == null || values.Count() != 2)
                return false;

            var driveInfos = values[1] as List<DriveInfo>;
            var targetDrive = values[0] as string; 
            if (driveInfos == null || !driveInfos.Any() || string.IsNullOrEmpty(targetDrive))
                return false;
            return driveInfos.Any(d => d.IsReady && d.Name == targetDrive);
        }




        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

And we define a GUI to test this code:
<Window x:Class="TestPopWpfWindow.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TestPopWpfWindow"
        Title="MainWindow" Height="350" Width="525">

    <Window.Resources>

        <Style x:Key="usbLabel" TargetType="Label">
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsReady}" Value="False">
                    <Setter Property="Background" Value="Gray"></Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding IsReady}" Value="True">
                    <Setter Property="Background" Value="Green"></Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>

        <local:UsbDriveAvailableEnablerConverter x:Key="usbDriveAvailableEnablerConverter"></local:UsbDriveAvailableEnablerConverter>

    </Window.Resources>


    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>

        </Grid.RowDefinitions>

        <StackPanel Orientation="Vertical">
            <TextBlock Text="USB Drive-detector" FontWeight="DemiBold" HorizontalAlignment="Center" FontSize="14" Margin="2"></TextBlock>
            <TextBlock Text="Removable drives on the system" FontWeight="Normal" HorizontalAlignment="Center" Margin="2"></TextBlock>
            <TextBlock Text="Drives detected:" FontWeight="Normal" HorizontalAlignment="Center" Margin="2"></TextBlock>
            <TextBlock Text="{Binding UsbDriveCount, UpdateSourceTrigger=PropertyChanged}" FontWeight="Normal" HorizontalAlignment="Center" Margin="2"></TextBlock>

            <ItemsControl Grid.Row="0" ItemsSource="{Binding DriveInfos, UpdateSourceTrigger=PropertyChanged}"
                          Width="100" BorderBrush="Black" BorderThickness="1">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Vertical">
                            <Label Style="{StaticResource usbLabel}" Width="32" Height="32" FontSize="18" Foreground="White" Content="{Binding Name}">
                            </Label>
                        </StackPanel>

                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </StackPanel>

        <Button Grid.Row="1" Height="24" Width="130" VerticalAlignment="Top" Margin="10" Content="Access functionality" Command="{Binding AccessCommand}">
            <Button.IsEnabled>
                <MultiBinding Converter="{StaticResource usbDriveAvailableEnablerConverter}">
                    <MultiBinding.Bindings>
                        <Binding Path="TargetUsbDrive"></Binding>
                        <Binding Path="DriveInfos"></Binding>
                    </MultiBinding.Bindings>
                </MultiBinding>
            </Button.IsEnabled>
        </Button>

        <StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center">
            <TextBlock Margin="2" Text="Target this USB-drive:"></TextBlock>
            <TextBox Margin="2" Text="{Binding TargetUsbDrive, UpdateSourceTrigger=LostFocus}" Width="100"></TextBox>
        </StackPanel>

    </Grid>

</Window>

I have now provided the Visual Studio 2013 solution with the code above available for download here:

Download VS 2013 Solution with source code above

Monday, 3 October 2016

Disposing objects instantiated by MEF

Experienced developers that has worked with the official extensibility framework in .NET, the Managed Extensibility Framework (MEF) allows the composition of different parts into more composite parts through composition. MEF has got similarities to other IoC framework, where you register components and then make use of them in other components. However, with MEF there is a caveat and an important one too!
MEF beautifully abstracts away the IoC container and lets you specify parts that can be epxorted and imported. But if you inspect your application or system with a memory profiler such as JetBrains DotMemory or Red Gate Memory Profiler, you soon find out that much of the memory used by your applications is not properly disposed, i.e freed up after use. This is the case for nonshared (non-singleton) objects that are exported and then instantiated (imported). This means that your application will through continued use hold more and more memory. It will leak memory. By inspecting the memory dependency chain, one can see that MEF is the reason why the nonshared objects instantiated by MEF is not released, even after the objects are issued to be disposed.

I use in this code the ServiceLocator found with the Enterprise Library. Make note that my code will break up the dependency chain that hinders the object, but it does not mean that necessarily objects will be disposed right away. After all, .NET is managed and decides itself when objects are really to be disposed. But if you strive with releasing objects that are tied to memory even after use and also use MEF, read on.

I use the Factory pattern here to instantiate objects. I also use the new feature in .NET 4.5 that is called the ExportLifeTimeContext. I also use the ExportFactory in MEF inside a class called ExportFactoryInstantiator that does actual instantiation of the objects and keeping a track of these ExportLifeTimeContext objects. As noted, you need at least .NET 4.5 to make this work. For .NET 4.0 users, sorry - you are out of luck as far as I know. Upgrade your application to .NET 4.5 if possible and get the newer version of MEF.

The code below shows how you can accomplish control over memory resources using MEF:

MefFactory.cs

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using Microsoft.Practices.ServiceLocation;

namespace SomeAcme.Client.Infrastructure.IoC
{

    /// <summary>
    /// Factory for MEF Parts that is able to actually dispose MEF instantiated objects and get around bug in MEF 
    /// where objects never gets properly GC-ed when they should dispose
    /// </summary>
    /// <typeparam name="T"></typeparam>
    [Export]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class MefFactory<T> : IPartImportsSatisfiedNotification 
    {

        /// <summary>
        /// Backlog that keeps track of mef parts that are instantiated via this factory 
        /// </summary>
        private static readonly ConcurrentBag<ExportLifetimeContext<T>> MefParts = new ConcurrentBag<ExportLifetimeContext<T>>();

        /// <summary>
        /// Disposes parts added to the mef factory backlog of type T
        /// </summary>
        public static void DisposeMefParts()
        {
            ExportLifetimeContext<T> item;
            while (MefParts.TryTake(out item))
            {
                if (item != null)
                    item.Dispose();
            }
        }

        /// <summary>
        /// Disposes parts added to the mef factory backlog of type T by a given predicate condition
        /// </summary>
        public static void DisposeMefParts(Predicate<T> condition)
        {
            ExportLifetimeContext<T> item;
            List<ExportLifetimeContext<T>> lifeTimeProlonged = new List<ExportLifetimeContext<T>>();
            while (MefParts.TryTake(out item))
            {
                if (item != null && condition(item.Value))
                    item.Dispose();
                else 
                    lifeTimeProlonged.Add(item);
            }
            if (lifeTimeProlonged.Any())
            {
                //Add back again the parts not matching condition to the Concurrent bag
                foreach (var part in lifeTimeProlonged)
                {
                    MefParts.Add(part);
                }
            }
        }

        public void OnImportsSatisfied()
        {
            //marker interface
        }
   
        /// <summary>
        /// Resolves the mef part
        /// </summary>
        /// <returns></returns>
        public static T Resolve()
        {
            var factoryInstantiator = ServiceLocator.Current.GetInstance<ExportFactoryInstantiator<T>>();
            MefParts.Add(factoryInstantiator.Lifetime);
            return factoryInstantiator.Instance;
        }

    }
}



using System.ComponentModel.Composition;

namespace SomeAcme.Client.Infrastructure.IoC
{

    [Export]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class ExportFactoryInstantiator<T> : IPartImportsSatisfiedNotification
    {

        [Import]
        public ExportFactory<T> Factory { get; set; }

        public T Instance { get; private set; }

        private ExportLifetimeContext<T> _lifeTime;

        public ExportLifetimeContext<T> Lifetime
        {
            get { return _lifeTime; }
        } 

        public void OnImportsSatisfied()
        {
            _lifeTime = Factory.CreateExport();
            Instance = _lifeTime.Value;
        }

        public bool DisposeOnDemand()
        {
            if (_lifeTime == null)
                return false;
            _lifeTime.Dispose();
            return Instance == null;
        }

    }

}

To instantiate an object, you do:

 var somepart = MefFactory.Resolve();

When you are done using the object you can dispose it with:

 MefFactory.DisposeMefParts(); 

Please note, you can use a Predicate here to filter out which object you want to keep and which ones to dispose.

And once more, the immediate disposal of the object is not guaranteed, since GC will still control the true lifetime of objects. You can use GC.Collect(); to force releasing disposed objects, but that will usually degrade application performance.

But the techniques shown here will over time really improve your application by gaining control on the memory footprint your application uses.

Resources

[1] Enterprise Library: https://msdn.microsoft.com/library/cc467894.aspx
[2] ServiceLocator class: https://msdn.microsoft.com/en-us/library/microsoft.practices.servicelocation.servicelocator(v=pandp.51).aspx
[3] ServiceLocator pattern: https://msdn.microsoft.com/en-us/library/ff648968.aspx
[4] Managed Extensibility Framework: https://msdn.microsoft.com/en-us/library/dd460648(v=vs.110).aspx

Friday, 9 October 2015

Switchbased delay with Dispatcher in WPF

Extended my DispatcherUtil class today, with SwitchBasedDelay! Example of calling the new method, note we use a fixed Guid in this case to "group" calls into a logical switch:

 DispatcherUtil.SwitchbasedDelayedInvokeAction(Guid.Parse(@"{4E101F98-31F3-4E19-B18B-2820AEA60A1B}"), () =>
     {
      PublishEvent<ProcedureFreeTypeTextChangedEvent, ProcedureFreeTypeTextChangedEventArg>(
       new ProcedureFreeTypeTextChangedEventArg
        {
          FreshId = Context.CurrentOperationalUnit.FreshId,
          ProcedureCode = Model.ProcedureTypeFreeText,
          OperationId = Model.OperationId
        });
      }, 2000);


using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Windows.Threading;

namespace SomeAcme.SomePackage
{

    /// <summary>
    /// Contains helper methods for dispatcher operations 
    /// </summary>
    public static class DispatcherUtil
    {

        private static readonly List<DelayedAction> ActionsRegistered = new List<DelayedAction>();

        private static readonly Dictionary<Guid?, bool> SwitchDelays = new Dictionary<Guid?, bool>();

        /// <summary>
        /// Executes an action passed into this method by a timeout measured in millisecond in a switch-based manner. 
        /// </summary>
        /// <param name="keyToken">A key token (Guid) to identity the switch (basic grouping)</param>
        /// <param name="executeAction">Action to execute</param>
        /// <param name="timeOut">The timeout to wait before executing (in milliseconds)</param>
        /// <param name="priority">Priority of the dispatcher operation</param>
        /// <returns></returns>
        public static bool SwitchbasedDelayedInvokeAction(Guid keyToken, Action executeAction, int timeOut,
            DispatcherPriority priority = DispatcherPriority.Background)
        {
            if (SwitchDelays.ContainsKey(keyToken) && SwitchDelays[keyToken])
                return false; //do not execute, already in progress 

            SwitchDelays[keyToken] = true;

            DelayedInvokeAction(executeAction, timeOut, priority, keyToken);
            return true; //delayed action sent off
        }

        /// <summary>
        /// Executes an action passed into this method by a timeout measured in milliseconds
        /// </summary>
        /// <param name="executeAction">Action to execute</param>
        /// <param name="timeOut">The timeout to wait before executing (in milliseconds)</param>
        /// <param name="priority"></param>
        ///    /// <param name="keyToken">A key token to identity the switch (basic grouing). Will be used as a tag on the DispatcherTimer</param>
        public static bool DelayedInvokeAction(Action executeAction, int timeOut, DispatcherPriority priority = DispatcherPriority.Background, Guid? keyToken = null)
        {
            var delayedAction = new DelayedAction(executeAction, timeOut, keyToken);
            ActionsRegistered.Add(delayedAction);
            DispatcherTimer dtimer = new DispatcherTimer(priority);

            dtimer.Interval += new TimeSpan(0, 0, 0, 0, timeOut);
            dtimer.Tag = delayedAction.ExecuteGuid;
            dtimer.Tick += DelayedInvokeTimerTick;
            dtimer.IsEnabled = true;
            dtimer.Start();

            return true;
        }

        private static void DelayedInvokeTimerTick(object sender, EventArgs e)
        {
            var dtimer = sender as DispatcherTimer;
            if (dtimer != null)
            {
                dtimer.IsEnabled = false;
                dtimer.Stop();
                dtimer.Tick -= DelayedInvokeTimerTick; //unsubscribe
                Guid targetActionGuid = (Guid)dtimer.Tag;

                DelayedAction delayedAction = ActionsRegistered.Single(a => a.ExecuteGuid == targetActionGuid);
                delayedAction.ActionToExecute(); //now execute the action 
                ActionsRegistered.Remove(delayedAction);

                if (dtimer.Tag != null)
                {
                    Guid? keyToken = dtimer.Tag as Guid?; 
                    if (SwitchDelays.ContainsKey(keyToken))
                    {
                        SwitchDelays.Remove(keyToken); //remove the switch 
                    } //if 
                } //if 

                // ReSharper disable once RedundantAssignment
                dtimer = null; //ensure free up dispatcher timer - do not starve threading resources 
            } //if 
        }

        /// <summary>
        /// Invokes an action on the current dispatcher, used to execute operations on the GUI thread
        /// </summary>
        /// <param name="executeAction">The action to execute, pass in e.g. delegate { --code lines goes here } </param>
        /// <param name="dispatcherPriority">The priority to give the action on the thread (signal to the WPF messaging queue). Default is background.</param>
        /// <returns>Returns true when the action was dispatched</returns>
        /// <remarks>Default priority is DispatcherPriority.Background</remarks>
        public static bool InvokeAction(Action executeAction, DispatcherPriority dispatcherPriority = DispatcherPriority.Background)
        {
            Dispatcher.CurrentDispatcher.Invoke(new Action(() =>
            {
                executeAction();
            }), dispatcherPriority);
            return true;
        }

        /// <summary>
        /// Asynchronously invokes an action on the current dispatcher, used to execute operations on the GUI thread
        /// </summary>
        /// <param name="executeAction">The action to execute, pass in e.g. delegate { --code lines goes here } </param>
        /// <param name="dispatcherPriority">The priority to give the action on the thread (signal to the WPF messaging queue). Default is background.</param>
        /// <returns>Returns true when the action was dispatched</returns>
        /// <remarks>Default priority is DispatcherPriority.Background</remarks>
        public static bool BeginInvokeAction(Action executeAction, DispatcherPriority dispatcherPriority = DispatcherPriority.Background)
        {
            Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() =>
            {
                executeAction();
            }), dispatcherPriority);
            return true;
        }

        public static void AsyncWorkAndUiThreadUpdate<T>(Dispatcher currentDispatcher, Func<T> threadWork, Action<T> guiUpdate)
        {
            // ReSharper disable once UnusedAnonymousMethodSignature
            ThreadPool.QueueUserWorkItem(delegate(object state)
            {
                T resultAfterThreadWork = threadWork();
                // ReSharper disable once UnusedAnonymousMethodSignature
                // ReSharper disable once UnusedAnonymousMethodSignature
                currentDispatcher.BeginInvoke(DispatcherPriority.Normal, new Action<T>(delegate {
                    guiUpdate(resultAfterThreadWork);
                }), resultAfterThreadWork);

            });
        }

    }
}