Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
<PackageVersion Include="Grpc.Net.Client" Version="2.62.0" />
<PackageVersion Include="Grpc.Tools" Version="2.62.0" />
<PackageVersion Include="Grpc" Version="2.46.6" />
<PackageVersion Include="Infragistics.WPF.DockManager.Trial" Version="23.2.94" />
<PackageVersion Include="Infragistics.WPF.Ribbon.Trial" Version="23.2.94" />
<PackageVersion Include="Infragistics.WPF.Trial" Version="23.2.94" />
<PackageVersion Include="Microsoft.CodeAnalysis.Common" Version="4.9.2" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" />
Expand Down
15 changes: 12 additions & 3 deletions src/shell/dotnet/Shell/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,15 @@ public TWindow CreateWindow<TWindow>(params object[] parameters) where TWindow :
return CreateInstance<TWindow>(parameters);
}

public WebContent CreateWebContent(params object[] parameters)
{
Dispatcher.VerifyAccess();
var webContent = CreateInstance<WebContent>(parameters);
_shellWindow!.AddDockableFloatingContent(webContent);

return webContent;
}

public T? GetService<T>()
{
return Host.Services.GetService<T>();
Expand Down Expand Up @@ -96,6 +105,7 @@ protected override void OnExit(ExitEventArgs e)
private IHost? _host;

private ILogger _logger = NullLogger<App>.Instance;
private MainWindow? _shellWindow;

// TODO: Assign a unique token for each module
internal readonly string MessageRouterAccessToken = Guid.NewGuid().ToString("N");
Expand Down Expand Up @@ -234,12 +244,11 @@ private void OnAsyncStartupCompleted(StartupEventArgs e)
{
new(WebWindowOptions.ParameterName, JsonSerializer.Serialize(webWindowOptions))
}));

return;
}

ShutdownMode = ShutdownMode.OnMainWindowClose;
CreateWindow<MainWindow>().Show();
_shellWindow = CreateWindow<MainWindow>();
_shellWindow.Show();
}

private async Task StopAsync()
Expand Down
35 changes: 23 additions & 12 deletions src/shell/dotnet/Shell/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,23 @@ See the License for the specific language governing permissions and limitations
********************************************************************************************************
-->
<RibbonWindow x:Class="MorganStanley.ComposeUI.Shell.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MorganStanley.ComposeUI.Shell"
mc:Ignorable="d"
Title="ComposeUI Shell"
Height="450"
Width="600"
Background="{DynamicResource {x:Static SystemColors.AppWorkspaceBrushKey}}"
WindowStartupLocation="CenterScreen"
Initialized="RibbonWindow_Initialized">
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MorganStanley.ComposeUI.Shell"
xmlns:igDock="http://infragistics.com/DockManager"
mc:Ignorable="d"
Title="ComposeUI Shell"
Height="450"
Width="600"
Background="{DynamicResource {x:Static SystemColors.AppWorkspaceBrushKey}}"
WindowStartupLocation="CenterScreen"
Initialized="RibbonWindow_Initialized">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Ribbon x:Name="Ribbon" SelectedIndex="0" Height="Auto" >
<!-- Hide the Application Menu -->
Expand All @@ -48,5 +50,14 @@ See the License for the specific language governing permissions and limitations
</RibbonGroup>
</RibbonTab>
</Ribbon>

<Grid Grid.Row="1"
x:Name="layoutRoot">
<igDock:XamDockManager x:Name="_xamDockManager"
AllowMaximizeFloatingWindows="True"
AllowMinimizeFloatingWindows="True"
ShowFloatingWindowsInTaskbar="True"
LayoutMode="FillContainer"/>
</Grid>
</Grid>
</RibbonWindow>
14 changes: 13 additions & 1 deletion src/shell/dotnet/Shell/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
using System.Windows;
using System.Windows.Controls.Ribbon;
using CommunityToolkit.Mvvm.ComponentModel;
using Infragistics.Windows.DockManager;
using MorganStanley.ComposeUI.ModuleLoader;
using MorganStanley.ComposeUI.Shell.ImageSource;
using MorganStanley.ComposeUI.Shell.Utilities;
using IconUtilities = MorganStanley.ComposeUI.Shell.Utilities.IconUtilities;

