WPF用户控件托管在默认AppDomain的Winforms中的弹出窗口中的选项卡导航损坏 [英] Broken tab navigation in popup with WPF user control hosted inside Winforms in default AppDomain

查看:138
本文介绍了WPF用户控件托管在默认AppDomain的Winforms中的弹出窗口中的选项卡导航损坏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用弹出窗口的WPF用户控件.此控件是一个插件,可以加载到主AppDomain中或单独的AppDomain中,并使用ElementHost以Winforms形式托管.当插件加载到主AppDomain中并打开弹出窗口时,在弹出窗口的字段之间进行制表键会将焦点移至弹出窗口父级的第一个控件.当将其加载到新的AppDomain中时,选项卡行为将按预期/期望的方式工作(在弹出窗口中的控件之间循环).

I have a WPF user control that uses a Popup. This control is a plugin and can be loaded in the main AppDomain or in a separate AppDomain, and it is hosted in a Winforms form using ElementHost. When the plugin is loaded in the main AppDomain, and the popup is opened, tabbing between the fields of the popup instead moves focus to the first control of the popup windows parent. When it is loaded in a new AppDomain, the tab behavior works as expected/desired (it cycles through the controls in the popup window).

我已经阅读了关于SO和其他地方的许多类似但不完全相同的问题,但是没有任何建议可以提供帮助.

I have read through many similar, but not quite the same, questions here on SO and elsewhere, but none of the suggestions have helped.

该选项卡消息似乎在AddInHost中得到处理(这是由于我使用FrameworkElementAdapters在域外情况下跨域边界封送WPF控件).我的最终目标是将其实现为托管加载项框架加载项,但我已简化了该过程以简化复制过程.

It appears that the tab message is getting handled in the AddInHost (which comes from my use of FrameworkElementAdapters to marshal the WPF control across domain boundaries in out-of-domain case). My ultimate goal is to implement this as a Managed Add-in Framework addin, but I have pared that WAY down to simplify the repro.

万一有一个更完整的上下文,我有简化复制的git repo

In case it helps to have a more complete context, I have a git repo of the simplified repro

我该怎么做才能使这种行为保持一致?

What can I do to make this behavior consistent?

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);
}

推荐答案

我受过一定程度的教育,尽管绝不是权威,但猜测是问题在于WinForms和WPF希望独占访问顶部窗口的消息泵.在自己的AppDomain中运行每个窗口,可以分别控制父窗口及其消息泵.

My somewhat educated, though by no means authoritative, guess is that the issue is that WinForms and WPF expect to have exclusive access to the top window's message pump. Running each in its own AppDomain gives each exclusive control of a parent window and its message pump.

这篇关于WPF用户控件托管在默认AppDomain的Winforms中的弹出窗口中的选项卡导航损坏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