SEBWIN-312: Implemented loading of whitelisted applications into shell.

This commit is contained in:
dbuechel 2019-11-06 08:45:37 +01:00
parent 7e76b029a6
commit c21005b934
58 changed files with 300 additions and 211 deletions

View file

@ -13,21 +13,21 @@ namespace SafeExamBrowser.Applications.Contracts
/// <summary>
/// The information about an application which can be accessed via the shell.
/// </summary>
public interface IApplicationInfo
public class ApplicationInfo
{
/// <summary>
/// The name of the application.
/// </summary>
string Name { get; }
public string Name { get; set; }
/// <summary>
/// The tooltip for the application.
/// </summary>
string Tooltip { get; }
public string Tooltip { get; set; }
/// <summary>
/// The resource providing the application icon.
/// </summary>
IIconResource IconResource { get; }
public IconResource IconResource { get; set; }
}
}

View file

@ -13,5 +13,5 @@ namespace SafeExamBrowser.Applications.Contracts.Events
/// <summary>
/// Event handler used to indicate that the icon of an <see cref="IApplicationInstance"/> has changed.
/// </summary>
public delegate void IconChangedEventHandler(IIconResource icon);
public delegate void IconChangedEventHandler(IconResource icon);
}

View file

@ -18,7 +18,7 @@ namespace SafeExamBrowser.Applications.Contracts
/// <summary>
/// Provides information about the application.
/// </summary>
IApplicationInfo Info { get; }
ApplicationInfo Info { get; }
/// <summary>
/// Fired when a new <see cref="IApplicationInstance"/> has started.

View file

@ -60,7 +60,7 @@
<Compile Include="FactoryResult.cs" />
<Compile Include="IApplication.cs" />
<Compile Include="IApplicationFactory.cs" />
<Compile Include="IApplicationInfo.cs" />
<Compile Include="ApplicationInfo.cs" />
<Compile Include="IApplicationInstance.cs" />
<Compile Include="InstanceIdentifier.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

View file