namespace MorganStanley.ComposeUI.Shell;

Expand Down Expand Up @@ -61,6 +61,18 @@ private async void RibbonWindow_Initialized(object sender, System.EventArgs e)
};
}

public void AddDockableFloatingContent(WebContent webContent)
{
var splitPane = new SplitPane();
var contentPane = new WebContentPane(webContent, _moduleLoader);
splitPane.Panes.Add(contentPane);

XamDockManager.SetInitialLocation(splitPane, InitialPaneLocation.DockedLeft);
XamDockManager.SetFloatingSize(splitPane, new(webContent.Width, webContent.Height));

_xamDockManager.Panes.Add(splitPane);
}

internal MainWindowViewModel ViewModel
{
get => (MainWindowViewModel) DataContext;
Expand Down
4 changes: 1 addition & 3 deletions src/shell/dotnet/Shell/Modules/ModuleService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,13 @@ private async void OnWebModuleStarted(LifetimeEvent.Started e)
await _application.Dispatcher.InvokeAsync(
() =>
{
var window = _application.CreateWindow<WebWindow>(
var window = _application.CreateWebContent(
e.Instance,
webWindowOptions ?? new WebWindowOptions
{
Url = properties.Url.ToString(),
IconUrl = properties.IconUrl?.ToString()
});

window.Show();
});
}
catch (Exception ex)
Expand Down
7 changes: 5 additions & 2 deletions src/shell/dotnet/Shell/Shell.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

<ItemGroup>
<None Remove="MainWindow.xaml" />
<None Remove="WebWindow.xaml" />
<None Remove="WebContent.xaml" />
</ItemGroup>

<ItemGroup>
Expand All @@ -22,10 +22,13 @@
<PackageReference Include="Microsoft.Extensions.Http" />
<PackageReference Include="Microsoft.Web.WebView2" />
<PackageReference Include="System.Drawing.Common" />
<PackageReference Include="Infragistics.WPF.DockManager.Trial" />
<PackageReference Include="Infragistics.WPF.Trial" />
<PackageReference Include="Infragistics.WPF.Ribbon.Trial" />
</ItemGroup>

<ItemGroup>
<Page Include="WebWindow.xaml">
<Page Include="WebContent.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="MainWindow.xaml" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
<Window x:Class="MorganStanley.ComposeUI.Shell.WebWindow"
<ContentPresenter x:Class="MorganStanley.ComposeUI.Shell.WebContent"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:wv2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
xmlns:local="clr-namespace:MorganStanley.ComposeUI.Shell"
mc:Ignorable="d"
Title="Compose" Height="450" Width="800"
mc:Ignorable="d" Height="450" Width="800"
>
<Grid>
<DockPanel>
<wv2:WebView2 Name = "WebView" Source = ""/>
</DockPanel>
</Grid>
</Window>
<ContentPresenter.Content>
<Grid>
<DockPanel>
<wv2:WebView2 Name = "WebView" Source = ""/>
</DockPanel>
</Grid>
</ContentPresenter.Content>
</ContentPresenter>
Original file line number Diff line number Diff line change
Expand Up @@ -14,40 +14,38 @@

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Web.WebView2.Core;
using MorganStanley.ComposeUI.ModuleLoader;
using MorganStanley.ComposeUI.Shell.ImageSource;
using MorganStanley.ComposeUI.Shell.Utilities;

namespace MorganStanley.ComposeUI.Shell;

/// <summary>
/// Interaction logic for WebWindow.xaml
/// Interaction logic for WebContent.xaml
/// </summary>

public partial class WebWindow : Window
public partial class WebContent : ContentPresenter, IDisposable
{
public WebWindow(
public WebContent(
WebWindowOptions options,
IModuleLoader moduleLoader,
IModuleInstance? moduleInstance = null,
ILogger<WebWindow>? logger = null,
ILogger<WebContent>? logger = null,
IImageSourcePolicy? imageSourcePolicy = null)
{
_moduleLoader = moduleLoader;
_moduleInstance = moduleInstance;
_iconProvider = new ImageSourceProvider(imageSourcePolicy ?? new DefaultImageSourcePolicy());
_options = options;
_logger = logger ?? NullLogger<WebWindow>.Instance;
_logger = logger ?? NullLogger<WebContent>.Instance;
InitializeComponent();

// TODO: When no title is set from options, we should show the HTML document's title instead
Expand All @@ -69,65 +67,33 @@ public WebWindow(
(LifetimeEvent e) =>
{
_lifetimeEvent = e.EventType;
Close();
})));
}

_ = InitializeAsync();
}

