WPF using BackgroundWorker vs using Task

Today I’m expanding on the ExampleAppinator post that I made last week which will be the foundation to my examples going forward.  In this I’m going to show an example that simply outputs the contents of the KitchenSink tables into grids…1 set using BackgroundWorker to create threads for doing the fetching of data, the other set is using a Task.

I’ll post the ending source code to the WPF example app at the end of this post.

The first thing I noticed when I put this together is that when there wasn’t a lot of data in the table, it really took little to no time to ever get anything out of the database so it was nealry impossible to see any difference in BackgroundWorker vs Task…which is what lead to me creating KitchenSinkClogger in the ExampleAppinator post.  I created that and let it run for the weekend…it filled up my database with about 250000 records.  Perfect, now I have some meat to sink my teeth into.

Now when I launched the test WPF app, I ran into some real perf problems.  At this stage of the test I had 12 DataGrid’s being loaded up simultaniously, 6 using BackgroundWorker threads, 6 using Task threads.  When I launched it, for about 5 solid minutes nothing happened but churning in the debugger.  I paused it in the debugger a couple times just to verify that there were worker threads churning in the background…and as far as I can tell, none of them should have been on the UI thread so the UI should have never locked up…I’m a bit confused by that one.

From here I had a thought that maybe the app was becoming unresponsive because I was trying to load up 12 DataGrid’s with 250000 records each and it was a memory issues…so I decided to add pagers to my DataGrids…and since that’s a total pain in the backside with normal built in WPF controls I decided to switch over to using Telerik controls at this point since they have a ready made RadDataPager object I could use.  About 10 minutes later…everything was switched over to RadBusyIndicator’s and RadGridView’s with a RadDataPager in place and as I tested out each individual grid they were all working smooth…until…I turned them all on to load at the same time again.  Again the app was brought down to it’s knees in perf.

So this is where I’m at right now as of 5/11/2016.  I think my next move is to make a post on the Telerik forums now that I’m using their controls and see if I get lucky with an answer on how to make my little test more performant…but in all honesty I don’t think it has anything to do with the controls.  I think it has something to do with the threads…and that I’m obviously attaching to the UI thread somewhere.

Update on 5/17/2016 – I got a reply from Telerik and they weren’t able to help figure out where I’m getting the performance hit…next I’m going to try disabling all the grids but one and see what kind of perf I get there…then start adding them back in one at a time…all the while monitoring threads to see if I can notice anything strange going on.

As always I encourage anyone reading this to leave a comment if you have questions or feedback…I know I don’t know what I’m doing…but I’m totally willing to learn new techniques.  🙂

Update on 5/25/2016 – Yes I know I haven’t posted in about a week…I’ve gotten busy at work again which cuts into my post preparation time so :P.  Quality posts take time to put together…and since mine suck it takes less time…but still a lot of time.

Update on 5/31/2016 – I did some work on this today and started by narrowing down the grids being returned from the database to just one.  I had to kill my database with over 1 million records in it and I’m currently rebuilding it…but at the moment I get about 11k records returned so fast that I can’t even see the Busy Indicator come up…so now I’m going to wait for the database to fill up again so I can see that.  Trying to make sure that each piece is working individually.  Once I can prove that the busy indicator comes up for a BackgroundWorker thread…then I’m going to try returning the same set of information using a Task thread to see if there’s any noticible difference.  Anyway…that’s where I’m at with this for now.  Stay tuned…I’ll get this figured out eventually.

Update on 6/1/2016 – So I got 500k records in my database now and tried the grid using the BackgroundWorker thread again.  Low and behold the Busy Indicator shows up…woohoo.  Now onto seeing if I get the same results using a Task instead.

