Continued implementation of browser window, i.e. added basic browser functionality like address bar, refresh and navigation.

This commit is contained in:
Damian Büchel 2017-07-31 20:22:53 +02:00
parent 714d300758
commit 5c365f02b0
23 changed files with 391 additions and 70 deletions

View file

@ -13,6 +13,7 @@ using CefSharp;
using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Browser
@ -23,10 +24,12 @@ namespace SafeExamBrowser.Browser
private IList<IApplicationInstance> instances = new List<IApplicationInstance>();
private ISettings settings;
private IUserInterfaceFactory uiFactory;
private IText text;
public BrowserApplicationController(ISettings settings, IUserInterfaceFactory uiFactory)
public BrowserApplicationController(ISettings settings, IText text, IUserInterfaceFactory uiFactory)
{
this.settings = settings;
this.text = text;
this.uiFactory = uiFactory;
}
@ -56,7 +59,7 @@ namespace SafeExamBrowser.Browser
{
foreach (var instance in instances)
{
instance.OnTerminated -= Instance_OnTerminated;
instance.Terminated -= Instance_Terminated;
instance.Window.Close();
}
@ -65,17 +68,13 @@ namespace SafeExamBrowser.Browser
private void CreateNewInstance()
{
var control = new BrowserControl("www.duckduckgo.com");
var window = uiFactory.CreateBrowserWindow(control, settings.Browser);
var instance = new BrowserApplicationInstance("DuckDuckGo");
instance.RegisterWindow(window);
instance.OnTerminated += Instance_OnTerminated;
var instance = new BrowserApplicationInstance(settings.Browser, text, uiFactory, instances.Count == 0);
button.RegisterInstance(instance);
instances.Add(instance);
window.Show();
instance.Terminated += Instance_Terminated;
instance.Window.Show();
}
private void Button_OnClick(Guid? instanceId = null)
@ -90,7 +89,7 @@ namespace SafeExamBrowser.Browser
}
}
private void Instance_OnTerminated(Guid id)
private void Instance_Terminated(Guid id)
{
instances.Remove(instances.FirstOrDefault(i => i.Id == id));
}

View file

@ -8,28 +8,70 @@
using System;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Browser
{
public class BrowserApplicationInstance : IApplicationInstance
{
private IBrowserControl control;
private IBrowserWindow window;
public Guid Id { get; private set; }
public string Name { get; private set; }
public IWindow Window { get; private set; }
public IWindow Window { get { return window; } }
public event TerminationEventHandler OnTerminated;
public event TerminationEventHandler Terminated;
public event NameChangedEventHandler NameChanged;
public BrowserApplicationInstance(string name)
public BrowserApplicationInstance(IBrowserSettings settings, IText text, IUserInterfaceFactory uiFactory, bool isMainInstance)
{
Id = Guid.NewGuid();
Name = name;
control = new BrowserControl(settings, text);
control.AddressChanged += Control_AddressChanged;
control.TitleChanged += Control_TitleChanged;
window = uiFactory.CreateBrowserWindow(control, settings);
window.IsMainWindow = isMainInstance;
window.Closing += () => Terminated?.Invoke(Id);
window.AddressChanged += Window_AddressChanged;
window.ReloadRequested += Window_ReloadRequested;
window.BackwardNavigationRequested += Window_BackwardNavigationRequested;
window.ForwardNavigationRequested += Window_ForwardNavigationRequested;
}
public void RegisterWindow(IWindow window)
private void Control_AddressChanged(string address)
{
Window = window;
Window.OnClose += () => OnTerminated?.Invoke(Id);
window.UpdateAddress(address);
}
private void Control_TitleChanged(string title)
{
window.UpdateTitle(title);
NameChanged?.Invoke(title);
}
private void Window_AddressChanged(string address)
{
control.NavigateTo(address);
}
private void Window_ReloadRequested()
{
control.Reload();
}
private void Window_BackwardNavigationRequested()
{
control.NavigateBackwards();
}
private void Window_ForwardNavigationRequested()
{
control.NavigateForwards();
}
}
}

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2017 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 CefSharp;
using SafeExamBrowser.Contracts.I18n;
using IBrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.IBrowserSettings;
namespace SafeExamBrowser.Browser
{
/// <remarks>
/// See https://cefsharp.github.io/api/57.0.0/html/T_CefSharp_IContextMenuHandler.htm.
/// </remarks>
internal class BrowserContextMenuHandler : IContextMenuHandler
{
private const int DEV_CONSOLE_COMMAND = (int) CefMenuCommand.UserFirst + 1;
private IBrowserSettings settings;
private IText text;
public BrowserContextMenuHandler(IBrowserSettings settings, IText text)
{
this.settings = settings;
this.text = text;
}
public void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model)
{
model.Clear();
if (settings.AllowDeveloperConsole)
{
model.AddItem((CefMenuCommand) DEV_CONSOLE_COMMAND, text.Get(Key.Browser_ShowDeveloperConsole));
}
}
public bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags)
{
if ((int) commandId == DEV_CONSOLE_COMMAND)
{
browser.ShowDevTools();
return true;
}
return false;
}
public void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame)
{
}
public bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback)
{
return false;
}
}
}