@ -11,6 +11,7 @@ using System.Collections.Generic;
using System.IO;
using Microsoft.Win32;
using SafeExamBrowser.Applications.Contracts;
using SafeExamBrowser.Core.Contracts;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Settings.Applications;
@ -27,33 +28,46 @@ namespace SafeExamBrowser.Applications
public FactoryResult TryCreate(WhitelistApplication settings, out IApplication application)
{
var name = $"'{settings.DisplayName}' ({ settings.ExecutableName})";
application = default(IApplication);
try
{
var success = TryFindMainExecutable(settings, out var mainExecutable);
var success = TryFindApplication(settings, out var executablePath);
if (success)
{
application = new ExternalApplication();
logger.Debug($"Successfully initialized application '{settings.DisplayName}' ({settings.ExecutableName}).");
application = BuildApplication(executablePath, settings);
application.Initialize();
logger.Debug($"Successfully initialized application {name}.");
return FactoryResult.Success;
}
logger.Error($"Could not find application '{settings.DisplayName}' ({settings.ExecutableName})!");
logger.Error($"Could not find application {name}!");
return FactoryResult.NotFound;
}
catch (Exception e)
{
logger.Error($"Unexpected error while trying to create application '{settings.DisplayName}' ({settings.ExecutableName})!", e);
logger.Error($"Unexpected error while trying to initialize application {name}!", e);
}
return FactoryResult.Error;
}
private bool TryFindMainExecutable(WhitelistApplication settings, out string mainExecutable)
private IApplication BuildApplication(string executablePath, WhitelistApplication settings)
{
var icon = new IconResource { Type = IconResourceType.Embedded, Uri = new Uri(executablePath) };
var info = new ApplicationInfo { IconResource = icon, Name = settings.DisplayName, Tooltip = settings.Description ?? settings.DisplayName };
var application = new ExternalApplication(executablePath, info);
return application;
}
private bool TryFindApplication(WhitelistApplication settings, out string mainExecutable)
{
var paths = new List<string[]>();
var registryPath = QueryPathFromRegistry(settings);

View file

@ -6,7 +6,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
using SafeExamBrowser.Applications.Contracts;
using SafeExamBrowser.Applications.Contracts.Events;
@ -14,10 +13,18 @@ namespace SafeExamBrowser.Applications
{
internal class ExternalApplication : IApplication
{
public IApplicationInfo Info => throw new NotImplementedException();
private string executablePath;
public ApplicationInfo Info { get; }
public event InstanceStartedEventHandler InstanceStarted;
internal ExternalApplication(string executablePath, ApplicationInfo info)
{
this.executablePath = executablePath;
this.Info = info;
}
public void Initialize()
{

View file

@ -62,6 +62,10 @@
<Project>{ac77745d-3b41-43e2-8e84-d40e5a4ee77f}</Project>
<Name>SafeExamBrowser.Applications.Contracts</Name>
</ProjectReference>
<ProjectReference Include="..\SafeExamBrowser.Core.Contracts\SafeExamBrowser.Core.Contracts.csproj">
<Project>{fe0e1224-b447-4b14-81e7-ed7d84822aa0}</Project>
<Name>SafeExamBrowser.Core.Contracts</Name>
</ProjectReference>
<ProjectReference Include="..\SafeExamBrowser.Logging.Contracts\SafeExamBrowser.Logging.Contracts.csproj">
<Project>{64ea30fb-11d4-436a-9c2b-88566285363e}</Project>
<Name>SafeExamBrowser.Logging.Contracts</Name>

View file

@ -38,7 +38,7 @@ namespace SafeExamBrowser.Browser
private IText text;
private IUserInterfaceFactory uiFactory;
public IApplicationInfo Info { get; private set; }
public ApplicationInfo Info { get; private set; }
public event DownloadRequestedEventHandler ConfigurationDownloadRequested;
public event InstanceStartedEventHandler InstanceStarted;
@ -65,7 +65,7 @@ namespace SafeExamBrowser.Browser
var cefSettings = InitializeCefSettings();
var success = Cef.Initialize(cefSettings, true, default(IApp));
Info = new BrowserApplicationInfo();
Info = BuildApplicationInfo();
if (success)
{
@ -95,6 +95,16 @@ namespace SafeExamBrowser.Browser
logger.Info("Terminated browser.");
}
private ApplicationInfo BuildApplicationInfo()
{
return new ApplicationInfo
{
IconResource = new BrowserIconResource(),
Name = "Safe Exam Browser",
Tooltip = text.Get(TextKey.Browser_Tooltip)
};
}
private void CreateNewInstance(string url = null)
{
var id = new BrowserInstanceIdentifier(++instanceIdCounter);

View file

@ -1,20 +0,0 @@
/*
* Copyright (c) 2019 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.Applications.Contracts;
using SafeExamBrowser.Core.Contracts;
namespace SafeExamBrowser.Browser
{
public class BrowserApplicationInfo : IApplicationInfo
{
public string Name => "Safe Exam Browser";
public string Tooltip => Name;
public IIconResource IconResource { get; } = new BrowserIconResource();
}
}

View file

@ -11,14 +11,11 @@ using SafeExamBrowser.Core.Contracts;
namespace SafeExamBrowser.Browser
{
public class BrowserIconResource : IIconResource
public class BrowserIconResource : IconResource
{
public Uri Uri { get; private set; }
public bool IsBitmapResource => true;
public bool IsXamlResource => false;
public BrowserIconResource(string uri = null)
{
Type = IconResourceType.Bitmap;
Uri = new Uri(uri ?? "pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/SafeExamBrowser.ico");
}
}

View file

@ -66,7 +66,6 @@
</ItemGroup>
<ItemGroup>
<Compile Include="BrowserApplication.cs" />
<Compile Include="BrowserApplicationInfo.cs" />
<Compile Include="BrowserApplicationInstance.cs" />
<Compile Include="BrowserInstanceIdentifier.cs" />
<Compile Include="Events\FaviconChangedEventHandler.cs" />

View file

@ -23,6 +23,6 @@ namespace SafeExamBrowser.Client.Contracts
/// <summary>
/// The resource providing the notification icon.
/// </summary>
IIconResource IconResource { get; }
IconResource IconResource { get; }
}
}

View file

@ -49,8 +49,8 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
sut.Perform();
browser.Verify(c => c.Initialize(), Times.Once);
actionCenter.Verify(a => a.AddApplicationControl(It.IsAny<IApplicationControl>()), Times.Once);
taskbar.Verify(t => t.AddApplicationControl(It.IsAny<IApplicationControl>()), Times.Once);
actionCenter.Verify(a => a.AddApplicationControl(It.IsAny<IApplicationControl>(), true), Times.Once);
taskbar.Verify(t => t.AddApplicationControl(It.IsAny<IApplicationControl>(), true), Times.Once);
}
[TestMethod]

View file

@ -198,7 +198,6 @@ namespace SafeExamBrowser.Client
{
var moduleLogger = ModuleLogger(nameof(BrowserApplication));
var browser = new BrowserApplication(context.AppConfig, context.Settings.Browser, messageBox, moduleLogger, text, uiFactory);
var browserInfo = new BrowserApplicationInfo();
var operation = new BrowserOperation(actionCenter, context, logger, taskbar, uiFactory);
context.Browser = browser;

View file

@ -1,20 +0,0 @@
/*
* Copyright (c) 2019 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.Core.Contracts;
namespace SafeExamBrowser.Client.Notifications
{
internal class AboutNotificationIconResource : IIconResource
{
public Uri Uri => new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/AboutNotification.xaml");
public bool IsBitmapResource => false;
public bool IsXamlResource => true;
}
}

View file

@ -6,6 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
using SafeExamBrowser.Client.Contracts;
using SafeExamBrowser.Core.Contracts;
using SafeExamBrowser.I18n.Contracts;
@ -14,14 +15,17 @@ namespace SafeExamBrowser.Client.Notifications
{
internal class AboutNotificationInfo : INotificationInfo
{
private IText text;
public string Tooltip => text.Get(TextKey.Notification_AboutTooltip);
public IIconResource IconResource { get; } = new AboutNotificationIconResource();
public string Tooltip { get; }
public IconResource IconResource { get; }
public AboutNotificationInfo(IText text)
{
this.text = text;
IconResource = new IconResource
{
Type = IconResourceType.Xaml,
Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/AboutNotification.xaml")
};
Tooltip = text.Get(TextKey.Notification_AboutTooltip);
}
}
}

View file

@ -1,20 +0,0 @@
/*
* Copyright (c) 2019 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.Core.Contracts;
namespace SafeExamBrowser.Client.Notifications
{
internal class LogNotificationIconResource : IIconResource
{
public Uri Uri => new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/LogNotification.ico");
public bool IsBitmapResource => true;
public bool IsXamlResource => false;
}
}

View file

@ -6,6 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
using SafeExamBrowser.Client.Contracts;
using SafeExamBrowser.Core.Contracts;
using SafeExamBrowser.I18n.Contracts;
@ -14,13 +15,17 @@ namespace SafeExamBrowser.Client.Notifications
{
internal class LogNotificationInfo : INotificationInfo
{
public string Tooltip { get; private set; }
public IIconResource IconResource { get; private set; }
public string Tooltip { get; }
public IconResource IconResource { get; }
public LogNotificationInfo(IText text)
{
IconResource = new IconResource
{
Type = IconResourceType.Bitmap,
Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/LogNotification.ico")
};
Tooltip = text.Get(TextKey.Notification_LogTooltip);
IconResource = new LogNotificationIconResource();
}
}
}

View file

@ -117,7 +117,6 @@ namespace SafeExamBrowser.Client.Operations
if (result == FactoryResult.Success)
{
application.Initialize();
Context.Applications.Add(application);
}
else
@ -129,7 +128,10 @@ namespace SafeExamBrowser.Client.Operations
private void FinalizeApplications()
{
// TODO: Terminate all running applications!
foreach (var application in Context.Applications)
{
application.Terminate();
}
}
private OperationResult HandleAutoTerminationFailure(IList<RunningApplication> applications)

View file

@ -45,8 +45,15 @@ namespace SafeExamBrowser.Client.Operations
Context.Browser.Initialize();
actionCenter.AddApplicationControl(uiFactory.CreateApplicationControl(Context.Browser, Location.ActionCenter));
taskbar.AddApplicationControl(uiFactory.CreateApplicationControl(Context.Browser, Location.Taskbar));
if (Context.Settings.ActionCenter.EnableActionCenter)
{
actionCenter.AddApplicationControl(uiFactory.CreateApplicationControl(Context.Browser, Location.ActionCenter), true);
}
if (Context.Settings.Taskbar.EnableTaskbar)
{
taskbar.AddApplicationControl(uiFactory.CreateApplicationControl(Context.Browser, Location.Taskbar), true);
}
return OperationResult.Success;
}

View file

@ -124,6 +124,7 @@ namespace SafeExamBrowser.Client.Operations
logger.Info("Initializing action center...");
actionCenter.InitializeText(text);
InitializeApplicationsFor(Location.ActionCenter);
InitializeAboutNotificationForActionCenter();
InitializeAudioForActionCenter();
InitializeClockForActionCenter();
@ -145,6 +146,7 @@ namespace SafeExamBrowser.Client.Operations
logger.Info("Initializing taskbar...");
taskbar.InitializeText(text);
InitializeApplicationsFor(Location.Taskbar);
InitializeAboutNotificationForTaskbar();
InitializeLogNotificationForTaskbar();
InitializePowerSupplyForTaskbar();
@ -159,6 +161,24 @@ namespace SafeExamBrowser.Client.Operations
}
}
private void InitializeApplicationsFor(Location location)
{
foreach (var application in Context.Applications)
{
var control = uiFactory.CreateApplicationControl(application, location);
switch (location)
{
case Location.ActionCenter:
actionCenter.AddApplicationControl(control);
break;
case Location.Taskbar:
taskbar.AddApplicationControl(control);
break;
}
}
}
private void InitializeSystemComponents()
{
audio.Initialize();

View file

@ -84,10 +84,8 @@
<Compile Include="Communication\ClientHost.cs" />
<Compile Include="CompositionRoot.cs" />
<Compile Include="Notifications\AboutNotificationController.cs" />
<Compile Include="Notifications\AboutNotificationIconResource.cs" />
<Compile Include="Notifications\AboutNotificationInfo.cs" />
<Compile Include="Notifications\LogNotificationController.cs" />
<Compile Include="Notifications\LogNotificationIconResource.cs" />
<Compile Include="Notifications\LogNotificationInfo.cs" />
<Compile Include="Operations\BrowserOperation.cs" />
<Compile Include="Operations\ClipboardOperation.cs" />

View file

@ -102,6 +102,11 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
application.AutoTerminate = autoTerminate;
}
if (applicationData.TryGetValue(Keys.Applications.Description, out v) && v is string description)
{
application.Description = description;
}
if (applicationData.TryGetValue(Keys.Applications.DisplayName, out v) && v is string displayName)
{
application.DisplayName = displayName;

View file

@ -26,6 +26,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
internal const string AutoStart = "autostart";
internal const string AutoTerminate = "strongKill";
internal const string Blacklist = "prohibitedProcesses";
internal const string Description = "description";
internal const string DisplayName = "title";
internal const string ExecutableName = "executable";
internal const string ExecutablePath = "path";

View file

@ -13,21 +13,16 @@ namespace SafeExamBrowser.Core.Contracts
/// <summary>
/// Defines an icon resource, i.e. the path to and type of an icon.
/// </summary>
public interface IIconResource
public class IconResource
{
/// <summary>
/// The <see cref="System.Uri"/> pointing to the icon.
/// Defines the data type of the resource.
/// </summary>
Uri Uri { get; }
public IconResourceType Type { get; set; }
/// <summary>
/// Indicates whether the icon resource consists of a bitmap image (i.e. raster graphics).
/// The <see cref="System.Uri"/> pointing to the icon data.
/// </summary>
bool IsBitmapResource { get; }
/// <summary>
/// Indicates whether the icon resource consists of XAML markup (i.e. vector graphics).
/// </summary>
bool IsXamlResource { get; }
public Uri Uri { get; set; }
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2019 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.Core.Contracts
{
/// <summary>
/// Defines the data format of an icon resource.
/// </summary>
public enum IconResourceType
{
/// <summary>
/// The icon resource is a bitmap image (i.e. raster graphics).
/// </summary>
Bitmap,
/// <summary>
/// The icon resource is a file with embedded icon data (e.g. an executable).
/// </summary>
Embedded,
/// <summary>
/// The icon resource consists of XAML markup (i.e. vector graphics).
/// </summary>
Xaml
}
}

View file

@ -53,7 +53,8 @@
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup>
<Compile Include="IIconResource.cs" />
<Compile Include="IconResource.cs" />
<Compile Include="IconResourceType.cs" />
<Compile Include="OperationModel\Events\ActionRequiredEventArgs.cs" />
<Compile Include="OperationModel\Events\ActionRequiredEventHandler.cs" />
<Compile Include="OperationModel\Events\ProgressChangedEventArgs.cs" />

View file

@ -18,6 +18,7 @@ namespace SafeExamBrowser.I18n.Contracts
Browser_BlockedPageButton,
Browser_BlockedPageMessage,
Browser_BlockedPageTitle,
Browser_Tooltip,
BrowserWindow_DeveloperConsoleMenuItem,
BrowserWindow_ZoomMenuItem,
Build,

View file

@ -12,6 +12,9 @@
<Entry key="Browser_BlockedPageTitle">
Page Blocked
</Entry>
<Entry key="Browser_Tooltip">
Browser Application
</Entry>
<Entry key="BrowserWindow_DeveloperConsoleMenuItem">
Developer Console
</Entry>

View file

@ -42,6 +42,11 @@ namespace SafeExamBrowser.Settings.Applications
/// </summary>
public bool AutoTerminate { get; set; }
/// <summary>
/// Provides further information about the application.
/// </summary>
public string Description { get; set; }
/// <summary>
/// The display name to be used for the application (e.g. in the shell).
/// </summary>

View file

@ -75,7 +75,7 @@ namespace SafeExamBrowser.UserInterface.Contracts.Browser
/// <summary>
/// Updates the icon of the browser window.
/// </summary>
void UpdateIcon(IIconResource icon);
void UpdateIcon(IconResource icon);
/// <summary>
/// Updates the loading state according to the given value.

View file

@ -29,7 +29,7 @@ namespace SafeExamBrowser.UserInterface.Contracts.Shell
/// <summary>
/// Adds the given application control to the action center.
/// </summary>
void AddApplicationControl(IApplicationControl control);
void AddApplicationControl(IApplicationControl control, bool atFirstPosition = false);
/// <summary>
/// Adds the given notification control to the action center.

View file

@ -29,7 +29,7 @@ namespace SafeExamBrowser.UserInterface.Contracts.Shell
/// <summary>
/// Adds the given application control to the taskbar.
/// </summary>
void AddApplicationControl(IApplicationControl control);
void AddApplicationControl(IApplicationControl control, bool atFirstPosition = false);
/// <summary>
/// Adds the given notification control to the taskbar.

View file

@ -30,11 +30,18 @@ namespace SafeExamBrowser.UserInterface.Desktop
InitializeActionCenter();
}
public void AddApplicationControl(IApplicationControl control)
public void AddApplicationControl(IApplicationControl control, bool atFirstPosition = false)
{
if (control is UIElement uiElement)
{
ApplicationPanel.Children.Add(uiElement);
if (atFirstPosition)
{
ApplicationPanel.Children.Insert(0, uiElement);
}
else
{
ApplicationPanel.Children.Add(uiElement);
}
}
}

View file

@ -104,7 +104,7 @@ namespace SafeExamBrowser.UserInterface.Desktop
Dispatcher.Invoke(() => UrlTextBox.Text = url);
}
public void UpdateIcon(IIconResource icon)
public void UpdateIcon(IconResource icon)
{
Dispatcher.InvokeAsync(() => Icon = new BitmapImage(icon.Uri));
}
@ -282,10 +282,10 @@ namespace SafeExamBrowser.UserInterface.Desktop
var forwardUri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/NavigateForward.xaml");
var menuUri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Menu.xaml");
var reloadUri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Reload.xaml");
var backward = new XamlIconResource(backUri);
var forward = new XamlIconResource(forwardUri);
var menu = new XamlIconResource(menuUri);
var reload = new XamlIconResource(reloadUri);
var backward = new IconResource { Type = IconResourceType.Xaml, Uri = backUri };
var forward = new IconResource { Type = IconResourceType.Xaml, Uri = forwardUri };
var menu = new IconResource { Type = IconResourceType.Xaml, Uri = menuUri };
var reload = new IconResource { Type = IconResourceType.Xaml, Uri = reloadUri };
BackwardButton.Content = IconResourceLoader.Load(backward);
ForwardButton.Content = IconResourceLoader.Load(forward);

View file

@ -16,12 +16,12 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
{
public partial class ActionCenterApplicationButton : UserControl
{
private IApplicationInfo info;
private ApplicationInfo info;
private IApplicationInstance instance;
internal event EventHandler Clicked;
public ActionCenterApplicationButton(IApplicationInfo info, IApplicationInstance instance = null)
public ActionCenterApplicationButton(ApplicationInfo info, IApplicationInstance instance = null)
{
this.info = info;
this.instance = instance;
@ -44,7 +44,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
}
}
private void Instance_IconChanged(IIconResource icon)
private void Instance_IconChanged(IconResource icon)
{
Dispatcher.InvokeAsync(() => Icon.Content = IconResourceLoader.Load(icon));
}

View file

@ -13,6 +13,7 @@ using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Windows.Threading;
using SafeExamBrowser.Core.Contracts;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.SystemComponents.Contracts.Audio;
using SafeExamBrowser.UserInterface.Contracts.Shell;
@ -25,8 +26,8 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
private readonly IAudio audio;
private readonly IText text;
private bool muted;
private XamlIconResource MutedIcon;
private XamlIconResource NoDeviceIcon;
private IconResource MutedIcon;
private IconResource NoDeviceIcon;
public ActionCenterAudioControl(IAudio audio, IText text)
{
@ -50,8 +51,8 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen;
Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver));
MuteButton.Click += MuteButton_Click;
MutedIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Muted.xaml"));
NoDeviceIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Light_NoDevice.xaml"));
MutedIcon = new IconResource { Type = IconResourceType.Xaml, Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Muted.xaml") };
NoDeviceIcon = new IconResource { Type = IconResourceType.Xaml, Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Light_NoDevice.xaml") };
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver));
Popup.Opened += (o, args) => Grid.Background = Brushes.Gray;
Popup.Closed += (o, args) => Grid.Background = originalBrush;
@ -146,7 +147,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
{
var icon = volume > 0.66 ? "100" : (volume > 0.33 ? "66" : "33");
var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Light_{icon}.xaml");
var resource = new XamlIconResource(uri);
var resource = new IconResource { Type = IconResourceType.Xaml, Uri = uri};
return IconResourceLoader.Load(resource);
}

View file

@ -9,6 +9,7 @@
using System;
using System.ComponentModel;
using System.Windows.Controls;
using SafeExamBrowser.Core.Contracts;
using SafeExamBrowser.UserInterface.Contracts.Shell.Events;
using SafeExamBrowser.UserInterface.Shared.Utilities;
@ -27,7 +28,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
private void InitializeControl()
{
var uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/ShutDown.xaml");
var resource = new XamlIconResource(uri);
var resource = new IconResource { Type = IconResourceType.Xaml, Uri = uri };
Icon.Content = IconResourceLoader.Load(resource);
Button.Click += (o, args) => Clicked?.Invoke(new CancelEventArgs());

View file

@ -12,6 +12,7 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using FontAwesome.WPF;
using SafeExamBrowser.Core.Contracts;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork;
using SafeExamBrowser.UserInterface.Contracts.Shell;
@ -133,7 +134,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
{
var icon = signalStrength > 66 ? "100" : (signalStrength > 33 ? "66" : (signalStrength > 0 ? "33" : "0"));
var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/WiFi_Light_{icon}.xaml");
var resource = new XamlIconResource(uri);
var resource = new IconResource { Type = IconResourceType.Xaml, Uri = uri };
return IconResourceLoader.Load(resource);
}

View file

@ -16,10 +16,10 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
{
public partial class TaskbarApplicationInstanceButton : UserControl
{
private IApplicationInfo info;
private ApplicationInfo info;
private IApplicationInstance instance;
public TaskbarApplicationInstanceButton(IApplicationInstance instance, IApplicationInfo info)
public TaskbarApplicationInstanceButton(IApplicationInstance instance, ApplicationInfo info)
{
this.info = info;
this.instance = instance;
@ -43,7 +43,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
instance.Activate();
}
private void Instance_IconChanged(IIconResource icon)
private void Instance_IconChanged(IconResource icon)
{
Dispatcher.InvokeAsync(() => Icon.Content = IconResourceLoader.Load(icon));
}

View file

@ -12,6 +12,7 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using SafeExamBrowser.Core.Contracts;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.SystemComponents.Contracts.Audio;
using SafeExamBrowser.UserInterface.Contracts.Shell;
@ -24,8 +25,8 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
private readonly IAudio audio;
private readonly IText text;
private bool muted;
private XamlIconResource MutedIcon;
private XamlIconResource NoDeviceIcon;
private IconResource MutedIcon;
private IconResource NoDeviceIcon;
public TaskbarAudioControl(IAudio audio, IText text)
{
@ -49,8 +50,8 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen;
Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver));
MuteButton.Click += MuteButton_Click;
MutedIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Muted.xaml"));
NoDeviceIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_NoDevice.xaml"));
MutedIcon = new IconResource { Type = IconResourceType.Xaml, Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_Muted.xaml") };
NoDeviceIcon = new IconResource { Type = IconResourceType.Xaml, Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_NoDevice.xaml") };
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver));
Volume.ValueChanged += Volume_ValueChanged;
@ -153,7 +154,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
{
var icon = volume > 0.66 ? "100" : (volume > 0.33 ? "66" : "33");
var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Audio_{icon}.xaml");
var resource = new XamlIconResource(uri);
var resource = new IconResource { Type = IconResourceType.Xaml, Uri = uri };
return IconResourceLoader.Load(resource);
}

View file

@ -10,6 +10,7 @@ using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using SafeExamBrowser.Core.Contracts;
using SafeExamBrowser.UserInterface.Contracts.Shell.Events;
using SafeExamBrowser.UserInterface.Shared.Utilities;
@ -33,7 +34,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
private void LoadIcon()
{
var uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/ShutDown.xaml");
var resource = new XamlIconResource(uri);
var resource = new IconResource { Type = IconResourceType.Xaml, Uri = uri };
Button.Content = IconResourceLoader.Load(resource);
}

View file

@ -12,6 +12,7 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using FontAwesome.WPF;
using SafeExamBrowser.Core.Contracts;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork;
using SafeExamBrowser.UserInterface.Contracts.Shell;
@ -142,7 +143,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
{
var icon = signalStrength > 66 ? "100" : (signalStrength > 33 ? "66" : (signalStrength > 0 ? "33" : "0"));
var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/WiFi_{icon}.xaml");
var resource = new XamlIconResource(uri);
var resource = new IconResource { Type = IconResourceType.Xaml, Uri = uri };
return IconResourceLoader.Load(resource);
}

View file

@ -36,11 +36,18 @@ namespace SafeExamBrowser.UserInterface.Desktop
InitializeTaskbar();
}
public void AddApplicationControl(IApplicationControl control)
public void AddApplicationControl(IApplicationControl control, bool atFirstPosition = false)
{
if (control is UIElement uiElement)
{
ApplicationStackPanel.Children.Add(uiElement);
if (atFirstPosition)
{
ApplicationStackPanel.Children.Insert(0, uiElement);
}
else
{
ApplicationStackPanel.Children.Add(uiElement);
}
}
}

View file

@ -30,11 +30,18 @@ namespace SafeExamBrowser.UserInterface.Mobile
InitializeActionCenter();
}
public void AddApplicationControl(IApplicationControl control)
public void AddApplicationControl(IApplicationControl control, bool atFirstPosition = false)
{
if (control is UIElement uiElement)
{
ApplicationPanel.Children.Add(uiElement);
if (atFirstPosition)
{
ApplicationPanel.Children.Insert(0, uiElement);
}
else
{
ApplicationPanel.Children.Add(uiElement);
}
}
}

View file

@ -104,7 +104,7 @@ namespace SafeExamBrowser.UserInterface.Mobile
Dispatcher.Invoke(() => UrlTextBox.Text = url);
}
public void UpdateIcon(IIconResource icon)
public void UpdateIcon(IconResource icon)
{
Dispatcher.InvokeAsync(() => Icon = new BitmapImage(icon.Uri));
}
@ -291,10 +291,10 @@ namespace SafeExamBrowser.UserInterface.Mobile
var forwardUri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/NavigateForward.xaml");
var menuUri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Menu.xaml");
var reloadUri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/Reload.xaml");
var backward = new XamlIconResource(backUri);
var forward = new XamlIconResource(forwardUri);
var menu = new XamlIconResource(menuUri);
var reload = new XamlIconResource(reloadUri);
var backward = new IconResource { Type = IconResourceType.Xaml, Uri = backUri };
var forward = new IconResource { Type = IconResourceType.Xaml, Uri = forwardUri };
var menu = new IconResource { Type = IconResourceType.Xaml, Uri = menuUri };
var reload = new IconResource { Type = IconResourceType.Xaml, Uri = reloadUri };
BackwardButton.Content = IconResourceLoader.Load(backward);
ForwardButton.Content = IconResourceLoader.Load(forward);

View file

@ -16,12 +16,12 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls
{
public partial class ActionCenterApplicationButton : UserControl
{
private IApplicationInfo info;
private ApplicationInfo info;
private IApplicationInstance instance;
internal event EventHandler Clicked;
public ActionCenterApplicationButton(IApplicationInfo info, IApplicationInstance instance = null)
public ActionCenterApplicationButton(ApplicationInfo info, IApplicationInstance instance = null)
{
this.info = info;
this.instance = instance;
@ -44,7 +44,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls
}
}
private void Instance_IconChanged(IIconResource icon)
private void Instance_IconChanged(IconResource icon)
{
Dispatcher.InvokeAsync(() => Icon.Content = IconResourceLoader.Load(icon));
}

View file

@ -13,6 +13,7 @@ using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Windows.Threading;
using SafeExamBrowser.Core.Contracts;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.SystemComponents.Contracts.Audio;
using SafeExamBrowser.UserInterface.Contracts.Shell;
@ -25,8 +26,8 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls
private readonly IAudio audio;
private readonly IText text;
private bool muted;
private XamlIconResource MutedIcon;
private XamlIconResource NoDeviceIcon;
private IconResource MutedIcon;
private IconResource NoDeviceIcon;
public ActionCenterAudioControl(IAudio audio, IText text)
{
@ -50,8 +51,8 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls
Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen;
Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver));
MuteButton.Click += MuteButton_Click;
MutedIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/Audio_Muted.xaml"));
NoDeviceIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/Audio_Light_NoDevice.xaml"));
MutedIcon = new IconResource { Type = IconResourceType.Xaml, Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/Audio_Muted.xaml") };
NoDeviceIcon = new IconResource { Type = IconResourceType.Xaml, Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/Audio_Light_NoDevice.xaml") };
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver));
Popup.Opened += (o, args) => Grid.Background = Brushes.Gray;
Popup.Closed += (o, args) => Grid.Background = originalBrush;
@ -145,7 +146,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls
{
var icon = volume > 0.66 ? "100" : (volume > 0.33 ? "66" : "33");
var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/Audio_Light_{icon}.xaml");
var resource = new XamlIconResource(uri);
var resource = new IconResource { Type = IconResourceType.Xaml, Uri = uri };
return IconResourceLoader.Load(resource);
}

View file

@ -9,6 +9,7 @@
using System;
using System.ComponentModel;
using System.Windows.Controls;
using SafeExamBrowser.Core.Contracts;
using SafeExamBrowser.UserInterface.Contracts.Shell.Events;
using SafeExamBrowser.UserInterface.Shared.Utilities;
@ -27,7 +28,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls
private void InitializeControl()
{
var uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/ShutDown.xaml");
var resource = new XamlIconResource(uri);
var resource = new IconResource { Type = IconResourceType.Xaml, Uri = uri };
Icon.Content = IconResourceLoader.Load(resource);
Button.Click += (o, args) => Clicked?.Invoke(new CancelEventArgs());

View file

@ -12,6 +12,7 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using FontAwesome.WPF;
using SafeExamBrowser.Core.Contracts;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork;
using SafeExamBrowser.UserInterface.Contracts.Shell;
@ -133,7 +134,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls
{
var icon = signalStrength > 66 ? "100" : (signalStrength > 33 ? "66" : (signalStrength > 0 ? "33" : "0"));
var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/WiFi_Light_{icon}.xaml");
var resource = new XamlIconResource(uri);
var resource = new IconResource { Type = IconResourceType.Xaml, Uri = uri };
return IconResourceLoader.Load(resource);
}

View file

@ -16,10 +16,10 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls
{
public partial class TaskbarApplicationInstanceButton : UserControl
{
private IApplicationInfo info;
private ApplicationInfo info;
private IApplicationInstance instance;
public TaskbarApplicationInstanceButton(IApplicationInstance instance, IApplicationInfo info)
public TaskbarApplicationInstanceButton(IApplicationInstance instance, ApplicationInfo info)
{
this.info = info;
this.instance = instance;
@ -43,7 +43,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls
instance.Activate();
}
private void Instance_IconChanged(IIconResource icon)
private void Instance_IconChanged(IconResource icon)
{
Dispatcher.InvokeAsync(() => Icon.Content = IconResourceLoader.Load(icon));
}

View file

@ -12,6 +12,7 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using SafeExamBrowser.Core.Contracts;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.SystemComponents.Contracts.Audio;
using SafeExamBrowser.UserInterface.Contracts.Shell;
@ -24,8 +25,8 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls
private readonly IAudio audio;
private readonly IText text;
private bool muted;
private XamlIconResource MutedIcon;
private XamlIconResource NoDeviceIcon;
private IconResource MutedIcon;
private IconResource NoDeviceIcon;
public TaskbarAudioControl(IAudio audio, IText text)
{
@ -49,8 +50,8 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls
Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen;
Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver));
MuteButton.Click += MuteButton_Click;
MutedIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/Audio_Muted.xaml"));
NoDeviceIcon = new XamlIconResource(new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/Audio_NoDevice.xaml"));
MutedIcon = new IconResource { Type = IconResourceType.Xaml, Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/Audio_Muted.xaml") };
NoDeviceIcon = new IconResource { Type = IconResourceType.Xaml, Uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/Audio_NoDevice.xaml") };
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver));
Volume.ValueChanged += Volume_ValueChanged;
@ -153,7 +154,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls
{
var icon = volume > 0.66 ? "100" : (volume > 0.33 ? "66" : "33");
var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/Audio_{icon}.xaml");
var resource = new XamlIconResource(uri);
var resource = new IconResource { Type = IconResourceType.Xaml, Uri = uri };
return IconResourceLoader.Load(resource);
}

View file

@ -10,6 +10,7 @@ using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using SafeExamBrowser.Core.Contracts;
using SafeExamBrowser.UserInterface.Contracts.Shell.Events;
using SafeExamBrowser.UserInterface.Shared.Utilities;
@ -33,7 +34,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls
private void LoadIcon()
{
var uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/ShutDown.xaml");
var resource = new XamlIconResource(uri);
var resource = new IconResource { Type = IconResourceType.Xaml, Uri = uri };
Button.Content = IconResourceLoader.Load(resource);
}

View file

@ -12,6 +12,7 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using FontAwesome.WPF;
using SafeExamBrowser.Core.Contracts;
using SafeExamBrowser.I18n.Contracts;
using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork;
using SafeExamBrowser.UserInterface.Contracts.Shell;
@ -142,7 +143,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Controls
{
var icon = signalStrength > 66 ? "100" : (signalStrength > 33 ? "66" : (signalStrength > 0 ? "33" : "0"));
var uri = new Uri($"pack://application:,,,/SafeExamBrowser.UserInterface.Mobile;component/Images/WiFi_{icon}.xaml");
var resource = new XamlIconResource(uri);
var resource = new IconResource { Type = IconResourceType.Xaml, Uri = uri };
return IconResourceLoader.Load(resource);
}

View file

@ -36,11 +36,18 @@ namespace SafeExamBrowser.UserInterface.Mobile
InitializeTaskbar();
}
public void AddApplicationControl(IApplicationControl control)
public void AddApplicationControl(IApplicationControl control, bool atFirstPosition = false)
{
if (control is UIElement uiElement)
{
ApplicationStackPanel.Children.Add(uiElement);
if (atFirstPosition)
{
ApplicationStackPanel.Children.Insert(0, uiElement);
}
else
{
ApplicationStackPanel.Children.Add(uiElement);
}
}
}

View file

@ -51,6 +51,7 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Drawing" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Xaml">
@ -67,7 +68,6 @@
<Compile Include="Utilities\IconResourceLoader.cs" />
<Compile Include="Utilities\VisualExtensions.cs" />
<Compile Include="Utilities\WindowUtility.cs" />
<Compile Include="Utilities\XamlIconResource.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SafeExamBrowser.Core.Contracts\SafeExamBrowser.Core.Contracts.csproj">

View file

@ -7,40 +7,45 @@
*/
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using SafeExamBrowser.Core.Contracts;
using Brushes = System.Windows.Media.Brushes;
using Image = System.Windows.Controls.Image;
namespace SafeExamBrowser.UserInterface.Shared.Utilities
{
public static class IconResourceLoader
{
public static UIElement Load(IIconResource resource)
public static UIElement Load(IconResource resource)
{
try
{
if (resource.IsBitmapResource)
switch (resource.Type)
{
return LoadBitmapResource(resource);
}
else if (resource.IsXamlResource)
{
return LoadXamlResource(resource);
case IconResourceType.Bitmap:
return LoadBitmapResource(resource);
case IconResourceType.Embedded:
return LoadEmbeddedResource(resource);
case IconResourceType.Xaml:
return LoadXamlResource(resource);
default:
throw new NotSupportedException($"Application icon resource of type '{resource.Type}' is not supported!");
}
}
catch (Exception)
{
return NotFoundSymbol();
}
throw new NotSupportedException($"Application icon resource of type '{resource.GetType()}' is not supported!");
}
private static UIElement LoadBitmapResource(IIconResource resource)
private static UIElement LoadBitmapResource(IconResource resource)
{
return new Image
{
@ -48,7 +53,28 @@ namespace SafeExamBrowser.UserInterface.Shared.Utilities
};
}
private static UIElement LoadXamlResource(IIconResource resource)
private static UIElement LoadEmbeddedResource(IconResource resource)
{
using (var stream = new MemoryStream())
{
var bitmap = new BitmapImage();
Icon.ExtractAssociatedIcon(resource.Uri.LocalPath).ToBitmap().Save(stream, ImageFormat.Png);
bitmap.BeginInit();
bitmap.StreamSource = stream;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
bitmap.Freeze();
return new Image
{
Source = bitmap
};
}
}
private static UIElement LoadXamlResource(IconResource resource)
{
using (var stream = Application.GetResourceStream(resource.Uri)?.Stream)
{

View file

@ -1,25 +0,0 @@
/*
* Copyright (c) 2019 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.Core.Contracts;
namespace SafeExamBrowser.UserInterface.Shared.Utilities
{
public class XamlIconResource : IIconResource
{
public Uri Uri { get; private set; }
public bool IsBitmapResource => false;
public bool IsXamlResource => true;
public XamlIconResource(Uri uri)
{
Uri = uri;
}
}
}