У меня есть пользовательский элемент управления WPF, который использует всплывающее окно. Этот элемент управления является плагином и может быть загружен в основной AppDomain или в отдельный AppDomain, и он размещен в форме Winforms, используя ElementHost. Когда плагин загружается в основной домен приложения и открывается всплывающее окно, вкладка между полями всплывающего окна вместо этого перемещает фокус на первый элемент управления родителя всплывающих окон. Когда он загружается в новый домен приложений, поведение вкладки работает так, как ожидается/желательно (циклически переключается по элементам управления во всплывающем окне).
Я прочитал много похожих, но не совсем одинаковых вопросов здесь, в SO и в других местах, но ни одно из предложений не помогло.
Похоже, что сообщение вкладки обрабатывается в AddInHost (что происходит от моего использования FrameworkElementAdapters для перенаправления элемента управления WPF через границы домена в случае отсутствия домена). Моя конечная цель состоит в том, чтобы реализовать это как надстройку Managed Add-in Framework, но я сократил WAY, чтобы упростить воспроизведение.
В случае, если это помогает иметь более полный контекст, у меня есть git-репозиторий упрощенного репро
Что я могу сделать, чтобы сделать это поведение последовательным?
WpfUserControl.xaml
<UserControl x:Class="MyPlugin.WpfUserControl"
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" Background="White">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="28" />
<RowDefinition Height="28" />
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Margin="3" />
<Button x:Name="DropDownButton" Grid.Row="1" Margin="3" HorizontalAlignment="Left" MinWidth="100" Content="Drop Down" Click="DropDownButton_OnClick" />
<Popup Grid.Row="1" x:Name="Popup1" Placement="Right" StaysOpen="True" PlacementTarget="{Binding ElementName=DropDownButton}">
<Border BorderBrush="Black" BorderThickness="1">
<Grid Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Label Content="Username:" Grid.Row="0" Grid.Column="0" Margin="3" />
<TextBox Grid.Row="0" Grid.Column="1" Margin="3" MinWidth="150" />
<Label Content="Password:" Grid.Row="1" Grid.Column="0" Margin="3" />
<TextBox Grid.Row="1" Grid.Column="1" Margin="3" MinWidth="150" />
<Button x:Name="SaveButton" Grid.Row="2" Grid.Column="1" Margin="3" HorizontalAlignment="Right"
Content="Save" Click="SaveButton_OnClick" />
</Grid>
</Border>
</Popup>
<Button x:Name="DoSomethingButton" Grid.Row="2" Margin="3" HorizontalAlignment="Left" MinWidth="100" Content="Do Something" />
</Grid>
</UserControl>
Plugin.cs
public class Plugin : MarshalByRefObject
{
public INativeHandleContract CreateWpfUserControl()
{
return FrameworkElementAdapters.ViewToContractAdapter(new WpfUserControl());
}
}
MainForm.cs (выбранные биты)
private void LoadPlugin(bool loadInSameAppDomain)
{
AppDomain appDomain;
if (loadInSameAppDomain)
{
appDomain = AppDomain.CurrentDomain;
}
else
{
var appDomainName = Guid.NewGuid().ToString();
_appDomain = AppDomain.CreateDomain(appDomainName, AppDomain.CurrentDomain.Evidence, new AppDomainSetup
{
ApplicationName = appDomainName,
ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
PrivateBinPath = AppDomain.CurrentDomain.BaseDirectory
});
appDomain = _appDomain;
}
_plugin = (Plugin)appDomain.CreateInstanceAndUnwrap("MyPlugin", "MyPlugin.Plugin");
}
private void loadPluginButton_Click(object sender, EventArgs e)
{
LoadPlugin(appDomainCheckBox.Checked);
var pluginControl = FrameworkElementAdapters.ContractToViewAdapter(_plugin.CreateWpfUserControl());
elementHost1.Child = pluginControl;
UpdateUi(true);
}