Update on 6/7/2016 – Today I made some great progress.  I learned what’s really hanging up the BW thread and the Task threads both is that I’m creating a whole bunch of them that are all using the same resources…the network…so there’s a ton of waiting and locking and syncronizing that the OS is doing with the threads and it causes the UI to seem like it’s getting hung up because the system is busy doing all this work sync’ing background threads.  What I learned to do is put a lock on the parent DLL object I have for all my Linq classes and models with each BW thread that I create.  This way I’m managing the sync’ing by forcing all the threads to wait until usage of the parent object free’s up.  The UI displays the Busy Indicator…all the worker threads spin up just fine…and the UI stays responsive.  The 1 down side of this that I noticed is now you have to wait for each table to load once at a time…even though the busy indicator is there and gives a good experience to the user, I feel there could be some more done here to improve the data retrieval experience.  Also I couldn’t retrieve a table with 5 million records.  Got an OOM expcetion thrown from Linq.  Stupid Linq.  😛  So I’m off to learn some data virtualization techniques so I can apply them to my example app and see if I can actually get back to my original theme to this post…which is better?  BW or Task?  Man, this post is crossing lots of different disciplines.  I like it!  Stay tuned!!!  🙂  I’ll be posting an update to the source code once I get the data virtualization part figured out…

MainWindow XAML:

<Window Height="350"
        mc:Ignorable="d"
        Title="MainWindow"
        Width="525"
        x:Class="CSharpWPFAppinator.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:local="clr-namespace:CSharpWPFAppinator"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
    <Grid>
        <TabControl x:Name="KitchenSinkTabControl">
            <TabItem    Header="BW - Engine"
                        x:Name="BWEngineTab" />
            <TabItem    Header="BW - History"
                        x:Name="BWHistoryTab" />
            <TabItem    Header="BW - Lifeform"
                        x:Name="BWLifeformTab" />
            <TabItem    Header="BW - Planet"
                        x:Name="BWPlanetTab" />
            <TabItem    Header="BW - Species"
                        x:Name="BWSpeciesTab" />
            <TabItem    Header="BW - Vehicle"
                        x:Name="BWVehicleTab" />
            <TabItem    Header="Task - Engine"
                        x:Name="TaskEngineTab" />
            <TabItem    Header="Task - History"
                        x:Name="TaskHistoryTab" />
            <TabItem    Header="Task - Lifeform"
                        x:Name="TaskLifeformTab" />
            <TabItem    Header="Task - Planet"
                        x:Name="TaskPlanetTab" />
            <TabItem    Header="Task - Species"
                        x:Name="TaskSpeciesTab" />
            <TabItem    Header="Task - Vehicle"
                        x:Name="TaskVehicleTab" />
        </TabControl>
    </Grid>
</Window>

MainWindow CS Code Behind:

using System.Windows;
using System.Windows.Controls;

namespace CSharpWPFAppinator
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            KitchenSinkDLL.KitchenSinkDLL.ConnectionString = @"Data Source=cmd-roswell;Initial Catalog=KitchenSink;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False";

            foreach(TabItem item in KitchenSinkTabControl.Items)
            {
                switch(item.Name)
                {
                    case "BWEngineTab":
                        BWEngineUserControl bwEngineControl = new BWEngineUserControl();
                        bwEngineControl.RefreshData();
                        item.Content = bwEngineControl;
                        break;
                    case "BWHistoryTab":
                        BWHistoryUserControl bwHistoryControl = new BWHistoryUserControl();
                        bwHistoryControl.RefreshData();
                        item.Content = bwHistoryControl;
                        break;
                    case "BWLifeformTab":
                        BWLifeformUserControl bwLifeformControl = new BWLifeformUserControl();
                        bwLifeformControl.RefreshData();
                        item.Content = bwLifeformControl;
                        break;
                    case "BWPlanetTab":
                        BWPlanetUserControl bwPlanetControl = new BWPlanetUserControl();
                        bwPlanetControl.RefreshData();
                        item.Content = bwPlanetControl;
                        break;
                    case "BWSpeciesTab":
                        BWSpeciesUserControl bwSpeciesControl = new BWSpeciesUserControl();
                        bwSpeciesControl.RefreshData();
                        item.Content = bwSpeciesControl;
                        break;
                    case "BWVehicleTab":
                        BWVehicleUserControl bwVehicleControl = new BWVehicleUserControl();
                        bwVehicleControl.RefreshData();
                        item.Content = bwVehicleControl;
                        break;
                    case "TaskEngineTab":
                        TaskEngineUserControl taskEngineControl = new TaskEngineUserControl();
                        taskEngineControl.RefreshData();
                        item.Content = taskEngineControl;
                        break;
                    case "TaskHistoryTab":
                        TaskHistoryUserControl taskHistoryControl = new TaskHistoryUserControl();
                        taskHistoryControl.RefreshData();
                        item.Content = taskHistoryControl;
                        break;
                    case "TaskLifeformTab":
                        TaskLifeformUserControl taskLifeformControl = new TaskLifeformUserControl();
                        taskLifeformControl.RefreshData();
                        item.Content = taskLifeformControl;
                        break;
                    case "TaskPlanetTab":
                        TaskPlanetUserControl taskPlanetControl = new TaskPlanetUserControl();
                        taskPlanetControl.RefreshData();
                        item.Content = taskPlanetControl;
                        break;
                    case "TaskSpeciesTab":
                        TaskSpeciesUserControl taskSpeciesControl = new TaskSpeciesUserControl();
                        taskSpeciesControl.RefreshData();
                        item.Content = taskSpeciesControl;
                        break;
                    case "TaskVehicleTab":
                        TaskVehicleUserControl taskVehicleControl = new TaskVehicleUserControl();
                        taskVehicleControl.RefreshData();
                        item.Content = taskVehicleControl;
                        break;
                    default:
                        break;
                }
            }
        }
    }
}

