fix(sidebar): wrap ElementHost in WinForms UserControl + cast Explorer.Close event

Two VSTO-only build errors:

1. CustomTaskPanes.Add() requires a System.Windows.Forms.UserControl.
   ElementHost derives from Control, not UserControl. Wrap it inside a
   thin UserControl so the COM adapter is happy.

2. Outlook.Explorer exposes BOTH a Close() method and a Close event with
   the same name; the C# compiler resolves "explorer.Close += handler"
   to the method group. Cast through ExplorerEvents_10_Event to bind
   the event explicitly.

Core/UI build clean. Host project still requires the VSTO build targets
to compile.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
PointStar
2026-05-11 16:00:18 +03:00
parent fa3562114d
commit 3bedb2cb06
+15 -3
View File
@@ -89,13 +89,18 @@ namespace OutlookAddin.Services
};
view.DataContext = vm;
// CustomTaskPanes.Add requires a System.Windows.Forms.UserControl,
// so we host the WPF UserControl inside ElementHost which itself
// lives inside a thin WinForms UserControl wrapper.
var element = new ElementHost
{
Child = view,
Dock = System.Windows.Forms.DockStyle.Fill
};
var hostControl = new System.Windows.Forms.UserControl();
hostControl.Controls.Add(element);
var pane = _taskPanes.Add(element, PaneTitle, explorer);
var pane = _taskPanes.Add(hostControl, PaneTitle, explorer);
pane.DockPosition = Office.MsoCTPDockPosition.msoCTPDockPositionRight;
pane.Width = DefaultWidth;
pane.Visible = true;
@@ -109,9 +114,12 @@ namespace OutlookAddin.Services
};
vm.OpenInBrowserRequested += (s, url) => TryOpenInBrowser(url);
explorer.Close += () => DetachExplorer(key);
// Outlook.Explorer exposes BOTH a Close() method and a Close event
// on the same name; cast through the events interface to bind the
// event handler.
((Outlook.ExplorerEvents_10_Event)explorer).Close += () => DetachExplorer(key);
_bindings[key] = new ExplorerBinding(pane, element, vm, handler, explorer);
_bindings[key] = new ExplorerBinding(pane, hostControl, element, vm, handler, explorer);
// Kick a first lookup based on whatever is selected when the pane opens.
handler.TriggerNow();
@@ -170,6 +178,7 @@ namespace OutlookAddin.Services
private sealed class ExplorerBinding : IDisposable
{
private readonly CustomTaskPane _pane;
private readonly System.Windows.Forms.UserControl _hostControl;
private readonly ElementHost _element;
private readonly ExplorerSelectionHandler _handler;
private readonly Outlook.Explorer _explorer;
@@ -178,12 +187,14 @@ namespace OutlookAddin.Services
public ExplorerBinding(
CustomTaskPane pane,
System.Windows.Forms.UserControl hostControl,
ElementHost element,
ReadingPaneViewModel viewModel,
ExplorerSelectionHandler handler,
Outlook.Explorer explorer)
{
_pane = pane;
_hostControl = hostControl;
_element = element;
ViewModel = viewModel;
_handler = handler;
@@ -195,6 +206,7 @@ namespace OutlookAddin.Services
try { _handler.Dispose(); } catch { /* ignore */ }
try { _pane.Visible = false; } catch { /* ignore */ }
try { _element.Dispose(); } catch { /* ignore */ }
try { _hostControl.Dispose(); } catch { /* ignore */ }
}
}
}