View file

@ -6,17 +6,70 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System.Windows.Forms;
using System;
using CefSharp.WinForms;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.UserInterface;
using IBrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.IBrowserSettings;
namespace SafeExamBrowser.Browser
{
class BrowserControl : ChromiumWebBrowser, IBrowserControl
{
public BrowserControl(string url) : base(url)
private AddressChangedHandler addressChanged;
private IBrowserSettings settings;
private TitleChangedHandler titleChanged;
private IText text;
event AddressChangedHandler IBrowserControl.AddressChanged
{
Dock = DockStyle.Fill;
add { addressChanged += value; }
remove { addressChanged -= value; }
}
event TitleChangedHandler IBrowserControl.TitleChanged
{
add { titleChanged += value; }
remove { titleChanged -= value; }
}
public BrowserControl(IBrowserSettings settings, IText text) : base(settings.StartUrl)
{
this.settings = settings;
this.text = text;
Initialize();
}
public void NavigateBackwards()
{
GetBrowser().GoBack();
}
public void NavigateForwards()
{
GetBrowser().GoForward();
}
public void NavigateTo(string address)
{
if (!String.IsNullOrWhiteSpace(address) && Uri.IsWellFormedUriString(address, UriKind.RelativeOrAbsolute))
{
Load(address);
}
}
public void Reload()
{
GetBrowser().Reload();
}
private void Initialize()
{
AddressChanged += (o, args) => addressChanged?.Invoke(args.Address);
TitleChanged += (o, args) => titleChanged?.Invoke(args.Title);
MenuHandler = new BrowserContextMenuHandler(settings, text);
}
}
}

View file

@ -67,6 +67,7 @@
<Compile Include="BrowserApplicationController.cs" />
<Compile Include="BrowserApplicationInfo.cs" />
<Compile Include="BrowserApplicationInstance.cs" />
<Compile Include="BrowserContextMenuHandler.cs" />
<Compile Include="BrowserControl.cs">
<SubType>Component</SubType>
</Compile>

View file

@ -23,24 +23,26 @@ namespace SafeExamBrowser.Configuration.Settings
public bool AllowAddressBar => true;
public bool AllowBackwardNavigation => false;
public bool AllowBackwardNavigation => true;
public bool AllowDebugConsole => true;
public bool AllowDeveloperConsole => true;
public bool AllowForwardNavigation => false;
public bool AllowForwardNavigation => true;
public bool AllowReloading => false;
public bool AllowReloading => true;
public string CachePath
{
get { return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), settings.AppDataFolderName, "Cache"); }
}
public bool FullScreenMode => throw new NotImplementedException();
public bool FullScreenMode => false;
public string LogFile
{
get { return Path.Combine(settings.LogFolderPath, $"{settings.RuntimeIdentifier}_Browser.txt"); }
}
public string StartUrl => "www.duckduckgo.com";
}
}

View file

@ -12,6 +12,7 @@ using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Contracts.Configuration
{
public delegate void TerminationEventHandler(Guid id);
public delegate void NameChangedEventHandler(string name);
public interface IApplicationInstance
{
@ -28,16 +29,16 @@ namespace SafeExamBrowser.Contracts.Configuration
/// <summary>
/// Event fired when the application instance has been terminated.
/// </summary>
event TerminationEventHandler OnTerminated;
event TerminationEventHandler Terminated;
/// <summary>
/// Event fired when the name or (document) title of the application instance has changed.
/// </summary>
event NameChangedEventHandler NameChanged;
/// <summary>
/// The main window of the application instance.
/// </summary>
IWindow Window { get; }
/// <summary>
/// Registers the given window as the main window of the application instance.
/// </summary>
void RegisterWindow(IWindow window);
}
}

