c# - Navegación de pestañas rotas en la ventana emergente con control de usuario de WPF alojado dentro de Winforms en el dominio de aplicación predeterminado
appdomain maf (1)
Tengo un control de usuario de WPF que utiliza una ventana emergente. Este control es un complemento y se puede cargar en el dominio de aplicación principal o en un dominio de aplicación separado, y se aloja en un formulario Winforms utilizando ElementHost. Cuando el complemento se carga en el dominio de aplicación principal, y se abre la ventana emergente, la tabulación entre los campos de la ventana emergente en su lugar se centra en el primer control del padre de la ventana emergente. Cuando se carga en un nuevo dominio de aplicación, el comportamiento de la pestaña funciona según lo esperado / deseado (pasa por los controles en la ventana emergente).
He leído muchas preguntas similares, pero no exactamente iguales aquí en SO y en otros lugares, pero ninguna de las sugerencias me ha ayudado.
Parece que el mensaje de la pestaña se maneja en AddInHost (que proviene de mi uso de FrameworkElementAdapters para calcular el control de WPF a través de los límites del dominio en un caso fuera del dominio). Mi objetivo final es implementar esto como un complemento del Marco Administrado de Complemento, pero lo he reducido para simplificar la reproducción.
En caso de que ayude a tener un contexto más completo, tengo un git repo del repro simplificado
¿Qué puedo hacer para que este comportamiento sea consistente?
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 (bits seleccionados)
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);
}
Mi algo educado, aunque de ninguna manera autoritario, supongo que el problema es que WinForms y WPF esperan tener acceso exclusivo a la bomba de mensajes de la ventana superior. La ejecución de cada uno en su propio dominio de aplicación le da a cada control exclusivo una ventana principal y su bomba de mensajes.