BackgroundWorkerUserControl:

using KitchenSinkDLL.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using Telerik.Windows.Controls;
using Xceed.Wpf.Toolkit;

namespace CSharpWPFAppinator
{
    public class BackgroundWorkerUserControl<T> : UserControl
    {
        public BackgroundWorkerUserControl()
        {
            BackgroundWorkerGrid = new Grid();
            BackgroundWorkerGrid.ColumnDefinitions.Add(new ColumnDefinition());
            BackgroundWorkerGrid.RowDefinitions.Add(new RowDefinition());
            BackgroundWorkerGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });

            BackgroundWorkerRadGridView = new RadGridView();
            Grid.SetColumn(BackgroundWorkerRadGridView, 0);
            Grid.SetRow(BackgroundWorkerRadGridView, 0);
            BackgroundWorkerGrid.Children.Add(BackgroundWorkerRadGridView);

            BackgroundWorkerRadDataPager = new RadDataPager();
            BackgroundWorkerRadDataPager.AutoEllipsisMode = AutoEllipsisModes.Both;
            BackgroundWorkerRadDataPager.DisplayMode = PagerDisplayModes.All;
            BackgroundWorkerRadDataPager.NumericButtonCount = 10;
            BackgroundWorkerRadDataPager.PageSize = 40;
            BackgroundWorkerRadDataPager.VerticalAlignment = VerticalAlignment.Bottom;
            BackgroundWorkerRadDataPager.Source = BackgroundWorkerRadGridView.Items;
            Grid.SetColumn(BackgroundWorkerRadDataPager, 0);
            Grid.SetRow(BackgroundWorkerRadDataPager, 1);
            BackgroundWorkerGrid.Children.Add(BackgroundWorkerRadDataPager);

            BackgroundWorkerRadBusyIndicator = new RadBusyIndicator();
            BackgroundWorkerRadBusyIndicator.Content = BackgroundWorkerGrid;

            Content = BackgroundWorkerRadBusyIndicator;

            if (DesignerProperties.GetIsInDesignMode(this))
                return;

