6

次のようにVB6モジュールで変数を宣言しようとしています。

Public WithEvents MyObject As MyClass

ヘルプファイルにはWithEvents、クラスモジュールでのみ使用できると記載されています。.basモジュールで使用できないのはなぜですか?

私が作業しているレガシーコードには、モジュール内でグローバルに宣言されたオブジェクトがあります。この宣言に追加したいのですWithEventsが、他の多くのフォームなどがオブジェクトを参照しているため、オブジェクトをグローバルに保つ必要があります。コードの中断を最小限に抑えてこれを実現するにはどうすればよいですか?

4

4 に答える 4

5

グローバルオブジェクトをパラメーターとして受け入れ、そのイベントをシンクするクラスを作成します。

' Class MySink
Private WithEvents m_oSink As MyClass

Friend Sub frInit(oSink As MyClass)
    Set m_oSink = oSink
End Sub

Private Sub m_oSink_MyEvent()
    '--- implement event
End Sub

モジュールにこのクラスのインスタンスを作成します.bas

Public g_oMyObject AS MyClass
Private m_oMySink As MySink

Sub Main()
    Set g_oMyObject = New MyClass
    Set m_oMySink = New MySink
    m_oMySink.frInit g_oMyObject
End Sub
于 2012-08-28T11:52:06.777 に答える
3

VBのイベントは、かなり複雑なCOMメカニズムのラッパーです。基本的にこのメカニズムでは、関係するすべてのものは、インターフェイスIConnectionPointまたはIConnectionPointContainerを実装するCOMクラスである必要があります。BASモジュールはレガシーBASICの一部であり、VBクラスとは異なりCOMクラスとして実装されていません。COMでBASファイルをシングルトンタイプのオブジェクトとして再実装できたと思いますが(Global MultiUseクラスの場合と同様)、そうではありませんでした。そのため、残念ながらBASファイルはWithEventsを使用できません。

問題の最も簡単な解決策として、オブジェクト変数はオブジェクト自体ではなく、オブジェクトへの単なる参照であるという事実を利用する必要があります。関心のあるアプリケーションのビットを制御する手段を使用するために、イベントメッセージを必要な最高レベルのオブジェクトに到達させたいと思います。この場所を特定します。たとえば、最初にロードされ、最後にアンロードされることが確実なメインフォームがある可能性があります。このオブジェクトの初期化の一部として、グローバルオブジェクトへの参照を渡し、これをWithEventsモジュールレベル変数に設定します。これで、制御できます。

しかし!!そして、これは非常に重要です!フォーム(またはその他)への循環参照がある場合に備えて、アプリケーションを閉じる前に、この参照を適切なタイミングでクリアする必要があります。この場合、Form_Unloadイベントが理想的です。

于 2012-08-28T09:20:55.260 に答える
1

アプリケーションのサイズはわかりませんが、これを行うにはいくつかの方法があります。これが私がすることですが、これを使用するためにアプリをリファクタリングするのに15分ほどかかる場合があります。

まず、すべてのパブリックメソッドとグローバルメソッドとメンバーをモジュールから(たとえば)clsApplicationというクラスにコピーします。

次に、空になったモジュール(modGlobalと呼びます)で、を宣言しPublic Property Get Application() As clsApplicationます。先に進み、セッターも追加します。

第三に、Sub Main()プログラムを開始するあなたの中で、これをあなたの最初の行として追加しますSet modGlobal.Application = New clsApplication

これで、モジュールを、アプリケーション全体で発生するイベントをリッスンできるグローバルクラスに置き換えました。アプリの残りの部分では、このようにグローバルな状態にアクセスしたりApplication.ConfigApplication.GetUser()グローバルレベルで保持している他のあらゆるものにアクセスしたりできます。

もちろん、これをWithEventsを使用する変数だけに適用することもできますが、とにかくモジュールからコードを取得することを実際に検討する必要があります。


@Markへのコメントを見たところです。最小限のアプローチは、私が最後に参照したものです。TargetイベントクラスがMyEventSourceの場合は、オブジェクトを渡してプライベートにWithEventsとして宣言されるというプロパティを持つMyEventSourceListenerというクラスを作成します。次に、MyEventSourceListenerはイベントを受信し、それらをモジュールに転送します。

