Just an FYI, if anyone else was looking to solve this problem w/o the use of ElementHost:
I figured this solution with extended reference to the MyAddInWithWPF blog post from a good bit of time ago. I am currently attempting to get this to work as shellview for a Caliburn.Micro development to little success.
With a basic XAML Window:
<Window x:Class="MyAddIn.Views.CalendarDockedWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:MyAddIn" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"> <Grid MaxWidth="500" MaxHeight="300"> <Button Content="Button" Margin="122,198,10,10"/> <CheckBox Content="CheckBox" Margin="10,183,129,0" VerticalAlignment="Top"/> <Calendar Margin="10,10,10,52"/> </Grid> </Window>
And a related Code-Behind:
public partial class CalendarDockedWindow : Window, IDockableWindow { #region /*-------------------- Properties & Fields -------------------------------*/ private readonly string _internalName; private WindowInteropHelper _helper; public string InternalName => _internalName; public WindowInteropHelper Helper => _helper ?? (_helper = new WindowInteropHelper(this)); public IntPtr HWND { get { Helper.EnsureHandle(); return Helper.Handle; } } #endregion private CalendarDockedWindow() { InitializeComponent(); } public CalendarDockedWindow(Inventor.Application app, string clientID, string internalName, string title) { _internalName = internalName; InitializeComponent(); Inventor.UserInterfaceManager _interfaceManager = app.UserInterfaceManager; var dockableWindow = _interfaceManager.DockableWindows.Add(clientID, internalName, title); dockableWindow.AddChild(HWND); WindowStyle = WindowStyle.None; dockableWindow.DisabledDockingStates = (DockingStateEnum.kDockTop & DockingStateEnum.kDockLeft); dockableWindow.Caption = title; dockableWindow.ShowTitleBar = true; Visibility = Visibility.Visible; if (dockableWindow.IsCustomized) return; dockableWindow.Visible = false; dockableWindow.DockingState = Inventor.DockingStateEnum.kFloat; dockableWindow.Move(25, 25, dockableWindow.Height, dockableWindow.Width); } }
//Simply Interface to ensure
public interface IDockableWindow
{
IntPtr HWND { get; }
string InternalName { get; }
WindowInteropHelper Helper { get; }
}
[Note that Window is the Magic Ingredient] As with a Window object I can get the HWND and assign it as a child to the Dockable Window, this code-behind is heavy and a lot of the work should be done elsewhere, but as a proof of concept it is clear.
I can now create the object with a simple call and collect the window reference in a list to use elsewhere if I need to restrict access or remove based on environment:
private IDockableWindow calendarDockedWindow; private List< IDockableWindow > dockedWindows = new List< IDockableWindow >(); private void GenerateDockableWindows() { calendarDockedWindow = new CalendarDockedWindow( _inventorApplication , _addInCLSIDString , "MyAddIn:DockedCalendar" , "Calendar" ); dockedWindows.Add( calendarDockedWindow ); }
Thanks @Anonymous I'm sure this will come in handy in future!
An additional note, as it was bugging me. I had a few different test windows as proof of concept and some of them the child/hosted WPF Window control was not fully realized, i.e. the control was not maximized in the host panel, or the control's edges were still visible. I tried the form with element host, which worked well in a simple context, but had to resort to using a custom IOTextBox [other source] in order to support actual text entry. The custom control for text entry was a bother, as the WPF hosted Window control handled text entry just fine. So that being said, I found the magic settings for the DockableWindow.AddChild() WPF Host Window for use.
The following snippet of code has the design settings for the hosted/child XAML Window Control in a dockable window: [not panel as it is not an activeX device, another time]
<Window x:Class="AddIn.Shell.Views.ShellPanelView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="600" ResizeMode="NoResize" WindowStyle="None" Visibility="Visible" SizeToContent="Manual" WindowState="Maximized">
<Grid>
</Grid>
</Window>
The key values were:
ResizeMode="NoResize" WindowStyle="None" Visibility="Visible" SizeToContent="Manual" WindowState="Maximized"
That being said, have fun making your own qualified panels. This snippet has been tested up to 2017.. if anything changes I will lookback. Currently, it is working well with a MvVM framework.
Best of Luck.
Can't find what you're looking for? Ask the community or share your knowledge.