            BackgroundWorker = new BackgroundWorker();
            BackgroundWorker.DoWork += BackgroundWorkerDoWork;
            BackgroundWorker.RunWorkerCompleted += BackgroundWorkerCompleted;
        }

        private BackgroundWorker BackgroundWorker { get; set; }

        private Grid BackgroundWorkerGrid { get; set; }

        private RadBusyIndicator BackgroundWorkerRadBusyIndicator { get; set; }

        private RadDataPager BackgroundWorkerRadDataPager { get; set; }

        private RadGridView BackgroundWorkerRadGridView { get; set; }

        private DateTime LastHistoryUpdate { get; set; }

        private void BackgroundWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Dispatcher.BeginInvoke(new Action<IEnumerable<T>>(RefreshBackgroundWorkerDataGrid), e.Result);
        }

        private void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
        {
            e.Result = KitchenSinkDLL.KitchenSinkDLL.ReadTable<T>();
        }

        private void RefreshBackgroundWorkerDataGrid(IEnumerable<T> engines)
        {
            BackgroundWorkerRadGridView.ItemsSource = null;

            if (engines != null)
            {
                LastHistoryUpdate = HistoryModel.ReadLastHistoryUpdate();
                BackgroundWorkerRadGridView.ItemsSource = engines;
            }

            BackgroundWorkerRadBusyIndicator.IsBusy = false;
        }

        public void RefreshData()
        {
            if (!BackgroundWorker.IsBusy)
            {
                DateTime currentLastHistoryUpdate = HistoryModel.ReadLastHistoryUpdate();

                if (currentLastHistoryUpdate > LastHistoryUpdate)
                {
                    BackgroundWorkerRadBusyIndicator.IsBusy = true;
                    BackgroundWorker.RunWorkerAsync();
                }
            }
        }
    }
}

TaskUserControl:

using KitchenSinkDLL.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using Telerik.Windows.Controls;
using Xceed.Wpf.Toolkit;

namespace CSharpWPFAppinator
{
    public class TaskUserControl<T> : UserControl
    {
        public TaskUserControl()
        {
            TaskGrid = new Grid();
            TaskGrid.ColumnDefinitions.Add(new ColumnDefinition());
            TaskGrid.RowDefinitions.Add(new RowDefinition());
            TaskGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });

            TaskRadGridView = new RadGridView();
            Grid.SetColumn(TaskRadGridView, 0);
            Grid.SetRow(TaskRadGridView, 0);
            TaskGrid.Children.Add(TaskRadGridView);

            TaskRadDataPager = new RadDataPager();
            TaskRadDataPager.AutoEllipsisMode = AutoEllipsisModes.Both;
            TaskRadDataPager.DisplayMode = PagerDisplayModes.All;
            TaskRadDataPager.NumericButtonCount = 10;
            TaskRadDataPager.PageSize = 40;
            TaskRadDataPager.VerticalAlignment = VerticalAlignment.Bottom;
            TaskRadDataPager.Source = TaskRadGridView.Items;
            Grid.SetColumn(TaskRadDataPager, 0);
            Grid.SetRow(TaskRadDataPager, 1);
            TaskGrid.Children.Add(TaskRadDataPager);

            TaskRadBusyIndicator = new RadBusyIndicator();
            TaskRadBusyIndicator.Content = TaskGrid;

            Content = TaskRadBusyIndicator;

            if (DesignerProperties.GetIsInDesignMode(this))
                return;
        }

        private Grid TaskGrid { get; set; }

        private RadBusyIndicator TaskRadBusyIndicator { get; set; }

        private RadDataPager TaskRadDataPager { get; set; }

        private RadGridView TaskRadGridView { get; set; }

        private DateTime LastHistoryUpdate { get; set; }

        private IEnumerable<T> Records { get; set; }

        private void FetchDataForControl()
        {
            Records = KitchenSinkDLL.KitchenSinkDLL.ReadTable<T>();
        }

        private void RefreshTaskDataGrid()
        {
            TaskRadGridView.ItemsSource = null;

            if (Records != null)
            {
                LastHistoryUpdate = HistoryModel.ReadLastHistoryUpdate();
                TaskRadGridView.ItemsSource = Records;
            }
        }

        public async Task RefreshData()
        {
            TaskRadBusyIndicator.IsBusy = true;

            await Task.Run(() =>
            {
                DateTime currentLastHistoryUpdate = HistoryModel.ReadLastHistoryUpdate();

                if (currentLastHistoryUpdate > LastHistoryUpdate)
                {
                    FetchDataForControl();
                }
            });

            RefreshTaskDataGrid();
            TaskRadBusyIndicator.IsBusy = false;
        }
    }
}

BWEngineUserControl XAML:

<UserControl    d:DesignHeight="300"
                d:DesignWidth="300"
                mc:Ignorable="d"
                x:Class="CSharpWPFAppinator.BWEngineUserControl"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                xmlns:local="clr-namespace:CSharpWPFAppinator"
                xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit">
    <Grid x:Name="BWEngineGrid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
        </Grid.RowDefinitions>
    </Grid>
</UserControl>

BWEngineUserControl CS Code Behind:

using KitchenSinkDLL.Models;
using System.ComponentModel;
using System.Windows.Controls;

namespace CSharpWPFAppinator
{
    /// <summary>
    /// Interaction logic for BWEngineUserControl.xaml
    /// </summary>
    public partial class BWEngineUserControl : UserControl
    {
        public BWEngineUserControl()
        {
            InitializeComponent();

            if (DesignerProperties.GetIsInDesignMode(this))
                return;

            EngineUserControl = new BackgroundWorkerUserControl<EngineModel>();
            Grid.SetColumn(EngineUserControl, 0);
            Grid.SetRow(EngineUserControl, 0);
            BWEngineGrid.Children.Add(EngineUserControl);
        }

        private BackgroundWorkerUserControl<EngineModel> EngineUserControl { get; set; }

        public void RefreshData()
        {
            EngineUserControl.RefreshData();
        }
    }
}

TaskEngineUserControl XAML:

<UserControl    d:DesignHeight="300"
                d:DesignWidth="300"
                mc:Ignorable="d"
                x:Class="CSharpWPFAppinator.TaskEngineUserControl"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                xmlns:local="clr-namespace:CSharpWPFAppinator"
                xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit">
    <Grid x:Name="TaskEngineGrid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
        </Grid.RowDefinitions>
    </Grid>
</UserControl>

TaskEngineUserControl CS Code Behind:

using KitchenSinkDLL.Models;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace CSharpWPFAppinator
{
    /// <summary>
    /// Interaction logic for TaskEngineUserControl.xaml
    /// </summary>
    public partial class TaskEngineUserControl : UserControl
    {
        public TaskEngineUserControl()
        {
            InitializeComponent();

            if (DesignerProperties.GetIsInDesignMode(this))
                return;

            EngineUserControl = new TaskUserControl<EngineModel>();
            Grid.SetColumn(EngineUserControl, 0);
            Grid.SetRow(EngineUserControl, 0);
            TaskEngineGrid.Children.Add(EngineUserControl);
        }

        private TaskUserControl<EngineModel> EngineUserControl { get; set; }

        public async Task RefreshData()
        {
            await EngineUserControl.RefreshData();
        }
    }
}

BWHistoryUserControl XAML:

<UserControl    d:DesignHeight="300"
                d:DesignWidth="300"
                mc:Ignorable="d"
                x:Class="CSharpWPFAppinator.BWHistoryUserControl"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                xmlns:local="clr-namespace:CSharpWPFAppinator"
                xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit">
    <Grid x:Name="BWHistoryGrid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
        </Grid.RowDefinitions>
    </Grid>
</UserControl>

BWHistoryUserControl CS Code Behind:

using KitchenSinkDLL.Models;
using System.ComponentModel;
using System.Windows.Controls;

namespace CSharpWPFAppinator
{
    /// <summary>
    /// Interaction logic for BWHistoryUserControl.xaml
    /// </summary>
    public partial class BWHistoryUserControl : UserControl
    {
        public BWHistoryUserControl()
        {
            InitializeComponent();

            if (DesignerProperties.GetIsInDesignMode(this))
                return;

            HistoryUserControl = new BackgroundWorkerUserControl<HistoryModel>();
            Grid.SetColumn(HistoryUserControl, 0);
            Grid.SetRow(HistoryUserControl, 0);
            BWHistoryGrid.Children.Add(HistoryUserControl);
        }

        private BackgroundWorkerUserControl<HistoryModel> HistoryUserControl { get; set; }

        public void RefreshData()
        {
            HistoryUserControl.RefreshData();
        }
    }
}

TaskHistoryUserControl XAML:

