SEBWIN-220: Replaced guid with abstact InstanceIdentifier for application instances and started to implement logging for browser component.
This commit is contained in:
parent
d521e2d3c0
commit
ef31db9920
22 changed files with 159 additions and 48 deletions
|
@ -24,6 +24,8 @@ namespace SafeExamBrowser.Browser
|
|||
{
|
||||
public class BrowserApplicationController : IBrowserApplicationController
|
||||
{
|
||||
private int instanceIdCounter = default(int);
|
||||
|
||||
private AppConfig appConfig;
|
||||
private IApplicationButton button;
|
||||
private IList<IApplicationInstance> instances;
|
||||
|
@ -57,6 +59,8 @@ namespace SafeExamBrowser.Browser
|
|||
var cefSettings = InitializeCefSettings();
|
||||
var success = Cef.Initialize(cefSettings, true, null);
|
||||
|
||||
logger.Info("Initialized CEF.");
|
||||
|
||||
if (!success)
|
||||
{
|
||||
throw new Exception("Failed to initialize the browser engine!");
|
||||
|
@ -75,14 +79,20 @@ namespace SafeExamBrowser.Browser
|
|||
{
|
||||
instance.Terminated -= Instance_Terminated;
|
||||
instance.Window.Close();
|
||||
|
||||
logger.Info($"Terminated browser instance {instance.Id}.");
|
||||
}
|
||||
|
||||
Cef.Shutdown();
|
||||
|
||||
logger.Info("Terminated CEF.");
|
||||
}
|
||||
|
||||
private void CreateNewInstance()
|
||||
{
|
||||
var instance = new BrowserApplicationInstance(appConfig, settings, text, uiFactory, instances.Count == 0);
|
||||
var id = new BrowserInstanceIdentifier(++instanceIdCounter);
|
||||
var isMainInstance = instances.Count == 0;
|
||||
var instance = new BrowserApplicationInstance(appConfig, settings, id, isMainInstance, text, uiFactory);
|
||||
|
||||
instance.Initialize();
|
||||
instance.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args);
|
||||
|
@ -91,36 +101,44 @@ namespace SafeExamBrowser.Browser
|
|||
button.RegisterInstance(instance);
|
||||
instances.Add(instance);
|
||||
instance.Window.Show();
|
||||
|
||||
logger.Info($"Created browser instance {instance.Id}.");
|
||||
}
|
||||
|
||||
private CefSettings InitializeCefSettings()
|
||||
{
|
||||
var warning = appConfig.LogLevel == LogLevel.Warning;
|
||||
var error = appConfig.LogLevel == LogLevel.Error;
|
||||
var cefSettings = new CefSettings
|
||||
{
|
||||
CachePath = appConfig.BrowserCachePath,
|
||||
LogFile = appConfig.BrowserLogFile,
|
||||
// TODO: Set according to current application LogLevel, but avoid verbose!
|
||||
LogSeverity = LogSeverity.Info
|
||||
LogSeverity = error ? LogSeverity.Error : (warning ? LogSeverity.Warning : LogSeverity.Info)
|
||||
};
|
||||
|
||||
logger.Debug($"CEF cache path is '{cefSettings.CachePath}'.");
|
||||
logger.Debug($"CEF log file is '{cefSettings.LogFile}'.");
|
||||
logger.Debug($"CEF log severity is '{cefSettings.LogSeverity}'.");
|
||||
|
||||
return cefSettings;
|
||||
}
|
||||
|
||||
private void Button_OnClick(Guid? instanceId = null)
|
||||
private void Button_OnClick(InstanceIdentifier id = null)
|
||||
{
|
||||
if (instanceId.HasValue)
|
||||
{
|
||||
instances.FirstOrDefault(i => i.Id == instanceId)?.Window?.BringToForeground();
|
||||
}
|
||||
else
|
||||
if (id is null)
|
||||
{
|
||||
CreateNewInstance();
|
||||
}
|
||||
else
|
||||
{
|
||||
instances.FirstOrDefault(i => i.Id == id)?.Window?.BringToForeground();
|
||||
}
|
||||
}
|
||||
|
||||
private void Instance_Terminated(Guid id)
|
||||
private void Instance_Terminated(InstanceIdentifier id)
|
||||
{
|
||||
instances.Remove(instances.FirstOrDefault(i => i.Id == id));
|
||||
logger.Info($"Browser instance {id} was terminated.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Browser.Handlers;
|
||||
using SafeExamBrowser.Contracts.Behaviour;
|
||||
using SafeExamBrowser.Contracts.Behaviour.Events;
|
||||
|
@ -30,7 +29,7 @@ namespace SafeExamBrowser.Browser
|
|||
private IText text;
|
||||
private IUserInterfaceFactory uiFactory;
|
||||
|
||||
public Guid Id { get; private set; }
|
||||
public InstanceIdentifier Id { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public IWindow Window { get { return window; } }
|
||||
|
||||
|
@ -41,11 +40,13 @@ namespace SafeExamBrowser.Browser
|
|||
public BrowserApplicationInstance(
|
||||
AppConfig appConfig,
|
||||
BrowserSettings settings,
|
||||
InstanceIdentifier id,
|
||||
bool isMainInstance,
|
||||
IText text,
|
||||
IUserInterfaceFactory uiFactory,
|
||||
bool isMainInstance)
|
||||
IUserInterfaceFactory uiFactory)
|
||||
{
|
||||
this.appConfig = appConfig;
|
||||
this.Id = id;
|
||||
this.isMainInstance = isMainInstance;
|
||||
this.settings = settings;
|
||||
this.text = text;
|
||||
|
@ -56,7 +57,6 @@ namespace SafeExamBrowser.Browser
|
|||
{
|
||||
var downloadHandler = new DownloadHandler(appConfig, settings);
|
||||
|
||||
Id = Guid.NewGuid();
|
||||
downloadHandler.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args);
|
||||
|
||||
control = new BrowserControl(appConfig, settings, text);
|
||||
|
|
42
SafeExamBrowser.Browser/BrowserInstanceIdentifier.cs
Normal file
42
SafeExamBrowser.Browser/BrowserInstanceIdentifier.cs
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
namespace SafeExamBrowser.Browser
|
||||
{
|
||||
internal class BrowserInstanceIdentifier : InstanceIdentifier
|
||||
{
|
||||
public int Value { get; private set; }
|
||||
|
||||
public BrowserInstanceIdentifier(int id)
|
||||
{
|
||||
Value = id;
|
||||
}
|
||||
|
||||
public override bool Equals(object other)
|
||||
{
|
||||
if (other is BrowserInstanceIdentifier id)
|
||||
{
|
||||
return Value == id.Value;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Value.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"#{Value}";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -65,6 +65,7 @@
|
|||
<Compile Include="BrowserApplicationController.cs" />
|
||||
<Compile Include="BrowserApplicationInfo.cs" />
|
||||
<Compile Include="BrowserApplicationInstance.cs" />
|
||||
<Compile Include="BrowserInstanceIdentifier.cs" />
|
||||
<Compile Include="Handlers\ContextMenuHandler.cs" />
|
||||
<Compile Include="BrowserControl.cs">
|
||||
<SubType>Component</SubType>
|
||||
|
|
|
@ -155,7 +155,7 @@ namespace SafeExamBrowser.Client
|
|||
|
||||
private IOperation BuildBrowserOperation()
|
||||
{
|
||||
var moduleLogger = new ModuleLogger(logger, typeof(BrowserApplicationController));
|
||||
var moduleLogger = new ModuleLogger(logger, "BrowserController");
|
||||
var browserController = new BrowserApplicationController(configuration.AppConfig, configuration.Settings.Browser, moduleLogger, messageBox, text, uiFactory);
|
||||
var browserInfo = new BrowserApplicationInfo();
|
||||
var operation = new BrowserOperation(browserController, browserInfo, logger, Taskbar, uiFactory);
|
||||
|
|
|
@ -11,6 +11,7 @@ using System.IO;
|
|||
using System.Reflection;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
|
||||
namespace SafeExamBrowser.Configuration
|
||||
{
|
||||
|
@ -81,7 +82,7 @@ namespace SafeExamBrowser.Configuration
|
|||
|
||||
CurrentSettings = new Settings();
|
||||
|
||||
CurrentSettings.KioskMode = KioskMode.DisableExplorerShell;
|
||||
CurrentSettings.KioskMode = KioskMode.None;
|
||||
CurrentSettings.ServicePolicy = ServicePolicy.Optional;
|
||||
|
||||
CurrentSettings.Browser.StartUrl = "https://www.safeexambrowser.org/testing";
|
||||
|
@ -117,6 +118,7 @@ namespace SafeExamBrowser.Configuration
|
|||
appConfig.ConfigurationFileExtension = ".seb";
|
||||
appConfig.DefaultSettingsFileName = "SebClientSettings.seb";
|
||||
appConfig.DownloadDirectory = Path.Combine(appDataFolder, "Downloads");
|
||||
appConfig.LogLevel = LogLevel.Debug;
|
||||
appConfig.ProgramCopyright = executable.GetCustomAttribute<AssemblyCopyrightAttribute>().Copyright;
|
||||
appConfig.ProgramDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), nameof(SafeExamBrowser));
|
||||
appConfig.ProgramTitle = executable.GetCustomAttribute<AssemblyTitleAttribute>().Title;
|
||||
|
|
|
@ -6,12 +6,11 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Behaviour.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Event handler used to indicate that an application instance with a particular ID has terminated.
|
||||
/// </summary>
|
||||
public delegate void InstanceTerminatedEventHandler(Guid id);
|
||||
public delegate void InstanceTerminatedEventHandler(InstanceIdentifier id);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Behaviour.Events;
|
||||
using SafeExamBrowser.Contracts.UserInterface.Windows;
|
||||
|
||||
|
@ -20,7 +19,7 @@ namespace SafeExamBrowser.Contracts.Behaviour
|
|||
/// <summary>
|
||||
/// The unique identifier for the application instance.
|
||||
/// </summary>
|
||||
Guid Id { get; }
|
||||
InstanceIdentifier Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The name or (document) title of the application instance.
|
||||
|
|
41
SafeExamBrowser.Contracts/Behaviour/InstanceIdentifier.cs
Normal file
41
SafeExamBrowser.Contracts/Behaviour/InstanceIdentifier.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Behaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines an identifier which uniquely identifies an <see cref="IApplicationInstance"/> in the context of a (third-party) application.
|
||||
/// </summary>
|
||||
public abstract class InstanceIdentifier
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether two identifiers are equal (i.e. whether they identify the same <see cref="IApplicationInstance"/>).
|
||||
/// </summary>
|
||||
public static bool operator ==(InstanceIdentifier a, InstanceIdentifier b) => Equals(a, b);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether two identifiers are different (i.e. whether they identify different <see cref="IApplicationInstance"/>s).
|
||||
/// </summary>
|
||||
public static bool operator !=(InstanceIdentifier a, InstanceIdentifier b) => !Equals(a, b);
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the given object is an <see cref="InstanceIdentifier"/> for the same <see cref="IApplicationInstance"/>.
|
||||
/// </summary>
|
||||
public abstract override bool Equals(object other);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a hash code for the identifier.
|
||||
/// </summary>
|
||||
public abstract override int GetHashCode();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a human-readable string representation of the identifier.
|
||||
/// </summary>
|
||||
public abstract override string ToString();
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Configuration
|
||||
{
|
||||
|
@ -71,6 +72,11 @@ namespace SafeExamBrowser.Contracts.Configuration
|
|||
/// </summary>
|
||||
public string DownloadDirectory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The currently active, global log severity threshold.
|
||||
/// </summary>
|
||||
public LogLevel LogLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The copyright information for the application (i.e. the executing assembly).
|
||||
/// </summary>
|
||||
|
|
|
@ -17,32 +17,32 @@ namespace SafeExamBrowser.Contracts.Logging
|
|||
public interface ILogger
|
||||
{
|
||||
/// <summary>
|
||||
/// Logs the given message with severity <b>DEBUG</b>.
|
||||
/// Logs the given message with severity <see cref="LogLevel.Debug"/>.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentNullException" />
|
||||
void Debug(string message);
|
||||
|
||||
/// <summary>
|
||||
/// Logs the given message with severity <b>INFO</b>.
|
||||
/// Logs the given message with severity <see cref="LogLevel.Info"/>.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentNullException" />
|
||||
void Info(string message);
|
||||
|
||||
/// <summary>
|
||||
/// Logs the given message with severity <b>WARNING</b>.
|
||||
/// Logs the given message with severity <see cref="LogLevel.Warning"/>.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentNullException" />
|
||||
void Warn(string message);
|
||||
|
||||
/// <summary>
|
||||
/// Logs the given message with severity <b>ERROR</b>.
|
||||
/// Logs the given message with severity <see cref="LogLevel.Error"/>.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentNullException" />
|
||||
void Error(string message);
|
||||
|
||||
/// <summary>
|
||||
/// Logs the given message with severity <b>ERROR</b> and includes information about
|
||||
/// the specified exception (i.e. type, message and stacktrace).
|
||||
/// Logs the given message with severity <see cref="LogLevel.Error"/> and includes
|
||||
/// information about the specified exception (i.e. type, message and stacktrace).
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentNullException" />
|
||||
void Error(string message, Exception exception);
|
||||
|
@ -60,7 +60,7 @@ namespace SafeExamBrowser.Contracts.Logging
|
|||
void Log(ILogContent content);
|
||||
|
||||
/// <summary>
|
||||
/// Suscribes an observer to the application log.
|
||||
/// Subscribes an observer to the application log.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentNullException" />
|
||||
void Subscribe(ILogObserver observer);
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
<Compile Include="Behaviour\Events\InstanceTerminatedEventHandler.cs" />
|
||||
<Compile Include="Behaviour\Events\NameChangedEventHandler.cs" />
|
||||
<Compile Include="Behaviour\IApplicationController.cs" />
|
||||
<Compile Include="Behaviour\InstanceIdentifier.cs" />
|
||||
<Compile Include="Behaviour\IRuntimeController.cs" />
|
||||
<Compile Include="Behaviour\OperationModel\IOperationSequence.cs" />
|
||||
<Compile Include="Behaviour\OperationModel\OperationResult.cs" />
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Behaviour;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.UserInterface.Taskbar.Events
|
||||
{
|
||||
|
@ -14,5 +14,5 @@ namespace SafeExamBrowser.Contracts.UserInterface.Taskbar.Events
|
|||
/// Indicates that an <see cref="IApplicationButton"/> has been clicked, optionally specifying the ID of the selected instance (if
|
||||
/// multiple instances of the same application are running).
|
||||
/// </summary>
|
||||
public delegate void ApplicationButtonClickedEventHandler(Guid? instanceId = null);
|
||||
public delegate void ApplicationButtonClickedEventHandler(InstanceIdentifier id = null);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
|
||||
namespace SafeExamBrowser.Contracts.WindowsApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines an abstraction of the Windows explorer shell (i.e. the process controlling the GUI of the operating system).
|
||||
/// </summary>
|
||||
public interface IExplorerShell
|
||||
{
|
||||
/// <summary>
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace SafeExamBrowser.Core.Communication.Proxies
|
|||
public abstract class BaseProxy : ICommunicationProxy
|
||||
{
|
||||
private const int ONE_MINUTE = 60000;
|
||||
private static readonly object @lock = new object();
|
||||
private readonly object @lock = new object();
|
||||
|
||||
private string address;
|
||||
private IProxyObject proxy;
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace SafeExamBrowser.Core.Logging
|
|||
/// </summary>
|
||||
public class LogFileWriter : ILogObserver
|
||||
{
|
||||
private static readonly object @lock = new object();
|
||||
private readonly object @lock = new object();
|
||||
private readonly string filePath;
|
||||
private readonly ILogContentFormatter formatter;
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace SafeExamBrowser.Core.Logging
|
|||
/// </summary>
|
||||
public class Logger : ILogger
|
||||
{
|
||||
private static readonly object @lock = new object();
|
||||
private readonly object @lock = new object();
|
||||
private readonly IList<ILogContent> log = new List<ILogContent>();
|
||||
private readonly IList<ILogObserver> observers = new List<ILogObserver>();
|
||||
|
||||
|
|
|
@ -18,12 +18,16 @@ namespace SafeExamBrowser.Core.Logging
|
|||
public class ModuleLogger : ILogger
|
||||
{
|
||||
private ILogger logger;
|
||||
private Type module;
|
||||
private string moduleInfo;
|
||||
|
||||
public ModuleLogger(ILogger logger, Type module)
|
||||
public ModuleLogger(ILogger logger, string moduleInfo)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.module = module;
|
||||
this.moduleInfo = moduleInfo;
|
||||
}
|
||||
|
||||
public ModuleLogger(ILogger logger, Type module) : this(logger, module.Name)
|
||||
{
|
||||
}
|
||||
|
||||
public void Debug(string message)
|
||||
|
@ -78,7 +82,7 @@ namespace SafeExamBrowser.Core.Logging
|
|||
|
||||
private string AppendModuleInfo(string message)
|
||||
{
|
||||
return $"[{module.Name}] {message}";
|
||||
return $"[{moduleInfo}] {message}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
|
@ -90,7 +89,7 @@ namespace SafeExamBrowser.UserInterface.Classic.Controls
|
|||
}
|
||||
}
|
||||
|
||||
private void Instance_OnTerminated(Guid id, ApplicationInstanceButton instanceButton)
|
||||
private void Instance_OnTerminated(InstanceIdentifier id, ApplicationInstanceButton instanceButton)
|
||||
{
|
||||
instances.Remove(instances.FirstOrDefault(i => i.Id == id));
|
||||
InstanceStackPanel.Children.Remove(instanceButton);
|
||||
|
|
|
@ -6,23 +6,21 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using SafeExamBrowser.Contracts.Behaviour;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events;
|
||||
using SafeExamBrowser.UserInterface.Classic.Utilities;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Classic.Controls
|
||||
{
|
||||
internal delegate void InstanceButtonClickedEventHandler(Guid instanceId);
|
||||
|
||||
public partial class ApplicationInstanceButton : UserControl
|
||||
{
|
||||
private IApplicationInfo info;
|
||||
private IApplicationInstance instance;
|
||||
|
||||
internal event InstanceButtonClickedEventHandler Clicked;
|
||||
internal event ApplicationButtonClickedEventHandler Clicked;
|
||||
|
||||
public ApplicationInstanceButton(IApplicationInstance instance, IApplicationInfo info)
|
||||
{
|
||||
|
|
|
@ -91,7 +91,7 @@ namespace SafeExamBrowser.UserInterface.Windows10.Controls
|
|||
}
|
||||
}
|
||||
|
||||
private void Instance_OnTerminated(Guid id, ApplicationInstanceButton instanceButton)
|
||||
private void Instance_OnTerminated(InstanceIdentifier id, ApplicationInstanceButton instanceButton)
|
||||
{
|
||||
instances.Remove(instances.FirstOrDefault(i => i.Id == id));
|
||||
InstanceStackPanel.Children.Remove(instanceButton);
|
||||
|
|
|
@ -6,23 +6,21 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using SafeExamBrowser.Contracts.Behaviour;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events;
|
||||
using SafeExamBrowser.UserInterface.Windows10.Utilities;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Windows10.Controls
|
||||
{
|
||||
internal delegate void InstanceButtonClickedEventHandler(Guid instanceId);
|
||||
|
||||
public partial class ApplicationInstanceButton : UserControl
|
||||
{
|
||||
private IApplicationInfo info;
|
||||
private IApplicationInstance instance;
|
||||
|
||||
internal event InstanceButtonClickedEventHandler Clicked;
|
||||
internal event ApplicationButtonClickedEventHandler Clicked;
|
||||
|
||||
public ApplicationInstanceButton(IApplicationInstance instance, IApplicationInfo info)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue