1

私はマルチスレッド TDI UI に取り組んでいます (興味がある場合は C1 DockingTabs を使用してください)。これまでのところ、各ウィンドウを個別のスレッドで開き、SetParent Win32 API を使用してウィンドウを適切なタブ内に配置することができました。また、モーダル ダイアログをタブ内にも表示し、他のタブの動作を妨げないようにすることもできました (ダイアログ フォームの Shown イベントにハンドラーを追加して、SetParent を再度呼び出すことにより、オンとオフの切り替えに多少手間がかかります)。タブ内のフォームの TopLevel ですが、機能します)。

ここで、少し厄介なことが起こっているのは、ダイアログが開いていることです。これにより、TDI 親フォームからフォーカスが削除され、フォーカスがすぐに戻されます。表示する前に SetParent を呼び出すと、親を持つフォームにモーダル ダイアログを表示できないため、例外が発生します。ウィンドウアニメーションのスライド/フェードインとフェードアウトを、タブ内に収まるまでサイズを 0,0 にすることで回避できましたが、フォーカスのフリックオフとバックを停止する方法がわかりません。メインの親フォーム。

2つの可能なアプローチがあると思います:

  1. フォーカスを失ったように見えるウィンドウ効果を無効にします(ウィンドウメッセージをブロックする可能性がありますか?)
  2. 実際にそれを止めてフォーカスを失う

これは少し変わったクエリであることに感謝します。助けていただければ幸いです。


編集:

演習のポイントを明確にするために、各タブが事実上独立しているタブ ベースの UI を用意しました。何かが ShowDialog を呼び出すたびに、その 1 つのタブだけでなくアプリ全体がブロックされるというエンド ユーザーからの苦情がありました。これを回避する唯一の方法 (Google Chrome のようなマルチプロセスを除く) は、各タブに個別の UI スレッドを提供し、タブ内にダイアログをロードして、ユーザーが引き続き他のタブにアクセスできるようにすることです。ハッキングの一部をある程度取り除くことができ、問題のほとんどを修正することができました (もう少しプレイしただけです)。メイン フォームで WM_NCACTIVATE メッセージをブロックすることで、私が尋ねた質問を実際に修正することができました。私は私だと思います アクティブ化するかどうかを決定するには、アクティブ化されたフォームがこのダイアログの子であるかどうかを検出する必要があります。解決しようとするちらつきもありますが、見た目はずっと良くなっています。コードを投稿しますが、関連するフォームが 3 つあるため、プロジェクトをアップロードしないと少し面倒です。誰かが興味を持っている場合は、それを減らすことができるかどうかを確認しますか?

私は現在、概念実証としてそれをいじっているだけです。これが機能するようになったら、既存のアプリケーションに改造する必要があります。そこから本当の楽しみが始まります! 私は TDI の側面を制御するためのフレームワークを持っているので、その点からはかなり単純なはずです。本当の悪夢は、本質的にスレッドセーフではない共有リソースがいくつかあるため、さまざまなスレッド間で発生する可能性のある同期の問題を解決するために全体を監査することです。

4

2 に答える 2

0

笑ってくれてありがとう。それはかなり印象的です。このすべてのハッキングの結果を後悔することになるかもしれませんが、この作業を行うための大胆不敵な試みを称賛することはできません:)私は、あなたがそのようにする正当な理由があると仮定しています.変更するには道が遠すぎますが、ビジネス ロジックをいくつかの非同期メソッドにラップするだけでなく、UI を強制的にマルチスレッド化するのに非常に多くの手間がかかるのは奇妙に思えます。すべてのビジネス ロジックが非同期の場合は、すべてのフォームを 1 つのスレッドにすることができます。ただし、そうであっても、ShowDialog の代わりに Show を使用してフォームを表示すると同じ問題が発生するかどうかを確認することをお勧めします。Show に問題がなければ、ユーザーがフォームを閉じるまでスレッドをブロックする独自の ShowDialog 同期メソッドを実装できます。メソッド内でそれ自体を表示し、フォームが表示されている間にループに座ってスリープとイベントを実行すると、同じ効果があると思います。ただし、それを提案するのは少しうんざりします。

于 2012-05-03T13:41:34.170 に答える
0
Friend NotInheritable Class Win32
  Public Const WM_NCACTIVATE = &H86
  Public Const WM_SDLG_ACTIVATE = &H8000

  <DllImport("user32.dll")> Public Shared Function GetForegroundWindow() As IntPtr
  End Function

  <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
  Public Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
  End Function
End Class

ダイアログ内でメイン フォームがフォーカスを失ったように見えるのを止めるには - メイン フォーム内: -

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)

    Select Case m.Msg
        Case Win32.WM_NCACTIVATE
            Dim m2 As New System.Windows.Forms.Message()
            m2.HWnd = m.HWnd
            m2.Msg = m.Msg
            m2.LParam = m.LParam

            Dim fgwh = Win32.GetForegroundWindow()

            m2.WParam = If(fgwh = Handle, 1, 0) 'title bar state - TRUE for active
            m.Result = 1 'TRUE to do default processing, FALSE to block
            MyBase.WndProc(m2)
            Exit Sub

        Case Win32.WM_SDLG_ACTIVATE
            Dim m2 As New System.Windows.Forms.Message()
            m2.HWnd = m.HWnd
            m2.Msg = Win32.WM_NCACTIVATE
            m2.LParam = m.LParam

            Dim fgwh = Win32.GetForegroundWindow()

            If m.WParam = 0 Then
                m2.WParam = If(fgwh = Handle, 1, 0) 'title bar state - TRUE for active
            Else
                m2.WParam = 1
            End If

            m.Result = 1 'TRUE to do default processing, FALSE to block
            MyBase.WndProc(m2)
            Exit Sub


    End Select

    MyBase.WndProc(m)
End Sub

そしてサブフォームで: -

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    If m.Msg = Win32.WM_NCACTIVATE Then

        Dim fgwh = Win32.GetForegroundWindow()
        Dim wParam As IntPtr
        If fgwh = Me.Handle OrElse fgwh = MainForm.Instance.Handle Then
            wParam = 1
        Else
            wParam = 0
        End If

        Win32.SendMessage(MainForm.Instance.Handle, Win32.WM_SDLG_ACTIVATE, wParam, m.LParam)
    End If

    MyBase.WndProc(m)
End Sub

非アクティブ化されているメイン フォームを停止し、ダイアログ フォーム クラスで を取得するには: -

Protected Overrides ReadOnly Property ShowWithoutActivation As Boolean
    Get
        Return True
    End Get
End Property
于 2012-05-04T14:00:14.410 に答える