<UserControl    d:DesignHeight="300"
                d:DesignWidth="300"
                mc:Ignorable="d"
                x:Class="CSharpWPFAppinator.TaskHistoryUserControl"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                xmlns:local="clr-namespace:CSharpWPFAppinator"
                xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit">
    <Grid x:Name="TaskHistoryGrid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
        </Grid.RowDefinitions>
    </Grid>
</UserControl>

TaskHistoryUserControl CS Code Behind:

using KitchenSinkDLL.Models;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace CSharpWPFAppinator
{
    /// <summary>
    /// Interaction logic for TaskHistoryUserControl.xaml
    /// </summary>
    public partial class TaskHistoryUserControl : UserControl
    {
        public TaskHistoryUserControl()
        {
            InitializeComponent();

            if (DesignerProperties.GetIsInDesignMode(this))
                return;

            HistoryUserControl = new TaskUserControl<HistoryModel>();
            Grid.SetColumn(HistoryUserControl, 0);
            Grid.SetRow(HistoryUserControl, 0);
            TaskHistoryGrid.Children.Add(HistoryUserControl);
        }

        private TaskUserControl<HistoryModel> HistoryUserControl { get; set; }

        public async Task RefreshData()
        {
            await HistoryUserControl.RefreshData();
        }
    }
}

BWLifeformUserControl XAML:

<UserControl    d:DesignHeight="300"
                d:DesignWidth="300"
                mc:Ignorable="d"
                x:Class="CSharpWPFAppinator.BWLifeformUserControl"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                xmlns:local="clr-namespace:CSharpWPFAppinator"
                xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit">
    <Grid x:Name="BWLifeformGrid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
        </Grid.RowDefinitions>
    </Grid>
</UserControl>

BWLifeformUserControl CS Code Behind:

using KitchenSinkDLL.Models;
using System.ComponentModel;
using System.Windows.Controls;

namespace CSharpWPFAppinator
{
    /// <summary>
    /// Interaction logic for BWLifeformUserControl.xaml
    /// </summary>
    public partial class BWLifeformUserControl : UserControl
    {
        public BWLifeformUserControl()
        {
            InitializeComponent();

            if (DesignerProperties.GetIsInDesignMode(this))
                return;

            LifeformUserControl = new BackgroundWorkerUserControl<LifeformModel>();
            Grid.SetColumn(LifeformUserControl, 0);
            Grid.SetRow(LifeformUserControl, 0);
            BWLifeformGrid.Children.Add(LifeformUserControl);
        }

        private BackgroundWorkerUserControl<LifeformModel> LifeformUserControl { get; set; }

        public void RefreshData()
        {
            LifeformUserControl.RefreshData();
        }
    }
}

TaskLifeformUserControl XAML:

<UserControl    d:DesignHeight="300"
                d:DesignWidth="300"
                mc:Ignorable="d"
                x:Class="CSharpWPFAppinator.TaskLifeformUserControl"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                xmlns:local="clr-namespace:CSharpWPFAppinator"
                xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit">
    <Grid x:Name="TaskLifeformGrid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
        </Grid.RowDefinitions>
    </Grid>
</UserControl>

TaskLifeformUserControl CS Code Behind:

using KitchenSinkDLL.Models;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace CSharpWPFAppinator
{
    /// <summary>
    /// Interaction logic for TaskLifeformUserControl.xaml
    /// </summary>
    public partial class TaskLifeformUserControl : UserControl
    {
        public TaskLifeformUserControl()
        {
            InitializeComponent();

            if (DesignerProperties.GetIsInDesignMode(this))
                return;

            LifeformUserControl = new TaskUserControl<LifeformModel>();
            Grid.SetColumn(LifeformUserControl, 0);
            Grid.SetRow(LifeformUserControl, 0);
            TaskLifeformGrid.Children.Add(LifeformUserControl);
        }

        private TaskUserControl<LifeformModel> LifeformUserControl { get; set; }

        public async Task RefreshData()
        {
            await LifeformUserControl.RefreshData();
        }
    }
}

BWPlanetUserControl XAML:

<UserControl    d:DesignHeight="300"
                d:DesignWidth="300"
                mc:Ignorable="d"
                x:Class="CSharpWPFAppinator.BWPlanetUserControl"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                xmlns:local="clr-namespace:CSharpWPFAppinator"
                xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit">
    <Grid x:Name="BWPlanetGrid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
        </Grid.RowDefinitions>
    </Grid>
</UserControl>

BWPlanetUserControl CS Code Behind:

using KitchenSinkDLL.Models;
using System.ComponentModel;
using System.Windows.Controls;

namespace CSharpWPFAppinator
{
    /// <summary>
    /// Interaction logic for BWPlanetUserControl.xaml
    /// </summary>
    public partial class BWPlanetUserControl : UserControl
    {
        public BWPlanetUserControl()
        {
            InitializeComponent();

            if (DesignerProperties.GetIsInDesignMode(this))
                return;

            PlanetUserControl = new BackgroundWorkerUserControl<PlanetModel>();
            Grid.SetColumn(PlanetUserControl, 0);
            Grid.SetRow(PlanetUserControl, 0);
            BWPlanetGrid.Children.Add(PlanetUserControl);
        }

        private BackgroundWorkerUserControl<PlanetModel> PlanetUserControl { get; set; }

        public void RefreshData()
        {
            PlanetUserControl.RefreshData();
        }
    }
}

TaskPlanetUserControl XAML:

<UserControl    d:DesignHeight="300"
                d:DesignWidth="300"
                mc:Ignorable="d"
                x:Class="CSharpWPFAppinator.TaskPlanetUserControl"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                xmlns:local="clr-namespace:CSharpWPFAppinator"
                xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit">
    <Grid x:Name="TaskPlanetGrid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
        </Grid.RowDefinitions>
    </Grid>
</UserControl>

TaskPlanetUserControl CS Code Behind:

using KitchenSinkDLL.Models;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace CSharpWPFAppinator
{
    /// <summary>
    /// Interaction logic for TaskPlanetUserControl.xaml
    /// </summary>
    public partial class TaskPlanetUserControl : UserControl
    {
        public TaskPlanetUserControl()
        {
            InitializeComponent();

            if (DesignerProperties.GetIsInDesignMode(this))
                return;

            PlanetUserControl = new TaskUserControl<PlanetModel>();
            Grid.SetColumn(PlanetUserControl, 0);
            Grid.SetRow(PlanetUserControl, 0);
            TaskPlanetGrid.Children.Add(PlanetUserControl);
        }

        private TaskUserControl<PlanetModel> PlanetUserControl { get; set; }

        public async Task RefreshData()
        {
            await PlanetUserControl.RefreshData();
        }
    }
}

BWSpeciesUserControl XAML:

<UserControl    d:DesignHeight="300"
                d:DesignWidth="300"
                mc:Ignorable="d"
                x:Class="CSharpWPFAppinator.BWSpeciesUserControl"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                xmlns:local="clr-namespace:CSharpWPFAppinator"
                xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit">
    <Grid x:Name="BWSpeciesGrid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
        </Grid.RowDefinitions>
    </Grid>
</UserControl>

BWSpeciesUserControl CS Code Behind:

using KitchenSinkDLL.Models;
using System.ComponentModel;
using System.Windows.Controls;

namespace CSharpWPFAppinator
{
    /// <summary>
    /// Interaction logic for BWSpeciesUserControl.xaml
    /// </summary>
    public partial class BWSpeciesUserControl : UserControl
    {
        public BWSpeciesUserControl()
        {
            InitializeComponent();

            if (DesignerProperties.GetIsInDesignMode(this))
                return;

            SpeciesUserControl = new BackgroundWorkerUserControl<SpeciesModel>();
            Grid.SetColumn(SpeciesUserControl, 0);
            Grid.SetRow(SpeciesUserControl, 0);
            BWSpeciesGrid.Children.Add(SpeciesUserControl);
        }

        private BackgroundWorkerUserControl<SpeciesModel> SpeciesUserControl { get; set; }

        public void RefreshData()
        {
            SpeciesUserControl.RefreshData();
        }
    }
}

TaskSpeciesUserControl XAML:

