SEBWIN-219: Implemented draft of session mechanism.

This commit is contained in:
dbuechel 2018-02-08 13:32:48 +01:00
parent 001c262158
commit 66e9078a4c
21 changed files with 334 additions and 59 deletions

View file

@ -18,6 +18,7 @@ namespace SafeExamBrowser.Configuration
{ {
private RuntimeInfo runtimeInfo; private RuntimeInfo runtimeInfo;
public ISessionData CurrentSessionData { get; private set; }
public ISettings CurrentSettings { get; private set; } public ISettings CurrentSettings { get; private set; }
public IRuntimeInfo RuntimeInfo public IRuntimeInfo RuntimeInfo
@ -33,6 +34,17 @@ namespace SafeExamBrowser.Configuration
} }
} }
public ISessionData InitializeSessionData()
{
var sessionData = new SessionData();
sessionData.Id = Guid.NewGuid();
CurrentSessionData = sessionData;
return sessionData;
}
public ISettings LoadSettings(Uri path) public ISettings LoadSettings(Uri path)
{ {
// TODO // TODO

View file

@ -54,6 +54,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="RuntimeInfo.cs" /> <Compile Include="RuntimeInfo.cs" />
<Compile Include="SessionData.cs" />
<Compile Include="Settings\BrowserSettings.cs" /> <Compile Include="Settings\BrowserSettings.cs" />
<Compile Include="Settings\KeyboardSettings.cs" /> <Compile Include="Settings\KeyboardSettings.cs" />
<Compile Include="Settings\MouseSettings.cs" /> <Compile Include="Settings\MouseSettings.cs" />

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
using SafeExamBrowser.Contracts.Configuration;
namespace SafeExamBrowser.Configuration
{
[Serializable]
public class SessionData : ISessionData
{
public Guid Id { get; set; }
}
}

View file

@ -12,6 +12,14 @@ namespace SafeExamBrowser.Contracts.Communication
{ {
public interface IClientProxy public interface IClientProxy
{ {
/// <summary>
/// Tries to connect to the client host.
/// </summary>
bool Connect(Guid token); bool Connect(Guid token);
/// <summary>
/// Disconnects from the client host.
/// </summary>
void Disconnect();
} }
} }

View file

@ -6,6 +6,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
using System;
using SafeExamBrowser.Contracts.Configuration.Settings;
namespace SafeExamBrowser.Contracts.Communication namespace SafeExamBrowser.Contracts.Communication
{ {
public interface IServiceProxy public interface IServiceProxy
@ -25,5 +28,15 @@ namespace SafeExamBrowser.Contracts.Communication
/// Disconnects from the service host. /// Disconnects from the service host.
/// </summary> /// </summary>
void Disconnect(); void Disconnect();
/// <summary>
/// Instructs the service to start a new session according to the given parameters.
/// </summary>
void StartSession(Guid sessionId, ISettings settings);
/// <summary>
/// Instructs the service to stop the specified session.
/// </summary>
void StopSession(Guid sessionId);
} }
} }

View file

