10

編集できないクラスを使用しています。プロパティ(ブール値)があり、変更されたときに通知されると便利です。からクラスをインポートしているため、プロパティgetまたはsetを編集できません。 dll(私はコードを持っていません)。

プロパティが変更されたときに発生するイベント/関数を作成するにはどうすればよいですか?

追加
それは、それ自身のクラス内で、基礎となるプライベート変数に直接変更されるだけです。

例えば

private bool m_MyValue = false;

public bool MyValue
  {
  get { return m_MyValue; }
  }

private void SomeFunction()
  {
  m_MyValue = true;
  }
4

8 に答える 8

10

基本的には、デバッガーAPIのようなものを使用して、実行時にコードを挿入し、元のライブラリのILを変更する必要があります(これらのソリューションのいずれもお勧めしません。他のソリューションを除いて、違反する可能性があります)ライブラリのライセンス)。

基本的に、プロパティが通知をサポートしていない場合、そのプロパティは通知をサポートしていません。問題に取り組む別の方法を探す必要があります。(たとえば、ポーリングは機能しますか?)

于 2009-08-06T10:44:13.340 に答える
5

これを直接行うことはできません[JonSkeetが言ったように]、仮想でない限り、クラスのすべてのインスタンス作成をインターセプトする立場にあり、propgetの実際の「値」に影響を与えるバッキングフィールドへの変更はありません。

これを総当たり攻撃する唯一の方法は、Mono.CecilまたはMS CCIを使用して、CecilのこのDimeCastでプロップセッターを計測することです。(またはPostSharp)

ただし、これはバッキングフィールドへの内部変更をトラップしません(バッキングフィールドがある場合でも)。(これが、ラッピングがおそらく機能しない理由です)。

更新:根本的なフィールドの変更を確実にトラップしようとしている更新を考えると、それを行う唯一の方法は、PS / CCI / Cecilを使用し、フローを分析してすべてのフィールドの更新をインターセプトすることです。要するに、あまり実現可能ではありません。

于 2009-08-06T10:43:06.807 に答える
3

間違いなく、これを行う唯一の実際の方法は、別のスレッドで実行されるある種の「ウォッチャー」コンポーネントを作成することです。このコンポーネントの仕事は、プロパティを定期的に読み取り、プロパティの値が変更されたときにイベントを発生させることです。もちろん、このソリューションは、スレッド化と同期化の濁った海域を航行します。

アプリケーションがこのオブジェクトに関してシングルスレッドであると仮定すると、最もクリーンな解決策は、プロキシオブジェクトを介してこのオブジェクトへのメソッド呼び出しを行うことです。物件の前後の状態をチェックし、変更された場合はイベントを発生させる役割があります。

これが私が話していることの簡単な例です:

public class SomeProxy
{
    public SomeProxy(ExternalObject obj)
    {
         _obj = obj;
    }

    public event EventArgs PropertyChanged;

    private bool _lastValue;

    private ExternalObject _obj;

    protected virtual void OnPropertyChanged()
    {
        if(PropertyChanged != null)
            PropertyChanged();
    }

    protected virtual void PreMethodCall()
    {
        _lastValue = _obj.SomeProperty;
    }

    protected virtual void PostMethodCall()
    {
        if(_lastValue != _obj.SomeProperty)
            OnPropertyChanged();
    }

    // Proxy method.
    public SomeMethod(int arg)
    {
        PreMethodCall();
        _obj.SomeMethod(arg); // Call actual method.
        PostMethodCall();
    }
}

明らかに、このプロキシパターンを適切なオブジェクトに組み込むことができます。イベントが発生すると予想されるときに、すべての呼び出しがプロキシを経由する必要があることに注意する必要があります。

于 2009-08-06T12:00:10.147 に答える
2

前述のように、最も直接的な方法(およびコードへの変更が最小限で済む方法)は、PostSharpなどのAOPライブラリを使用することです。

ただし、従来のC#/。NETを使用して、WPF全体で大きな効果を発揮する依存関係プロパティパターンを使用することで、解決策を実現で​​きます。これをよく読んで、適切な場合は、プロジェクトにそのようなシステム(または少なくともその簡略化されたバージョン)を実装することを検討することをお勧めします。

于 2009-08-06T12:04:15.317 に答える
1

dll内のクラスをラップするクラスを作成する必要があります。setterプロパティ内で、通常のメソッドを使用してそこでイベントを発生させるだけです。

于 2009-08-06T10:44:20.533 に答える
1

クラスから継承してプロパティを非表示にできますか?このようなもの...

class MyClass : BaseClass
{
    // hide base property.
    public new bool MyProperty
    {
        get
        {
            return base.MyProperty;
        }

        set
        {
            base.MyProperty = value;
            RaiseMyPropertyChangedEvent();
        }
    }
}
于 2009-08-06T10:47:11.120 に答える
0

Alexのラッパーの考え方は良いと思いますが、最も重要なことは、使用前に値が変更されることを知っていることを考えると、内部の値の変更の心配を回避して、通知をゲッターに移動するだけです。 。そうすれば、ポーリングに似たものを手に入れることができますが、信頼性があります。

class MyClass : BaseClass
{
    //local value
    private bool local;

    //first access yet?
    private bool accessed = false;

    // Override base property.
    public new bool MyProperty
    {
        get
        {
            if(!accessed)
            {
                // modify first-get case according to your taste, e.g.
                local = base.MyProperty;
                accessed = true;
                RaiseMyPropertyChangedBeforeUseEvent();
            }
            else
            {
                if(local != base.MyProperty)
                {
                    local = base.MyProperty;
                    RaiseMyPropertyChangedBeforeUseEvent();
                }
            }

            return local;
        }

        set
        {
            base.MyProperty = value;
        }
    }
}
于 2009-08-06T12:11:52.650 に答える
-1

あなたはそれを継承して、それの代わりにそれの子を使うことを試みることができます。プロパティの「セット」をオーバーライドして、イベントを発生させます。

編集:...プロパティが親クラスで仮想である場合のみ..。

于 2009-08-06T10:44:35.430 に答える