20

既存の Windows フォーム/MFC アプリケーション エンジン (Rhino 3D) 内で使用される WPF の UI コントロールを開発しています。

アプリケーション エンジンは、基本的にエンジン インターフェイスにドッキングできる子ウィンドウ内に Windows フォーム コントロールを配置できる「ドックバー」を作成する機能を公開します。

Dockbar に追加された ElementHost コントロール内に単純な WPF TextBox を配置しようとしています。これは一見すると正常に動作するように見えます。しかし、TextBox に入力しようとした後、特定のシーケンスのみが実際に TextBox に表示されます。DELETEBACKSPACECOPYPASTE、およびSELECTING TEXTが機能します。A ~ Z、1 ~ 9 などを入力すると、これらのキーは表示されません。

私はネットを調べて聞いたことがありますElementHost.EnableModelessKeyboardInterop()が、これはフォームから作成されている WPF Windows にのみ適用されます。私は WPF UserControls を作成し、ElementHost コントロールでそれらをホストしているだけです。

Dispatcher.Run() について話している投稿を見ましたが、ある程度は機能しますが、フォームの残りの部分が壊れています。

System.Windows.Threading.Dispatcher.Run();

PreviewKeyUp 、PreviewKeyDownKeyUp、およびKeyDownイベントはすべて TextBox で発生しますが、残念ながら TextBox にテキストは表示されません。

Windows メッセージについてはよくわかりませんが、WinSpector を使用して、TextBox から WM_GETTEXT メッセージが来ていないことに気付きました (そうであるべきかどうかはわかりません)。

また、新しい Windows フォーム プロジェクトを作成し、そこで同じことを行ったところ正常に動作したため、Rhino 3D エンジン内でウィンドウを作成してドッキングする方法に問題があるはずです。

動作しないサンプルコードは次のとおりです。

ElementHost el = new ElementHost();
System.Windows.Controls.TextBox t = new System.Windows.Controls.TextBox();
t.Width = 100;
t.Text = "TEST";
el.Child = t;
panel1.Controls.Add(el);
4

4 に答える 4

23

2日間頭を悩ませた後、ようやくそれを理解しました...

MFC ダイアログ ウィンドウがWM_CHARメッセージを受け取り、コントロールが入力を処理できないようにしていました。したがって、これを防ぐために、HwndSource をフックし、WM_GETDLGCODEメッセージを受信するたびに、受け入れる入力の種類で応答し、イベントを処理済みとしてマークします。

すべてのテキストボックスを修正する必要がないように、独自の TextBox を作成しました (以下を参照)。

    /// <summary>
    /// Interop Enabled TextBox : This TextBox will properly handle WM_GETDLGCODE Messages allowing Key Input
    /// </summary>
    class IOTextBox : TextBox
    {
        private const UInt32 DLGC_WANTARROWS = 0x0001;
        private const UInt32 DLGC_WANTTAB = 0x0002;
        private const UInt32 DLGC_WANTALLKEYS = 0x0004;
        private const UInt32 DLGC_HASSETSEL = 0x0008;
        private const UInt32 DLGC_WANTCHARS = 0x0080;
        private const UInt32 WM_GETDLGCODE = 0x0087;

        public IOTextBox() : base()
        {
            Loaded += delegate
                          {
                              HwndSource s = HwndSource.FromVisual(this) as HwndSource;
                              if (s != null)
                                  s.AddHook(new HwndSourceHook(ChildHwndSourceHook));
                          };
        }

        IntPtr ChildHwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if (msg == WM_GETDLGCODE)
            {
                handled = true;
                return new IntPtr(DLGC_WANTCHARS | DLGC_WANTARROWS | DLGC_HASSETSEL);
            }
            return IntPtr.Zero;
        }
    }
于 2009-05-07T19:58:29.370 に答える
12

これとまったく同じことについての私自身の質問をチェックしてください。結局のところ、必要なのは次のようなものだけです。

Window window1 = new Window();
ElementHost.EnableModelessKeyboardInterop(window1);
window1.Show();

WPFテキストボックスが「ちょっと」読み取り専用なのはなぜですか?

于 2009-05-08T13:30:49.050 に答える
7

派生 TextBox を作成する必要はありません。IOTextBox のコードは、テキスト ボックスをホストする UserControl で使用できます。VS2010 パッケージで使用されるカスタム オプション ページに使用される WPF コントロールで正常にテストしました。

于 2012-03-19T15:16:54.927 に答える
7

wxWidgets 親ウィンドウと埋め込まれた WPF TextBox コントロールにも同様の問題があります。ChildHwndSourceHook をアタッチすると、キーボード入力を受け取れないという問題は解決しますが、スペース文字が重複してしまうことがありました。WM_KEYDOWN メッセージはスペース文字を確実に処理しているように見えますが、一部のスペースに対して重複した WM_CHAR メッセージも受信されます。これを解決するために、ChildHwndSourceHook 関数の本体に次の句を追加しました。これは、単に WM_CHAR スペース文字を無視します。

        const UInt32 WM_CHAR = 0x0102;

        if (msg == WM_CHAR)
        {
            // avoid duplicated spaces when parent window is a native window
            if (wParam.ToInt32() == 32)
                handled = true;
        }
于 2011-03-15T16:58:56.263 に答える