<UserControl    d:DesignHeight="300"
                d:DesignWidth="300"
                mc:Ignorable="d"
                x:Class="CSharpWPFAppinator.TaskSpeciesUserControl"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                xmlns:local="clr-namespace:CSharpWPFAppinator"
                xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit">
    <Grid x:Name="TaskSpeciesGrid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
        </Grid.RowDefinitions>
    </Grid>
</UserControl>

TaskSpeicesUserControl CS Code Behind:

using KitchenSinkDLL.Models;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace CSharpWPFAppinator
{
    /// <summary>
    /// Interaction logic for TaskSpeciesUserControl.xaml
    /// </summary>
    public partial class TaskSpeciesUserControl : UserControl
    {
        public TaskSpeciesUserControl()
        {
            InitializeComponent();

            if (DesignerProperties.GetIsInDesignMode(this))
                return;

            SpeciesUserControl = new TaskUserControl<SpeciesModel>();
            Grid.SetColumn(SpeciesUserControl, 0);
            Grid.SetRow(SpeciesUserControl, 0);
            TaskSpeciesGrid.Children.Add(SpeciesUserControl);
        }

        private TaskUserControl<SpeciesModel> SpeciesUserControl { get; set; }

        public async Task RefreshData()
        {
            await SpeciesUserControl.RefreshData();
        }
    }
}

BWVehicleUserControl XAML:

<UserControl    d:DesignHeight="300"
                d:DesignWidth="300"
                mc:Ignorable="d"
                x:Class="CSharpWPFAppinator.BWVehicleUserControl"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                xmlns:local="clr-namespace:CSharpWPFAppinator"
                xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit">
    <Grid x:Name="BWVehicleGrid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
        </Grid.RowDefinitions>
    </Grid>
</UserControl>

BWVehicleUserControl CS Code Behind:

using KitchenSinkDLL.Models;
using System.ComponentModel;
using System.Windows.Controls;

namespace CSharpWPFAppinator
{
    /// <summary>
    /// Interaction logic for BWVehicleUserControl.xaml
    /// </summary>
    public partial class BWVehicleUserControl : UserControl
    {
        public BWVehicleUserControl()
        {
            InitializeComponent();

            if (DesignerProperties.GetIsInDesignMode(this))
                return;

            VehicleUserControl = new BackgroundWorkerUserControl<VehicleModel>();
            Grid.SetColumn(VehicleUserControl, 0);
            Grid.SetRow(VehicleUserControl, 0);
            BWVehicleGrid.Children.Add(VehicleUserControl);
        }

        private BackgroundWorkerUserControl<VehicleModel> VehicleUserControl { get; set; }

        public void RefreshData()
        {
            VehicleUserControl.RefreshData();
        }
    }
}

TaskVehicleUserControl XAML:

<UserControl    d:DesignHeight="300"
                d:DesignWidth="300"
                mc:Ignorable="d"
                x:Class="CSharpWPFAppinator.TaskVehicleUserControl"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                xmlns:local="clr-namespace:CSharpWPFAppinator"
                xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit">
    <Grid x:Name="TaskVehicleGrid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
        </Grid.RowDefinitions>
    </Grid>
</UserControl>

TaskVehicleUserControl CS Code Behind:

using KitchenSinkDLL.Models;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace CSharpWPFAppinator
{
    /// <summary>
    /// Interaction logic for TaskVehicleUserControl.xaml
    /// </summary>
    public partial class TaskVehicleUserControl : UserControl
    {
        public TaskVehicleUserControl()
        {
            InitializeComponent();

            if (DesignerProperties.GetIsInDesignMode(this))
                return;

            VehicleUserControl = new TaskUserControl<VehicleModel>();
            Grid.SetColumn(VehicleUserControl, 0);
            Grid.SetRow(VehicleUserControl, 0);
            TaskVehicleGrid.Children.Add(VehicleUserControl);
        }

        private TaskUserControl<VehicleModel> VehicleUserControl { get; set; }

        public async Task RefreshData()
        {
            await VehicleUserControl.RefreshData();
        }
    }
}
WPF using BackgroundWorker vs using Task

One thought on “WPF using BackgroundWorker vs using Task

Leave a comment