public IModuleInstance? ModuleInstance => _moduleInstance;
public LifetimeEventType LifetimeEvent => _lifetimeEvent;

protected override void OnClosing(CancelEventArgs args)
{
// TODO: Send the closing event to the page, allow it to cancel

if (_moduleInstance == null)
return;

switch (_lifetimeEvent)
{
case LifetimeEventType.Stopped:
return;

case LifetimeEventType.Stopping:
args.Cancel = true;
Hide();
return;

default:
args.Cancel = true;
Hide();
Task.Run(() => _moduleLoader.StopModule(new StopRequest(_moduleInstance.InstanceId)));
return;
}
}

protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
RemoveLogicalChild(WebView);
WebView.Dispose();
public event EventHandler CloseRequested;

var disposables = _disposables.AsEnumerable().Reverse().ToArray();
_disposables.Clear();
public string Title { get; private set; }

foreach (var disposable in disposables)
{
disposable.Dispose();
}
}
public System.Windows.Media.ImageSource? Icon { get; private set; }

private readonly IModuleLoader _moduleLoader;
private readonly IModuleInstance? _moduleInstance;
private readonly WebWindowOptions _options;
private readonly ILogger<WebWindow> _logger;
private readonly ILogger<WebContent> _logger;
private readonly ImageSourceProvider _iconProvider;
private bool _scriptsInjected;
private LifetimeEventType _lifetimeEvent = LifetimeEventType.Started;
private readonly TaskCompletionSource _scriptInjectionCompleted = new();
private readonly List<IDisposable> _disposables = new();

public WebWindowOptions Options => _options;

private async Task InitializeAsync()
{
await WebView.EnsureCoreWebView2Async();
Expand Down Expand Up @@ -162,7 +128,7 @@ private Task InitializeCoreWebView2(CoreWebView2 coreWebView)
{
coreWebView.NewWindowRequested += (sender, args) => OnNewWindowRequested(args);
coreWebView.WindowCloseRequested += (sender, args) => OnWindowCloseRequested(args);
coreWebView.NavigationStarting += (sender, args) => OnNavigationStarting(args);
coreWebView.NavigationStarting += (sender, args) => OnNavigationStarting(args);
coreWebView.DocumentTitleChanged += (sender, args) => OnDocumentTitleChanged(args);

return Task.CompletedTask;
Expand Down Expand Up @@ -244,14 +210,27 @@ private async void OnNewWindowRequested(CoreWebView2NewWindowRequestedEventArgs
constructorArgs.Add(_moduleInstance);
}

var window = App.Current.CreateWindow<WebWindow>(constructorArgs.ToArray());
window.Show();
var window = App.Current.CreateWebContent(constructorArgs.ToArray());
await window.WebView.EnsureCoreWebView2Async();
e.NewWindow = window.WebView.CoreWebView2;
}

private void OnWindowCloseRequested(object args)
{
Close();
CloseRequested?.Invoke(this, EventArgs.Empty);
}

public void Dispose()
{
RemoveLogicalChild(WebView);
WebView.Dispose();

var disposables = _disposables.AsEnumerable().Reverse().ToArray();
_disposables.Clear();

foreach (var disposable in disposables)
{
disposable.Dispose();
}
}
}
Loading