Skip to content

Commit

Permalink
refactored async load objects..
Browse files Browse the repository at this point in the history
  • Loading branch information
Dirkster99 committed Jul 14, 2019
1 parent c9f161f commit 94325a4
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 50 deletions.
53 changes: 6 additions & 47 deletions source/MLibTest/MLibTest/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@ public partial class App : Application
#region fields
private ViewModels.AppViewModel _appVM = null;
private MainWindow _mainWindow = null;

internal LayoutLoaderResult LayoutLoaded { get; private set; }

private SemaphoreSlim _LayoutSemaphore;

internal EventHandler<LayoutLoadedEventArgs> LayoutLoadedEvent;
#endregion fields

#region constructors
Expand All @@ -38,36 +32,16 @@ static App()

public App()
{
_LayoutSemaphore = new SemaphoreSlim(1, 1);
LayoutLoaded = new LayoutLoader(@".\AvalonDock.Layout.config");
}
#endregion constructors

internal LayoutLoader LayoutLoaded { get; }

#region methods
private void Application_Startup(object sender, StartupEventArgs e)
{
try
{
Task.Factory.StartNew<LayoutLoaderResult>(() => LoadAvalonDockLayoutToString()).ContinueWith
(async r =>
{
await this._LayoutSemaphore.WaitAsync();
try
{
this.LayoutLoaded = r.Result;

// Send an event if MainWindow is already successfull constructed and waiting for Xml Layout
LayoutLoadedEvent?.Invoke(this, new LayoutLoadedEventArgs(r.Result));
}
finally
{
this._LayoutSemaphore.Release();
}
});
}
catch (Exception exc)
{
this.LayoutLoaded = new LayoutLoaderResult(null, false, exc);
}
LayoutLoaded.LoadLayout();

try
{
Expand Down Expand Up @@ -177,6 +151,7 @@ private void MainWindow_Loaded(object sender, RoutedEventArgs e)
Debug.WriteLine(exp);
}

// Load and layout AvalonDock elements when MainWindow has loaded
_mainWindow.OnLoadLayoutAsync();

/***
Expand Down Expand Up @@ -322,23 +297,7 @@ private LayoutLoaderResult LoadAvalonDockLayoutToString()

internal async Task<LayoutLoaderResult> GetLayoutString(EventHandler<LayoutLoadedEventArgs> loadEventHandler)
{
await this._LayoutSemaphore.WaitAsync();
try
{
if (this.LayoutLoaded != null)
return this.LayoutLoaded;
else
{
// Attach event to return result later
LayoutLoadedEvent += loadEventHandler;

return null;
}
}
finally
{
this._LayoutSemaphore.Release();
}
return await LayoutLoaded.GetLayoutString(loadEventHandler);
}

/// <summary>
Expand Down
1 change: 1 addition & 0 deletions source/MLibTest/MLibTest/MLibTest.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
</Compile>
<Compile Include="Models\AppCore.cs" />
<Compile Include="Models\LayoutLoadedEventArgs.cs" />
<Compile Include="Models\LayoutLoader.cs" />
<Compile Include="Models\LayoutLoaderResult.cs" />
<Compile Include="Models\SettingDefaults.cs" />
<Compile Include="ServiceInjector.cs" />
Expand Down
9 changes: 7 additions & 2 deletions source/MLibTest/MLibTest/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ public ICommand LoadLayoutCommand
{
if (_loadLayoutCommand == null)
{
_loadLayoutCommand = new RelayCommand<object>((p) => OnLoadLayoutAsync(p), (p) => CanLoadLayout(p));
_loadLayoutCommand = new RelayCommand<object>(
(p) => OnLoadLayoutAsync(p),
(p) => CanLoadLayout(p));
}

return _loadLayoutCommand;
Expand All @@ -44,7 +46,9 @@ public ICommand LoadLayoutCommand

private bool CanLoadLayout(object parameter)
{
return System.IO.File.Exists(@".\AvalonDock.Layout.config");
App myApp = (App)Application.Current;

return myApp.LayoutLoaded.CanLoadLayout();
}

internal void OnLayoutLoaded_Event(object sender, LayoutLoadedEventArgs layoutLoadedEvent)
Expand Down Expand Up @@ -116,6 +120,7 @@ internal void OnLayoutLoaded_Event(object sender, LayoutLoadedEventArgs layoutLo
}
finally
{
// Make sure AvalonDock control is visible at the end of restoring layout
dockManager.Visibility = Visibility.Visible;
}
},
Expand Down
2 changes: 1 addition & 1 deletion source/MLibTest/MLibTest/Models/LayoutLoadedEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ namespace MLibTest.Models
using System;

/// <summary>
/// Implements a simple event that is invoked when a layout is loaded.
/// Implements an event that is invoked when a layout is loaded.
/// </summary>
internal class LayoutLoadedEventArgs : EventArgs
{
Expand Down
155 changes: 155 additions & 0 deletions source/MLibTest/MLibTest/Models/LayoutLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
namespace MLibTest.Models
{
using System;
using System.Threading;
using System.Threading.Tasks;

/// <summary>
/// Implements base methods and events for loading an AvalonDock layout
/// in a background thread.
/// </summary>
internal class LayoutLoader
{
#region fields
private SemaphoreSlim _LayoutSemaphore;
private readonly string _layoutFileName;
private LayoutLoaderResult _LayoutLoaded;
#endregion fields

#region ctors
/// <summary>
/// Class constructor
/// </summary>
public LayoutLoader(string layoutFileName)
: this()
{
_layoutFileName = layoutFileName;
}

/// <summary>
/// Hidden class constructor
/// </summary>
protected LayoutLoader()
{
_LayoutSemaphore = new SemaphoreSlim(1, 1);
}
#endregion ctors

#region events
/// <summary>
/// Implements an event that is raised when the AvalonDock layout
/// was successfully loaded.
/// </summary>
public EventHandler<LayoutLoadedEventArgs> LayoutLoadedEvent;
#endregion events

#region methods
/// <summary>
/// Loads the AvalonDockLayout with a background task and makes the result
/// available in a private <see cref="_LayoutLoaded"/> field.
///
/// The result can later be queried with the <see cref="GetLayoutString"/> method
/// which will eiter return the available result of connect to an eventhandler
/// The will return the result via <see cref="LayoutLoadedEvent"/> as soon as it
/// is available.
/// </summary>
public void LoadLayout()
{
try
{
Task.Factory.StartNew<LayoutLoaderResult>(() => LoadAvalonDockLayoutToString()
).ContinueWith(async r =>
{
await this._LayoutSemaphore.WaitAsync();
try
{
this._LayoutLoaded = r.Result;

// Send an event if event subscriber is available
// if MainWindow is already successfull constructed and waiting for Xml Layout
LayoutLoadedEvent?.Invoke(this, new LayoutLoadedEventArgs(r.Result));
}
finally
{
this._LayoutSemaphore.Release();
}
});
}
catch (Exception exc)
{
this._LayoutLoaded = new LayoutLoaderResult(null, false, exc);
}
}

/// <summary>
/// Loads the layout object queried via <see cref="LoadLayout"/> method or
/// connects the caller to the eventhandler to return the result object at
/// a later stage (if it was not available at this time).
/// </summary>
/// <param name="loadEventHandler"></param>
/// <returns></returns>
internal async Task<LayoutLoaderResult> GetLayoutString(EventHandler<LayoutLoadedEventArgs> loadEventHandler)
{
await this._LayoutSemaphore.WaitAsync();
try
{
if (this._LayoutLoaded != null)
return this._LayoutLoaded;
else
{
// Attach event to return result later
LayoutLoadedEvent += loadEventHandler;

return null;
}
}
finally
{
this._LayoutSemaphore.Release();
}
}

/// <summary>
/// Reads the AvalonDock layout into a string and returns it with additional
/// information wrapped into a <see cref="LayoutLoaderResult"/>.
/// </summary>
/// <returns></returns>
private LayoutLoaderResult LoadAvalonDockLayoutToString()
{
string path = GetFullPathToLayout();

if (System.IO.File.Exists(path) == false)
return null;

try
{
//Thread.Sleep(2000);
return new LayoutLoaderResult(System.IO.File.ReadAllText(path), true, null);
}
catch (Exception exc)
{
return new LayoutLoaderResult(null, false, exc);
}
}

/// <summary>
/// Gets whether a standard layout file is available for loading.
/// </summary>
/// <returns></returns>
internal bool CanLoadLayout()
{
return System.IO.File.Exists(GetFullPathToLayout());
}

/// <summary>
/// Gets the full path to the layout file that stores the AvalonDock layout
/// and is used to store/restore the layout of the controls.
/// </summary>
/// <returns></returns>
internal string GetFullPathToLayout()
{
return System.IO.Path.GetFullPath(_layoutFileName);
}
#endregion methods
}
}
14 changes: 14 additions & 0 deletions source/MLibTest/MLibTest/Models/LayoutLoaderResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ namespace MLibTest.Models
{
using System;

/// <summary>
/// Implements a class that contains the items that describe the results
/// of loading the AvalonDock layout from persistence.
/// </summary>
internal class LayoutLoaderResult
{
#region ctors
Expand All @@ -25,10 +29,20 @@ protected LayoutLoaderResult()
#endregion ctors

#region properties
/// <summary>
/// Gets the Xml definition of the AvalonDock layout with a string object.
/// </summary>
public string XmlContent { get; }

/// <summary>
/// Determines whether loading the layout was successful or not.
/// </summary>
public bool LoadwasSuccesful { get; }

/// <summary>
/// Gets an <see cref="Exception"/> that might be available if layout loading
/// was not succesful and additional error information is available.
/// </summary>
public Exception LoadError { get; }
#endregion properties
}
Expand Down

0 comments on commit 94325a4

Please sign in to comment.