ハックしてコードをモジュールに戻すので、私はそれが好きではありませんが、それが最も便利なアプローチかもしれません。

于 2012-08-28T11:43:11.963 に答える
1

1つの単純なアプローチの事例

クラスまたはUserControl(実際には特別な種類のクラス)でさえ、プログラム全体で広く一般的に使用されるプロパティとメソッドを持つと非常に便利な場合があります。

主な関心事がステートレスな「ユーティリティ」メソッドの幅広い使用である場合(たとえば、URLエンコード、エンティティエンコードなどのメソッドを持つWeb関連の配列)、追加のグローバルインスタンスを「なし」イベントとして宣言するだけでかなり安価になります。重い内部状態(配列、コレクションなど)をロードさせないこと。プログラムはとにかくすべてのコードを必要とし、1つのコピーだけがメモリにあるため、2番目のインスタンスはかなり安価になる可能性があります。

もう1つのオプションは、これらの「一般的な」操作、さらにはプロパティ値を別のクラスまたは静的(BAS)モジュールに分解することです。

ただし、個別のモジュールにリファクタリングしたり、変更したりしてカスタマイズしたくない、かなり複雑なUserControlまたはクラスがある場合があります。たぶん、さまざまなプロジェクトで使用するための共通の標準バージョンを維持しているでしょう。多分それはあなたがソースさえ持っていないサードパーティのライブラリです。なんでもいい。

考慮すべきこと

これは、Irving Mainwayの不滅の言葉では「盲目の子供向けではない」にもかかわらず、あなたに役立つかもしれない別のテクニックに私たちをもたらします。あなたがこれを使用するのに十分な経験を積んでいるなら、それはすでにあなたに起こっているはずです-しかし、私たちの誰も完璧な記憶を持っていません(実際に私たちがその素晴らしいマニュアルを読むのに時間をかけたことがあれば)

したがって、おそらくこれは何らかの理由で機能せず、あなたはすでにそのアイデアを検討して破棄しました。

コンテナオブジェクト(Form、UserControl、親クラスなど)は、初期化時に問題のオブジェクトのインスタンスへのグローバル参照を慎重に設定し、終了時に参照を削除できます。これは、他のオブジェクトやプログラム全体がアンロードされないようにする循環参照や孤立した参照を避けるために、注意して行う必要があります。

これは、Johnny GoToが誤って使用したり、使用したりしないでください。しかし、VBで何をしているのかを知っていて、このテクニックとその落とし穴について説明しているマニュアルの部分を実際に読んで理解している場合は、役立つことがあります。

プログラムのスタートアップオブジェクトとしてForm1があるとします。Form1には、WebWiz1という名前のユーザーコントロール「WebWiz」のインスタンスがあります。しかし、他の場所(別の3つまたは12のフォーム?)では、一般的なMIMEタイプの文字列値のセットをファイル拡張子に変換するWebWizメソッドを呼び出したいと考えています。Form1のみがWebWiz1のイベントを処理する必要があり、WebWizは内部状態にかなり重いため、このメソッドのためだけに追加のインスタンスを作成する必要はありません。

静的モジュールでは、次のことを宣言するだけです。

Public gWebWiz As WebWiz

Form1のInitializeまたはLoadイベントが実行されるとき(または、WithEventsインスタンスを作成した後のクラスの場合)、次のことができます。

Set gWebWiz = WebWiz1

Form1のUnloadイベントハンドラーの場合:

Set gWebWiz = Nothing

次に、プログラムには、さまざまな目的に使用できるグローバル参照があります。

簡単そうですね?

これを使用するプログラムが、またはメインフォームで始まるコードの適切な「ツリー」として記述されているSub Main場合、通常、特別な注意を払う必要はありません。しかし、あなたがピンボールウィザードのようにコーディングしていて、「開いているすべてのフォームを見つけてアンロードするにはどうすればよいですか?」などの質問をしている人の1人である場合。次にあなた:

  • 「ハング」するプログラムを回避するために、さらに多くの作業を行う必要があります。
  • おそらく、このテクニックを実際に使用することはできません。
于 2012-08-28T13:36:03.957 に答える