@ -13,6 +13,12 @@ namespace SafeExamBrowser.Contracts.Configuration
{ {
public interface IConfigurationRepository public interface IConfigurationRepository
{ {
/// <summary>
/// Retrieves the current session data, i.e. the last ones which were initialized. If no session has been initialized yet, this
/// property will be <c>null</c>!
/// </summary>
ISessionData CurrentSessionData { get; }
/// <summary> /// <summary>
/// Retrieves the current settings, i.e. the last ones which were loaded. If no settings have been loaded yet, this property will /// Retrieves the current settings, i.e. the last ones which were loaded. If no settings have been loaded yet, this property will
/// be <c>null</c>! /// be <c>null</c>!
@ -24,6 +30,11 @@ namespace SafeExamBrowser.Contracts.Configuration
/// </summary> /// </summary>
IRuntimeInfo RuntimeInfo { get; } IRuntimeInfo RuntimeInfo { get; }
/// <summary>
/// Initializes all relevant data for a new session.
/// </summary>
ISessionData InitializeSessionData();
/// <summary> /// <summary>
/// Attempts to load settings from the specified path. /// Attempts to load settings from the specified path.
/// </summary> /// </summary>

View file

@ -0,0 +1,20 @@
/*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
namespace SafeExamBrowser.Contracts.Configuration
{
public interface ISessionData
{
/// <summary>
/// The unique session identifier.
/// </summary>
Guid Id { get; }
}
}

View file

@ -45,19 +45,19 @@ namespace SafeExamBrowser.Contracts.I18n
ProgressIndicator_StartEventHandling, ProgressIndicator_StartEventHandling,
ProgressIndicator_StartKeyboardInterception, ProgressIndicator_StartKeyboardInterception,
ProgressIndicator_StartMouseInterception, ProgressIndicator_StartMouseInterception,
ProgressIndicator_StartSession,
ProgressIndicator_StopCommunicationHost, ProgressIndicator_StopCommunicationHost,
ProgressIndicator_StopEventHandling, ProgressIndicator_StopEventHandling,
ProgressIndicator_StopKeyboardInterception, ProgressIndicator_StopKeyboardInterception,
ProgressIndicator_StopMouseInterception, ProgressIndicator_StopMouseInterception,
ProgressIndicator_StopProcessMonitoring, ProgressIndicator_StopProcessMonitoring,
ProgressIndicator_StopSession,
ProgressIndicator_StopWindowMonitoring, ProgressIndicator_StopWindowMonitoring,
ProgressIndicator_TerminateBrowser, ProgressIndicator_TerminateBrowser,
ProgressIndicator_TerminateTaskbar, ProgressIndicator_TerminateTaskbar,
ProgressIndicator_WaitExplorerStartup, ProgressIndicator_WaitExplorerStartup,
ProgressIndicator_WaitExplorerTermination, ProgressIndicator_WaitExplorerTermination,
RuntimeWindow_ApplicationRunning, RuntimeWindow_ApplicationRunning,
RuntimeWindow_StartSession,
RuntimeWindow_StopSession,
SystemControl_BatteryCharged, SystemControl_BatteryCharged,
SystemControl_BatteryCharging, SystemControl_BatteryCharging,
SystemControl_BatteryChargeCriticalWarning, SystemControl_BatteryChargeCriticalWarning,

View file

@ -66,6 +66,7 @@
<Compile Include="Communication\Responses\IResponse.cs" /> <Compile Include="Communication\Responses\IResponse.cs" />
<Compile Include="Communication\Responses\IConnectResponse.cs" /> <Compile Include="Communication\Responses\IConnectResponse.cs" />
<Compile Include="Configuration\IRuntimeInfo.cs" /> <Compile Include="Configuration\IRuntimeInfo.cs" />
<Compile Include="Configuration\ISessionData.cs" />
<Compile Include="Configuration\Settings\ConfigurationMode.cs" /> <Compile Include="Configuration\Settings\ConfigurationMode.cs" />
<Compile Include="Behaviour\INotificationController.cs" /> <Compile Include="Behaviour\INotificationController.cs" />
<Compile Include="Behaviour\Operations\IOperation.cs" /> <Compile Include="Behaviour\Operations\IOperation.cs" />

View file

@ -33,9 +33,38 @@ namespace SafeExamBrowser.Core.Communication
this.logger = logger; this.logger = logger;
} }
public abstract IConnectResponse Connect(Guid? token = null); protected abstract IConnectResponse OnConnect(Guid? token);
public abstract void Disconnect(IMessage message); protected abstract void OnDisconnect(IMessage message);
public abstract IResponse Send(IMessage message); protected abstract IResponse OnReceive(IMessage message);
public IConnectResponse Connect(Guid? token = null)
{
logger.Debug($"Received connection request with token '{token}'.");
var response = OnConnect(token);
logger.Debug($"{(response.ConnectionEstablished ? "Accepted" : "Denied")} connection request.");
return response;
}
public void Disconnect(IMessage message)
{
logger.Debug($"Received disconnection request with message '{message}'.");
OnDisconnect(message);
}
public IResponse Send(IMessage message)
{
logger.Debug($"Received message '{message}'.");
var response = OnReceive(message);
logger.Debug($"Sending response '{response}'.");
return response;
}
public void Start() public void Start()
{ {

View file

@ -6,7 +6,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
using System;
using SafeExamBrowser.Contracts.Communication; using SafeExamBrowser.Contracts.Communication;
using SafeExamBrowser.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Core.Communication.Messages; using SafeExamBrowser.Core.Communication.Messages;
@ -22,22 +24,48 @@ namespace SafeExamBrowser.Core.Communication
public bool Connect() public bool Connect()
{ {
if (!IgnoreOperation(nameof(Connect))) if (IgnoreOperation(nameof(Connect)))
{ {
return base.Connect().ConnectionEstablished; return false;
} }
return false; return base.Connect().ConnectionEstablished;
} }
public void Disconnect() public void Disconnect()
{ {
if (!IgnoreOperation(nameof(Disconnect))) if (IgnoreOperation(nameof(Disconnect)))
{ {
FailIfNotConnected(nameof(Disconnect)); return;
Disconnect(new Message { CommunicationToken = CommunicationToken.Value });
} }
FailIfNotConnected(nameof(Disconnect));
Disconnect(new Message { CommunicationToken = CommunicationToken.Value });
}
public void StartSession(Guid sessionId, ISettings settings)
{
if (IgnoreOperation(nameof(StartSession)))
{
return;
}
FailIfNotConnected(nameof(StartSession));
// TODO: Send(new StartSessionMessage { Id = sessionId, Settings = settings });
}
public void StopSession(Guid sessionId)
{
if (IgnoreOperation(nameof(StopSession)))
{
return;
}
FailIfNotConnected(nameof(StopSession));
// TODO
} }
private bool IgnoreOperation(string operationName) private bool IgnoreOperation(string operationName)

View file

@ -90,6 +90,9 @@
<Entry key="ProgressIndicator_StartMouseInterception"> <Entry key="ProgressIndicator_StartMouseInterception">
Starting mouse interception Starting mouse interception
</Entry> </Entry>
<Entry key="ProgressIndicator_StartSession">
Starting new session
</Entry>
<Entry key="ProgressIndicator_StopCommunicationHost"> <Entry key="ProgressIndicator_StopCommunicationHost">
Stopping communication host Stopping communication host
</Entry> </Entry>
@ -105,6 +108,9 @@
<Entry key="ProgressIndicator_StopProcessMonitoring"> <Entry key="ProgressIndicator_StopProcessMonitoring">
Stopping process monitoring Stopping process monitoring
</Entry> </Entry>
<Entry key="ProgressIndicator_StopSession">
Stopping current session
</Entry>
<Entry key="ProgressIndicator_StopWindowMonitoring"> <Entry key="ProgressIndicator_StopWindowMonitoring">
Stopping window monitoring Stopping window monitoring
</Entry> </Entry>
@ -123,12 +129,6 @@
<Entry key="RuntimeWindow_ApplicationRunning"> <Entry key="RuntimeWindow_ApplicationRunning">
The application is running. The application is running.
</Entry> </Entry>
<Entry key="RuntimeWindow_StartSession">
Starting new session
</Entry>
<Entry key="RuntimeWindow_StopSession">
Stopping current session
</Entry>
<Entry key="SystemControl_BatteryCharging"> <Entry key="SystemControl_BatteryCharging">
Plugged in, charging... (%%CHARGE%%%) Plugged in, charging... (%%CHARGE%%%)
</Entry> </Entry>

View file

@ -74,6 +74,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
public void Repeat() public void Repeat()
{ {
// TODO: How will the new settings be retrieved? Uri passed to the repository? If yes, how does the Uri get here?! // TODO: How will the new settings be retrieved? Uri passed to the repository? If yes, how does the Uri get here?!
// -> IDEA: Use configuration repository as container?
} }
public void Revert() public void Revert()

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using SafeExamBrowser.Contracts.Communication;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Logging;
namespace SafeExamBrowser.Runtime.Behaviour.Operations
{
internal class SessionSequenceEndOperation : SessionSequenceOperation
{
public SessionSequenceEndOperation(IConfigurationRepository configuration, ILogger logger, IServiceProxy serviceProxy) : base(configuration, logger, serviceProxy)
{
}
public override void Perform()
{
StartSession();
}
public override void Repeat()
{
StartSession();
}
public override void Revert()
{
StopSession();
}
}
}

View file

@ -0,0 +1,76 @@
/*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.Communication;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Runtime.Behaviour.Operations
{
internal abstract class SessionSequenceOperation : IOperation
{
private bool sessionInitialized;
private IConfigurationRepository configuration;
private ILogger logger;
private IServiceProxy serviceProxy;
private ISessionData sessionData;
public bool Abort { get; private set; }
public IProgressIndicator ProgressIndicator { private get; set; }
public SessionSequenceOperation(IConfigurationRepository configuration, ILogger logger, IServiceProxy serviceProxy)
{
this.configuration = configuration;
this.logger = logger;
this.serviceProxy = serviceProxy;
}
public abstract void Perform();
public abstract void Repeat();
public abstract void Revert();
protected void StartSession()
{
logger.Info("Starting new session...");
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StartSession, true);
sessionData = configuration.InitializeSessionData();
serviceProxy.StartSession(sessionData.Id, configuration.CurrentSettings);
// TODO:
// - Create and connect to client
// - Verify session integrity and start event handling -> in runtime controller?
System.Threading.Thread.Sleep(5000);
sessionInitialized = true;
logger.Info($"Successfully started new session with identifier '{sessionData.Id}'.");
}
protected void StopSession()
{
if (sessionInitialized)
{
logger.Info($"Stopping session with identifier '{sessionData.Id}'...");
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StopSession, true);
serviceProxy.StopSession(sessionData.Id);
// TODO:
// - Terminate client (or does it terminate itself?)
// - Stop event handling and verify session termination -> in runtime controller?
System.Threading.Thread.Sleep(5000);
sessionInitialized = false;
logger.Info($"Successfully stopped session with identifier '{sessionData.Id}'.");
}
}
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using SafeExamBrowser.Contracts.Communication;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Logging;
namespace SafeExamBrowser.Runtime.Behaviour.Operations
{
internal class SessionSequenceStartOperation : SessionSequenceOperation
{
public SessionSequenceStartOperation(IConfigurationRepository configuration, ILogger logger, IServiceProxy serviceProxy) : base(configuration, logger, serviceProxy)
{
}
public override void Perform()
{
// Nothing to do here...
}
public override void Repeat()
{
StopSession();
}
public override void Revert()
{
// Nothing to do here...
}
}
}

View file

@ -20,7 +20,7 @@ namespace SafeExamBrowser.Runtime.Behaviour
{ {
internal class RuntimeController : IRuntimeController internal class RuntimeController : IRuntimeController
{ {
private bool initialized; private bool sessionRunning;
private IConfigurationRepository configuration; private IConfigurationRepository configuration;
private ILogger logger; private ILogger logger;
@ -68,7 +68,7 @@ namespace SafeExamBrowser.Runtime.Behaviour
splashScreen.Show(); splashScreen.Show();
initialized = bootstrapSequence.TryPerform(); var initialized = bootstrapSequence.TryPerform();
if (initialized) if (initialized)
{ {
@ -86,20 +86,16 @@ namespace SafeExamBrowser.Runtime.Behaviour
logger.Log(string.Empty); logger.Log(string.Empty);
} }
return initialized; return initialized && sessionRunning;
} }
public void Terminate() public void Terminate()
{ {
// TODO: Necessary here? Move to App.cs as private "started" flag if not... if (sessionRunning)
if (!initialized)
{ {
return; StopSession();
} }
// TODO: Only if session is running!
StopSession();
logger.Unsubscribe(runtimeWindow); logger.Unsubscribe(runtimeWindow);
runtimeWindow?.Close(); runtimeWindow?.Close();
splashScreen?.Show(); splashScreen?.Show();
@ -129,23 +125,12 @@ namespace SafeExamBrowser.Runtime.Behaviour
private void StartSession(bool initial = false) private void StartSession(bool initial = false)
{ {
logger.Info("Starting new session...");
runtimeWindow.UpdateText(TextKey.RuntimeWindow_StartSession, true);
runtimeWindow.Show(); runtimeWindow.Show();
var success = initial ? sessionSequence.TryPerform() : sessionSequence.TryRepeat(); sessionRunning = initial ? sessionSequence.TryPerform() : sessionSequence.TryRepeat();
if (success) if (sessionRunning)
{ {
// TODO:
// - Initialize session data
// - Create and connect to client
// - Initialize session with service
// - Verify session integrity and start event handling
runtimeWindow.HideProgressBar(); runtimeWindow.HideProgressBar();
runtimeWindow.UpdateText(TextKey.RuntimeWindow_ApplicationRunning); runtimeWindow.UpdateText(TextKey.RuntimeWindow_ApplicationRunning);
@ -157,34 +142,27 @@ namespace SafeExamBrowser.Runtime.Behaviour
else else
{ {
uiFactory.Show(TextKey.MessageBox_SessionStartError, TextKey.MessageBox_SessionStartErrorTitle, icon: MessageBoxIcon.Error); uiFactory.Show(TextKey.MessageBox_SessionStartError, TextKey.MessageBox_SessionStartErrorTitle, icon: MessageBoxIcon.Error);
logger.Info($"Failed to start new session. Terminating application...");
if (initial) if (!initial)
{ {
initialized = false; shutdown.Invoke();
}
else
{
shutdown();
} }
} }
} }
private void StopSession() private void StopSession()
{ {
logger.Info("Stopping current session...");
runtimeWindow.Show(); runtimeWindow.Show();
runtimeWindow.BringToForeground(); runtimeWindow.BringToForeground();
runtimeWindow.ShowProgressBar(); runtimeWindow.ShowProgressBar();
runtimeWindow.UpdateText(TextKey.RuntimeWindow_StopSession, true);
// TODO:
// - Terminate client (or does it terminate itself?)
// - Finalize session with service
// - Stop event handling and close session
var success = sessionSequence.TryRevert(); var success = sessionSequence.TryRevert();
if (success) if (success)
{ {
sessionRunning = false;
// TODO // TODO
} }
else else

View file

@ -21,19 +21,19 @@ namespace SafeExamBrowser.Runtime.Communication
{ {
} }
public override IConnectResponse Connect(Guid? token = null) protected override IConnectResponse OnConnect(Guid? token = null)
{ {
// TODO // TODO
throw new NotImplementedException(); throw new NotImplementedException();
} }
public override void Disconnect(IMessage message) protected override void OnDisconnect(IMessage message)
{ {
// TODO // TODO
throw new NotImplementedException(); throw new NotImplementedException();
} }
public override IResponse Send(IMessage message) protected override IResponse OnReceive(IMessage message)
{ {
// TODO // TODO
throw new NotImplementedException(); throw new NotImplementedException();

View file

@ -37,10 +37,8 @@ namespace SafeExamBrowser.Runtime
internal void BuildObjectGraph() internal void BuildObjectGraph()
{ {
var args = Environment.GetCommandLineArgs(); var args = Environment.GetCommandLineArgs();
var bootstrapOperations = new Queue<IOperation>();
var sessionOperations = new Queue<IOperation>();
var nativeMethods = new NativeMethods();
var configuration = new ConfigurationRepository(); var configuration = new ConfigurationRepository();
var nativeMethods = new NativeMethods();
logger = new Logger(); logger = new Logger();
runtimeInfo = configuration.RuntimeInfo; runtimeInfo = configuration.RuntimeInfo;
@ -53,12 +51,17 @@ namespace SafeExamBrowser.Runtime
var runtimeHost = new RuntimeHost(runtimeInfo.RuntimeAddress, new ModuleLogger(logger, typeof(RuntimeHost))); var runtimeHost = new RuntimeHost(runtimeInfo.RuntimeAddress, new ModuleLogger(logger, typeof(RuntimeHost)));
var serviceProxy = new ServiceProxy(runtimeInfo.ServiceAddress, new ModuleLogger(logger, typeof(ServiceProxy))); var serviceProxy = new ServiceProxy(runtimeInfo.ServiceAddress, new ModuleLogger(logger, typeof(ServiceProxy)));
var bootstrapOperations = new Queue<IOperation>();
var sessionOperations = new Queue<IOperation>();
bootstrapOperations.Enqueue(new I18nOperation(logger, text)); bootstrapOperations.Enqueue(new I18nOperation(logger, text));
bootstrapOperations.Enqueue(new CommunicationOperation(runtimeHost, logger)); bootstrapOperations.Enqueue(new CommunicationOperation(runtimeHost, logger));
sessionOperations.Enqueue(new SessionSequenceStartOperation(configuration, logger, serviceProxy));
sessionOperations.Enqueue(new ConfigurationOperation(configuration, logger, runtimeInfo, text, uiFactory, args)); sessionOperations.Enqueue(new ConfigurationOperation(configuration, logger, runtimeInfo, text, uiFactory, args));
sessionOperations.Enqueue(new ServiceOperation(configuration, logger, serviceProxy, text)); sessionOperations.Enqueue(new ServiceOperation(configuration, logger, serviceProxy, text));
sessionOperations.Enqueue(new KioskModeOperation(logger, configuration)); sessionOperations.Enqueue(new KioskModeOperation(logger, configuration));
sessionOperations.Enqueue(new SessionSequenceEndOperation(configuration, logger, serviceProxy));
var boostrapSequence = new OperationSequence(logger, bootstrapOperations); var boostrapSequence = new OperationSequence(logger, bootstrapOperations);
var sessionSequence = new OperationSequence(logger, sessionOperations); var sessionSequence = new OperationSequence(logger, sessionOperations);

View file

@ -90,6 +90,9 @@
<Compile Include="Behaviour\Operations\ConfigurationOperation.cs" /> <Compile Include="Behaviour\Operations\ConfigurationOperation.cs" />
<Compile Include="Behaviour\Operations\KioskModeOperation.cs" /> <Compile Include="Behaviour\Operations\KioskModeOperation.cs" />
<Compile Include="Behaviour\Operations\ServiceOperation.cs" /> <Compile Include="Behaviour\Operations\ServiceOperation.cs" />
<Compile Include="Behaviour\Operations\SessionSequenceEndOperation.cs" />
<Compile Include="Behaviour\Operations\SessionSequenceOperation.cs" />
<Compile Include="Behaviour\Operations\SessionSequenceStartOperation.cs" />
<Compile Include="Communication\RuntimeHost.cs" /> <Compile Include="Communication\RuntimeHost.cs" />
<Compile Include="CompositionRoot.cs" /> <Compile Include="CompositionRoot.cs" />
<Compile Include="Properties\AssemblyInfo.cs"> <Compile Include="Properties\AssemblyInfo.cs">

View file

@ -52,7 +52,7 @@
<s:Double x:Key="{x:Static SystemParameters.HorizontalScrollBarHeightKey}">5</s:Double> <s:Double x:Key="{x:Static SystemParameters.HorizontalScrollBarHeightKey}">5</s:Double>
<s:Double x:Key="{x:Static SystemParameters.VerticalScrollBarWidthKey}">5</s:Double> <s:Double x:Key="{x:Static SystemParameters.VerticalScrollBarWidthKey}">5</s:Double>
</ScrollViewer.Resources> </ScrollViewer.Resources>
<TextBox x:Name="LogTextBlock" Background="Transparent" BorderThickness="0" FontFamily="Courier New" Foreground="Black" IsReadOnly="True" /> <TextBox x:Name="LogTextBlock" Background="Transparent" BorderThickness="0" FontFamily="Courier New" FontSize="10" Foreground="Black" IsReadOnly="True" />
</ScrollViewer> </ScrollViewer>
</Border> </Border>
</Grid> </Grid>