{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/vblang/issues/198","repository_url":"https://api.github.com/repos/dotnet/vblang","labels_url":"https://api.github.com/repos/dotnet/vblang/issues/198/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/vblang/issues/198/comments","events_url":"https://api.github.com/repos/dotnet/vblang/issues/198/events","html_url":"https://github.com/dotnet/vblang/issues/198","id":270682641,"number":198,"title":"Bindable Classes and Properties","user":{"login":"AnthonyDGreen","id":10539978,"avatar_url":"https://avatars3.githubusercontent.com/u/10539978?v=4","gravatar_id":"","url":"https://api.github.com/users/AnthonyDGreen","html_url":"https://github.com/AnthonyDGreen","followers_url":"https://api.github.com/users/AnthonyDGreen/followers","following_url":"https://api.github.com/users/AnthonyDGreen/following{/other_user}","gists_url":"https://api.github.com/users/AnthonyDGreen/gists{/gist_id}","starred_url":"https://api.github.com/users/AnthonyDGreen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnthonyDGreen/subscriptions","organizations_url":"https://api.github.com/users/AnthonyDGreen/orgs","repos_url":"https://api.github.com/users/AnthonyDGreen/repos","events_url":"https://api.github.com/users/AnthonyDGreen/events{/privacy}","received_events_url":"https://api.github.com/users/AnthonyDGreen/received_events","type":"User","site_admin":false},"labels":[{"id":521567546,"url":"https://api.github.com/repos/dotnet/vblang/labels/Proposal","name":"Proposal","color":"fef2c0","default":false},{"id":616186138,"url":"https://api.github.com/repos/dotnet/vblang/labels/Ready-to-Review","name":"Ready-to-Review","color":"0e8a16","default":false}],"state":"open","locked":false,"assignee":{"login":"AnthonyDGreen","id":10539978,"avatar_url":"https://avatars3.githubusercontent.com/u/10539978?v=4","gravatar_id":"","url":"https://api.github.com/users/AnthonyDGreen","html_url":"https://github.com/AnthonyDGreen","followers_url":"https://api.github.com/users/AnthonyDGreen/followers","following_url":"https://api.github.com/users/AnthonyDGreen/following{/other_user}","gists_url":"https://api.github.com/users/AnthonyDGreen/gists{/gist_id}","starred_url":"https://api.github.com/users/AnthonyDGreen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnthonyDGreen/subscriptions","organizations_url":"https://api.github.com/users/AnthonyDGreen/orgs","repos_url":"https://api.github.com/users/AnthonyDGreen/repos","events_url":"https://api.github.com/users/AnthonyDGreen/events{/privacy}","received_events_url":"https://api.github.com/users/AnthonyDGreen/received_events","type":"User","site_admin":false},"assignees":[{"login":"AnthonyDGreen","id":10539978,"avatar_url":"https://avatars3.githubusercontent.com/u/10539978?v=4","gravatar_id":"","url":"https://api.github.com/users/AnthonyDGreen","html_url":"https://github.com/AnthonyDGreen","followers_url":"https://api.github.com/users/AnthonyDGreen/followers","following_url":"https://api.github.com/users/AnthonyDGreen/following{/other_user}","gists_url":"https://api.github.com/users/AnthonyDGreen/gists{/gist_id}","starred_url":"https://api.github.com/users/AnthonyDGreen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnthonyDGreen/subscriptions","organizations_url":"https://api.github.com/users/AnthonyDGreen/orgs","repos_url":"https://api.github.com/users/AnthonyDGreen/repos","events_url":"https://api.github.com/users/AnthonyDGreen/events{/privacy}","received_events_url":"https://api.github.com/users/AnthonyDGreen/received_events","type":"User","site_admin":false}],"milestone":null,"comments":11,"created_at":"2017-11-02T14:52:12Z","updated_at":"2017-11-22T07:15:09Z","closed_at":null,"author_association":"CONTRIBUTOR","body":"Klaus said #194 was complicated by its generality. On the far end here is an alternative.\r\n\r\n* New Modifier `Bindable`. Can be applied to individual properties.\r\n* Causes auto-props to implement precisely the pattern used of `INotifyPropertyChanged`.\r\n  * Check to see if value changed (null = null) calling the `=` operator if present, or `Shared` `Object.Equals` method if no `=` operator exists.\r\n  * If changed, call `OnPropertyChanged` if available, or raise `PropertyChanged` event if that method does not exist. This is required to support the event being defined in a base class.\r\n* Can be applied to an entire class (but not structures), making all auto-props implicitly `Bindable`.\r\n  * `NotBindable` modifier can be applied at property level to opt-out.\r\n* Doesn't inherit; if your base class is `Bindable` it doesn't mean you are.\r\n* Requires you to explicitly implement `INotifyPropertyChanged`, IDE should probably code spit this.\r\n* We could also spit code for `INotifyPropertyChanging` though I'm aware of no use-case for this. I've heard rumors of a performance optimization of LINQ-to-SQL and others have suggested it so it's worth discussing.\r\n\r\nWe only get one shot at this so whatever code pattern we pick better be all anyone ever needs.\r\n\r\n===11/6/2017===\r\nI've been thinking about another common scenario, computed properties which depend on other properties and need to fire `PropertyChanged` whenever their dependencies change. There are a few ways we could deal with this.\r\n\r\n**The imperative way**\r\nUnder the above proposal here's what a user could do.\r\n\r\n``` VB.NET\r\nBindable Class Rectangle\r\n    Implements INotifyPropertyChanged\r\n\r\n    Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged\r\n\r\n    Property Width As Integer\r\n    Property Height As Integer\r\n\r\n    ReadOnly Property Area As Integer\r\n        Get\r\n            Return Width * Height\r\n        End Get\r\n    End Property\r\n\r\n    Sub OnPropertyChanged(propertyName As String)\r\n        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))\r\n\r\n        Select Case propertyName\r\n            Case NameOf(Width), NameOf(Height)\r\n                OnPropertyChanged(NameOf(Area))\r\n        End Select\r\n    End Sub\r\n```\r\n\r\n**The declarative way**\r\nThat's doable but not ideal. But what if we made a way to declare such a dependency explicitly in code?\r\n\r\n``` VB.NET\r\n    ReadOnly Property Area As Integer DependsOn Width, Height\r\n        Get\r\n            Return Width * Height\r\n        End Get\r\n    End Property\r\n```\r\n\r\nSimilar to the `Handles` clause for methods, the `DependsOn` clause could be added to the end of a expanded `ReadOnly` property (this is the only case for which this feature would make sense) and would in essence cause a special handler to be registered on the `PropertyChanged` event on object creation that would re-raise the event for the dependent property.\r\n\r\n**Bonus**\r\nIf the property being depended upon itself implements `INotifyPropertyChanged` or `INotifyCollectionChanged` a handler will also be registered for those events to raise `PropertyChanged` for the dependent properties. Of course, I think for this to make sense the compiler code-gen for the auto-props would have to be very similar to what we do for `Handles` today, where the handler is registered when the property is set and removed when the value changes. I think it might be common for composite ViewModels which aggregate other ViewModels or multiple model objects.\r\n\r\n**Likely bridge too far**\r\nWe could allow a single dotted name so that the user could be more granular about which sub-properties they depend on, e.g. `DependsOn Product.UnitPrice`. The only benefit of this would be performance and I don't think the frequency of that concern justifies the complexity, but let's discuss."},"comment":{"url":"https://api.github.com/repos/dotnet/vblang/issues/comments/346263279","html_url":"https://github.com/dotnet/vblang/issues/198#issuecomment-346263279","issue_url":"https://api.github.com/repos/dotnet/vblang/issues/198","id":346263279,"user":{"login":"KlausLoeffelmann","id":9663150,"avatar_url":"https://avatars3.githubusercontent.com/u/9663150?v=4","gravatar_id":"","url":"https://api.github.com/users/KlausLoeffelmann","html_url":"https://github.com/KlausLoeffelmann","followers_url":"https://api.github.com/users/KlausLoeffelmann/followers","following_url":"https://api.github.com/users/KlausLoeffelmann/following{/other_user}","gists_url":"https://api.github.com/users/KlausLoeffelmann/gists{/gist_id}","starred_url":"https://api.github.com/users/KlausLoeffelmann/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/KlausLoeffelmann/subscriptions","organizations_url":"https://api.github.com/users/KlausLoeffelmann/orgs","repos_url":"https://api.github.com/users/KlausLoeffelmann/repos","events_url":"https://api.github.com/users/KlausLoeffelmann/events{/privacy}","received_events_url":"https://api.github.com/users/KlausLoeffelmann/received_events","type":"User","site_admin":false},"created_at":"2017-11-22T07:15:09Z","updated_at":"2017-11-22T07:15:09Z","author_association":"NONE","body":"This, BTW, is the result of the reflectored Assembly with Telerik's JustDecompile:\r\n\r\n![image](https://user-images.githubusercontent.com/9663150/33114385-eb9c8bcc-cf5c-11e7-80ae-e0975e463cb0.png)\r\n\r\nAnd, of course...\r\n\r\n![image](https://user-images.githubusercontent.com/9663150/33114457-3ecfb4e0-cf5d-11e7-856e-1f6b7460d35a.png)\r\n\r\n"}}
{"actor":{"display_login":"KlausLoeffelmann"}}