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. So the question is, does INotifyPropertyChanged only works on classes?
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. 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). 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. 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):
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With