2017-05-11 12 views
3

こんにちは、私は次のコードを持っている:C#の構造体にINotifyPropertyChangedの

public struct zoomInfo : INotifyPropertyChanged 
{ 
    public float zoom; 
    public float translateX; 
    public float translateY; 
    private int level; 

    public int zoomLevel 
    { 
     get { return level; } 
     set { 
      level = value; 
      OnPropertyChanged("zoomLevel"); 
     } 
    } 

    //region Implementation of INotifyPropertyChanged 

    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnPropertyChanged(string propertyName) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    //endregion 

}; 

私がコントロールにこれをバインドする...それが機能していませんが。 PropertyChangedEventHandlerは常にnullです。しかし、これをstructではなくクラスに変更すると、PropertyChangedEventHandlerはnullでなくなり、バインディングは完全に機能します。ですから、問題は、INotifyPropertyChangedはクラスでのみ動作するのですか?

+2

構造体は常に値によって渡されます。一般的なイベントではうまくいきません。 [これを考慮](http://kosiara87.blogspot.co.at/2011/11/cnever-place-event-inside-struct-c.html)、[これと](http://stackoverflow.com/q/12173723/1132334) – dlatikay

+0

だから私はこの記事で受け入れられた答えを推測する:http://stackoverflow.com/questions/33065954/structs-and-inotifypropertychangedは間違っている – Redis1001

+0

[インターフェイスを実装する構造]をサポートするために必要なボクシングを考えてみましょうhttps://blogs.msdn.microsoft.com/abhinaba/2005/10/05/c-structs-and-interface/) – Steve

答えて

2

構造体にINotifyPropertyChangedを実装することはできますが、構造体のセマンティクスがこのインタフェースと一般的なイベントでうまく動かないため(私はまったく言っていません)、これを行うべきではありません。

struct EventStruct : INotifyPropertyChanged { 
    private string _property; 

    public string Property 
    { 
     get { return _property; } 
     set 
     { 
      _property = value; 
      OnPropertyChanged(); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    [NotifyPropertyChangedInvocator] 
    private void OnPropertyChanged([CallerMemberName] string propertyName = null) { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

今、私たちはイベントをサブスクライブし、プロパティを変更します:

class Program { 
    static void Main() { 
     var s = new EventStruct(); 
     s.PropertyChanged += OnPropertyChanged; 
     s.Property = "test"; 
     Console.ReadKey(); 
    }   

    private static void OnPropertyChanged(object sender, PropertyChangedEventArgs e) { 
     Console.WriteLine(e.PropertyName + " changed"); 
    }   
} 

出力は "プロパティを変更" であるこのことを考えてみましょう。したがって、構造体とイベントがまったく動作しない(またはINotifyPropertyChangedが構造体で動作しない)とは言えません。あなたがEventStructの1つのインスタンスを(使用してPropertyChangedイベントをサブスクライブして、Bind方法に構造体を渡す

class Program { 
    static void Main() { 
     var s = new EventStruct();    
     Bind(s); 
     s.Property = "test"; 
     Console.ReadKey(); 
    } 

    static void Bind(INotifyPropertyChanged item) { 
     // this is not the same instance of EventStruct, 
     // it's a copy, and event will never be fired on this copy 
     item.PropertyChanged += OnPropertyChanged; 
    } 

    private static void OnPropertyChanged(object sender, PropertyChangedEventArgs e) { 
     Console.WriteLine(e.PropertyName + " changed"); 
    }   
} 

INotifyPropertyChangedとしてボックスコピーを作成し、構造体を、:あなたはそれを渡すようにしようとするまで、それはどこでも構造体、一種の、作品コピー)が、構造体の別のインスタンスでイベントが発生します。イベントが実際に発生したインスタンスでは、イベントのサブスクライバリストは空です。あなたが参照渡しする場合は

static void Bind(EventStruct item) { 
    item.PropertyChanged += OnPropertyChanged; 
} 

、それが再び動作します:

static void Bind(ref EventStruct item) { 
    item.PropertyChanged += OnPropertyChanged; 
} 

のためにあなただけの構造体渡し、インタフェースされていない場合も同じことが(この場合、構造体の値によって渡されているためコピーされる)が起こりますあなたが構造体のイベントを決して実装してはならない理由は、これが役に立つかもしれないし、トラブルにつながることもないユースケースは少なくとも私の心にかかっていません。

+0

WinFormsのデータバインディングは 'object'で動作します(したがってボックス化された構造体では常に動作します)。参照によってさえもオプションではありません。 –

+1

@IvanStoev確かに、唯一の選択肢はこれをしないことです。 Refの例は、回避策としてではなく、動作の説明のためのものです。 – Evk