View file

@ -21,9 +21,9 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings
bool AllowBackwardNavigation { get; }
/// <summary>
/// Determines whether the user should be allowed to open the debug console of a browser window.
/// Determines whether the user should be allowed to open the developer console of a browser window.
/// </summary>
bool AllowDebugConsole { get; }
bool AllowDeveloperConsole { get; }
/// <summary>
/// Determines whether the user should be allowed to navigate forwards in a browser window.
@ -49,5 +49,10 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings
/// Determines whether the main browser window should be rendered in fullscreen mode, i.e. without window frame.
/// </summary>
bool FullScreenMode { get; }
/// <summary>
/// The start URL with which a new browser window should be loaded.
/// </summary>
string StartUrl { get; }
}
}

View file

@ -13,6 +13,7 @@ namespace SafeExamBrowser.Contracts.I18n
/// </summary>
public enum Key
{
Browser_ShowDeveloperConsole,
MessageBox_ShutdownError,
MessageBox_ShutdownErrorTitle,
MessageBox_SingleInstance,

View file

@ -8,7 +8,39 @@
namespace SafeExamBrowser.Contracts.UserInterface
{
public delegate void AddressChangedHandler(string address);
public delegate void TitleChangedHandler(string title);
public interface IBrowserControl
{
/// <summary>
/// Event fired when the address of the browser control changes.
/// </summary>
event AddressChangedHandler AddressChanged;
/// <summary>
/// Event fired when the current page (and thus the title) of the browser control changes.
/// </summary>
event TitleChangedHandler TitleChanged;
/// <summary>
/// Navigates to the previous page in the browser control history.
/// </summary>
void NavigateBackwards();
/// <summary>
/// Navigates to the next page in the browser control history.
/// </summary>
void NavigateForwards();
/// <summary>
/// Navigates to the specified web address.
/// </summary>
void NavigateTo(string address);
/// <summary>
/// Reloads the current web page.
/// </summary>
void Reload();
}
}

View file

@ -8,7 +8,43 @@
namespace SafeExamBrowser.Contracts.UserInterface
{
public delegate void ActionRequestedHandler();
public interface IBrowserWindow : IWindow
{
/// <summary>
/// Event fired when the user changed the URL.
/// </summary>
event AddressChangedHandler AddressChanged;
/// <summary>
/// Event fired when the user would like to navigate backwards.
/// </summary>
event ActionRequestedHandler BackwardNavigationRequested;
/// <summary>
/// Event fired when the user would like to navigate forwards.
/// </summary>
event ActionRequestedHandler ForwardNavigationRequested;
/// <summary>
/// Event fired when the user would like to reload the current page.
/// </summary>
event ActionRequestedHandler ReloadRequested;
/// <summary>
/// Determines whether this window is the main browser window.
/// </summary>
bool IsMainWindow { get; set; }
/// <summary>
/// Updates the address bar of the browser window to the given value;
/// </summary>
void UpdateAddress(string adress);
/// <summary>
/// Sets the title of the browser window to the given value;
/// </summary>
void UpdateTitle(string title);
}
}

View file

@ -20,7 +20,7 @@ namespace SafeExamBrowser.Contracts.UserInterface
ITaskbarButton CreateApplicationButton(IApplicationInfo info);
/// <summary>
/// Creates a new browser window loaded with the given browser control.
/// Creates a new browser window loaded with the given browser control and settings.
/// </summary>
IBrowserWindow CreateBrowserWindow(IBrowserControl control, IBrowserSettings settings);

View file

@ -8,14 +8,14 @@
namespace SafeExamBrowser.Contracts.UserInterface
{
public delegate void WindowCloseHandler();
public delegate void WindowClosingHandler();
public interface IWindow
{
/// <summary>
/// Event fired when the window is closing.
/// </summary>
event WindowCloseHandler OnClose;
event WindowClosingHandler Closing;
/// <summary>
/// Brings the window to the foreground.

View file

@ -1,24 +1,25 @@
<?xml version="1.0" encoding="utf-8" ?>
<Text>
<MessageBox_ShutdownError>An unexpected error occurred during the shutdown procedure! Please consult the application log for more information...</MessageBox_ShutdownError>
<MessageBox_ShutdownErrorTitle>Shutdown Error</MessageBox_ShutdownErrorTitle>
<MessageBox_StartupError>An unexpected error occurred during the startup procedure! Please consult the application log for more information...</MessageBox_StartupError>
<MessageBox_StartupErrorTitle>Startup Error</MessageBox_StartupErrorTitle>
<Notification_AboutTooltip>About Safe Exam Browser</Notification_AboutTooltip>
<SplashScreen_InitializeBrowser>Initializing browser</SplashScreen_InitializeBrowser>
<SplashScreen_InitializeProcessMonitoring>Initializing process monitoring</SplashScreen_InitializeProcessMonitoring>
<SplashScreen_InitializeTaskbar>Initializing taskbar</SplashScreen_InitializeTaskbar>
<SplashScreen_InitializeWindowMonitoring>Initializing window monitoring</SplashScreen_InitializeWindowMonitoring>
<SplashScreen_InitializeWorkingArea>Initializing working area</SplashScreen_InitializeWorkingArea>
<SplashScreen_RestoreWorkingArea>Restoring working area</SplashScreen_RestoreWorkingArea>
<SplashScreen_ShutdownProcedure>Initiating shutdown procedure</SplashScreen_ShutdownProcedure>
<SplashScreen_StartEventHandling>Starting event handling</SplashScreen_StartEventHandling>
<SplashScreen_StartupProcedure>Initiating startup procedure</SplashScreen_StartupProcedure>
<SplashScreen_StopEventHandling>Stopping event handling</SplashScreen_StopEventHandling>
<SplashScreen_StopProcessMonitoring>Stopping process monitoring</SplashScreen_StopProcessMonitoring>
<SplashScreen_StopWindowMonitoring>Stopping window monitoring</SplashScreen_StopWindowMonitoring>
<SplashScreen_TerminateBrowser>Terminating browser</SplashScreen_TerminateBrowser>
<SplashScreen_WaitExplorerStartup>Waiting for Windows explorer to start up</SplashScreen_WaitExplorerStartup>
<SplashScreen_WaitExplorerTermination>Waiting for Windows explorer to shut down</SplashScreen_WaitExplorerTermination>
<Version>Version</Version>
<Browser_ShowDeveloperConsole>Open Console</Browser_ShowDeveloperConsole>
<MessageBox_ShutdownError>An unexpected error occurred during the shutdown procedure! Please consult the application log for more information...</MessageBox_ShutdownError>
<MessageBox_ShutdownErrorTitle>Shutdown Error</MessageBox_ShutdownErrorTitle>
<MessageBox_StartupError>An unexpected error occurred during the startup procedure! Please consult the application log for more information...</MessageBox_StartupError>
<MessageBox_StartupErrorTitle>Startup Error</MessageBox_StartupErrorTitle>
<Notification_AboutTooltip>About Safe Exam Browser</Notification_AboutTooltip>
<SplashScreen_InitializeBrowser>Initializing browser</SplashScreen_InitializeBrowser>
<SplashScreen_InitializeProcessMonitoring>Initializing process monitoring</SplashScreen_InitializeProcessMonitoring>
<SplashScreen_InitializeTaskbar>Initializing taskbar</SplashScreen_InitializeTaskbar>
<SplashScreen_InitializeWindowMonitoring>Initializing window monitoring</SplashScreen_InitializeWindowMonitoring>
<SplashScreen_InitializeWorkingArea>Initializing working area</SplashScreen_InitializeWorkingArea>
<SplashScreen_RestoreWorkingArea>Restoring working area</SplashScreen_RestoreWorkingArea>
<SplashScreen_ShutdownProcedure>Initiating shutdown procedure</SplashScreen_ShutdownProcedure>
<SplashScreen_StartEventHandling>Starting event handling</SplashScreen_StartEventHandling>
<SplashScreen_StartupProcedure>Initiating startup procedure</SplashScreen_StartupProcedure>
<SplashScreen_StopEventHandling>Stopping event handling</SplashScreen_StopEventHandling>
<SplashScreen_StopProcessMonitoring>Stopping process monitoring</SplashScreen_StopProcessMonitoring>
<SplashScreen_StopWindowMonitoring>Stopping window monitoring</SplashScreen_StopWindowMonitoring>
<SplashScreen_TerminateBrowser>Terminating browser</SplashScreen_TerminateBrowser>
<SplashScreen_WaitExplorerStartup>Waiting for Windows explorer to start up</SplashScreen_WaitExplorerStartup>
<SplashScreen_WaitExplorerTermination>Waiting for Windows explorer to shut down</SplashScreen_WaitExplorerTermination>
<Version>Version</Version>
</Text>

View file

@ -5,7 +5,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface"
mc:Ignorable="d"
Title="BrowserWindow" Height="500" Width="500" WindowState="Maximized">
Title="BrowserWindow" Height="500" Width="500" WindowState="Maximized" Icon=".\Images\Chromium.ico">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />

View file

@ -7,6 +7,7 @@
*/
using System.Windows;
using System.Windows.Controls;
using SafeExamBrowser.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.UserInterface;
@ -14,9 +15,33 @@ namespace SafeExamBrowser.UserInterface
{
public partial class BrowserWindow : Window, IBrowserWindow
{
private bool isMainWindow;
private IBrowserSettings settings;
public WindowClosingHandler closing;
public event WindowCloseHandler OnClose;
public bool IsMainWindow
{
get
{
return isMainWindow;
}
set
{
isMainWindow = value;
ApplySettings();
}
}
public event AddressChangedHandler AddressChanged;
public event ActionRequestedHandler BackwardNavigationRequested;
public event ActionRequestedHandler ForwardNavigationRequested;
public event ActionRequestedHandler ReloadRequested;
event WindowClosingHandler IWindow.Closing
{
add { closing += value; }
remove { closing -= value; }
}
public BrowserWindow(IBrowserControl browserControl, IBrowserSettings settings)
{
@ -36,6 +61,26 @@ namespace SafeExamBrowser.UserInterface
Activate();
}
public void UpdateAddress(string url)
{
Dispatcher.Invoke(() =>
{
UrlTextBox.TextChanged -= UrlTextBox_TextChanged;
UrlTextBox.Text = url;
UrlTextBox.TextChanged += UrlTextBox_TextChanged;
});
}
public void UpdateTitle(string title)
{
Dispatcher.Invoke(() => Title = title);
}
private void UrlTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
AddressChanged?.Invoke(UrlTextBox.Text);
}
private void InitializeBrowserWindow(IBrowserControl browserControl)
{
if (browserControl is System.Windows.Forms.Control)
@ -43,8 +88,26 @@ namespace SafeExamBrowser.UserInterface
BrowserControlHost.Child = browserControl as System.Windows.Forms.Control;
}
Closing += (o, args) => closing?.Invoke();
UrlTextBox.TextChanged += UrlTextBox_TextChanged;
ReloadButton.Click += (o, args) => ReloadRequested?.Invoke();
BackButton.Click += (o, args) => BackwardNavigationRequested?.Invoke();
ForwardButton.Click += (o, args) => ForwardNavigationRequested?.Invoke();
ApplySettings();
}
private void ApplySettings()
{
if (IsMainWindow && settings.FullScreenMode)
{
MaxHeight = SystemParameters.WorkArea.Height;
ResizeMode = ResizeMode.NoResize;
WindowState = WindowState.Maximized;
WindowStyle = WindowStyle.None;
}
UrlTextBox.IsEnabled = settings.AllowAddressBar;
UrlTextBox.Visibility = settings.AllowAddressBar ? Visibility.Visible : Visibility.Collapsed;
ReloadButton.IsEnabled = settings.AllowReloading;
ReloadButton.Visibility = settings.AllowReloading ? Visibility.Visible : Visibility.Collapsed;
@ -54,8 +117,6 @@ namespace SafeExamBrowser.UserInterface
ForwardButton.IsEnabled = settings.AllowForwardNavigation;
ForwardButton.Visibility = settings.AllowForwardNavigation ? Visibility.Visible : Visibility.Collapsed;
Closing += (o, args) => OnClose?.Invoke();
}
}
}

View file

@ -37,7 +37,7 @@
</Button.Template>
</Button>
<Grid Panel.ZIndex="10">
<Rectangle x:Name="ActiveBar" Height="3" Width="40" VerticalAlignment="Bottom" Fill="LightSteelBlue" Visibility="Collapsed" />
<Rectangle x:Name="ActiveBar" Height="2" Width="40" VerticalAlignment="Bottom" Fill="LightSteelBlue" Visibility="Collapsed" />
</Grid>
</Grid>
</UserControl>

View file

@ -11,6 +11,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.UserInterface;
using SafeExamBrowser.UserInterface.Utilities;
@ -37,7 +38,7 @@ namespace SafeExamBrowser.UserInterface.Controls
var instanceButton = new ApplicationInstanceButton(instance, info);
instanceButton.Click += (id) => OnClick?.Invoke(id);
instance.OnTerminated += (id) => Instance_OnTerminated(id, instanceButton);
instance.Terminated += (id) => Instance_OnTerminated(id, instanceButton);
instances.Add(instance);
InstanceStackPanel.Children.Add(instanceButton);
@ -49,13 +50,24 @@ namespace SafeExamBrowser.UserInterface.Controls
{
Button.ToolTip = info.Tooltip;
Button.Content = IconResourceLoader.Load(info.IconResource);
Button.MouseEnter += (o, args) => InstancePopup.IsOpen = instances.Count > 1;
Button.MouseLeave += (o, args) => InstancePopup.IsOpen &= InstancePopup.IsMouseOver || ActiveBar.IsMouseOver;
ActiveBar.MouseLeave += (o, args) => InstancePopup.IsOpen &= InstancePopup.IsMouseOver || Button.IsMouseOver;
InstancePopup.MouseLeave += (o, args) => InstancePopup.IsOpen = false;
InstancePopup.Opened += (o, args) => ActiveBar.Width = Double.NaN;
InstancePopup.Closed += (o, args) => ActiveBar.Width = 40;
InstancePopup.Opened += (o, args) =>
{
ActiveBar.Width = Double.NaN;
Background = (Brush) new BrushConverter().ConvertFrom("#2AFFFFFF");
};
InstancePopup.Closed += (o, args) =>
{
ActiveBar.Width = 40;
Background = (Brush) new BrushConverter().ConvertFrom("#00000000");
};
InstanceStackPanel.SizeChanged += (o, args) =>
{
if (instances.Count > 9)

View file

@ -10,7 +10,7 @@
<Button.Template>
<ControlTemplate TargetType="Button">
<Border x:Name="ButtonContent" Background="#00000000" Padding="5">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" ContentSource="Content" />
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Left" ContentSource="Content" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">

View file

@ -36,7 +36,16 @@ namespace SafeExamBrowser.UserInterface.Controls
{
Icon.Content = IconResourceLoader.Load(info.IconResource);
Text.Text = instance.Name;
Button.ToolTip = $"{instance.Name} - {info.Name}";
Button.ToolTip = instance.Name;
instance.NameChanged += (name) =>
{
Dispatcher.Invoke(() =>
{
Text.Text = name;
Button.ToolTip = name;
});
};
}
private void Button_Click(object sender, RoutedEventArgs e)

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

View file

@ -163,5 +163,8 @@
<ItemGroup>
<Resource Include="Images\SafeExamBrowser.ico" />
</ItemGroup>
<ItemGroup>
<Resource Include="Images\Chromium.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View file

@ -63,10 +63,11 @@ namespace SafeExamBrowser
text = new Text(textResource);
aboutInfo = new AboutNotificationInfo(text);
browserController = new BrowserApplicationController(settings, uiFactory);
browserController = new BrowserApplicationController(settings, text, uiFactory);
processMonitor = new ProcessMonitor(new ModuleLogger(logger, typeof(ProcessMonitor)), nativeMethods);
windowMonitor = new WindowMonitor(new ModuleLogger(logger, typeof(WindowMonitor)), nativeMethods);
workingArea = new WorkingArea(new ModuleLogger(logger, typeof(WorkingArea)), nativeMethods);
eventController = new EventController(new ModuleLogger(logger, typeof(EventController)), processMonitor, Taskbar, windowMonitor, workingArea);
ShutdownController = new ShutdownController(logger, settings, text, uiFactory);
StartupController = new StartupController(logger, settings, text, uiFactory);