简体   繁体   English

INOTifyPropertyChanged在c#结构中

[英]INotifyPropertyChanged in c# structures

Hello I have the following code: 您好我有以下代码:

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

};

When I bind this to a control.. it is not working. 当我将它绑定到控件时...它无法正常工作。 PropertyChangedEventHandler is always null.. But when I change this to class instead of struct, PropertyChangedEventHandler is not null and binding works perfectly. PropertyChangedEventHandler始终为null ..但是当我将其更改为类而不是struct时,PropertyChangedEventHandler不为null并且绑定工作正常。 So the question is, does INotifyPropertyChanged only works on classes? 所以问题是,INotifyPropertyChanged只适用于类吗?

You can implement INotifyPropertyChanged in a struct, but you should never do that, because semantics of structs do not play well (I'd say at all) with this interface, and events in general. 你可以在一个结构中实现INotifyPropertyChanged ,但是你永远不应该这样做,因为结构的语义在这个界面和一般的事件中都不能很好地发挥(我会说)。 Consider this: 考虑一下:

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));
    }
}

Now we just subscribe to event and change a property: 现在我们只订阅事件并更改属性:

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");
    }        
}

Output is "Property changed". 输出是“属性已更改”。 So you cannot say that structs and events do not work at all (or that INotifyPropertyChanged doesn't work with structs). 所以你不能说结构和事件根本不起作用(或者INotifyPropertyChanged不能用于结构)。 It works, kind of, until you try to pass that struct anywhere: 它有效,直到你尝试将结构传递到任何地方:

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");
    }        
}

Passing struct to Bind method as INotifyPropertyChanged boxes that struct, which makes a copy, so you subscribe to PropertyChanged event using one instance of EventStruct (a copy), but event is fired on another instance of the struct. 通过结构来Bind方法INotifyPropertyChanged是结构,这使得副本,让你订阅箱PropertyChanged使用的一个实例事件EventStruct (复印件),但事件对结构的另一个实例解雇。 So event subscriber list is empty on that instance where event is actually fired. 因此事件订阅者列表在实际触发事件的实例上为空。 Same happens if you just pass struct and not interface (in this case struct is copied because passed by value): 如果你只是传递struct而不是接口(在这种情况下,因为按值传递而复制了struct),也会发生同样的情况:

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

If you will pass by reference, it will work again: 如果您将通过引用传递,它将再次工作:

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

For that reason you should never implement events on structs, at least no use case comes to my mind where this can be useful and not lead into troubles. 出于这个原因,你永远不应该在结构上实现事件,至少没有一个用例出现在我的脑海里,这可能是有用的而不是导致麻烦。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM