{"id":14,"date":"2009-09-15T14:03:01","date_gmt":"2009-09-15T12:03:01","guid":{"rendered":"http:\/\/www.limilabs.com\/blog\/?p=14"},"modified":"2009-09-15T14:03:01","modified_gmt":"2009-09-15T12:03:01","slug":"inotifypropertychanged-with-postsharp","status":"publish","type":"post","link":"https:\/\/www.limilabs.com\/blog\/inotifypropertychanged-with-postsharp","title":{"rendered":"INotifyPropertyChanged with PostSharp 1.5"},"content":{"rendered":"<p>If you are doing WPF development, most likely you are tired of writing property implementations that raise <em>PropertyChanged<\/em> event manually:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic class MainWindowViewModel : ViewModel\n{\n    private string _message;\n\n    public string Message\n    {\n        get\n        {\n            return _message;\n        }\n        set\n        {\n            _message = value;\n            OnPropertyChanged(&quot;Message&quot;);\n        }\n    }\n\n    \/\/ ...\n}\n<\/pre>\n<p><a href=\"http:\/\/www.postsharp.org\">PostSharp<\/a> is a great tool to make such things simplier.<\/p>\n<p>Let&#8217;s look at the specific ViewModel class that has a <em>Message<\/em> property that is <strong>bound to some UI element<\/strong> using XAML:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic class MainWindowViewModel : ViewModel\n{\n    &#x5B;RaisePropertyChanged]\n    public string Message { get; set; }\n\n    \/\/ ...\n}\n<\/pre>\n<p> Notice the <em>RaisePropertyChanged<\/em> attribute, which we&#8217;ll implement later.<\/p>\n<p>Here&#8217;s our <strong>base ViewModel<\/strong> class that provides <strong>actual implementation<\/strong> of the <em>INotifyPropertyChanged<\/em> interface:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic class ViewModel : INotifyPropertyChanged\n{\n    public event PropertyChangedEventHandler PropertyChanged\n        = delegate { };\n\n    public void OnPropertyChanged(string propertyName)\n    {\n        PropertyChanged(this,new PropertyChangedEventArgs(propertyName));\n    }\n};\n<\/pre>\n<p>Finally the PostSharp attribute:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n&#x5B;Serializable]  \/\/ required by PostSharp\npublic class RaisePropertyChangedAttribute : OnMethodBoundaryAspect\n{\n    private string _propertyName;\n\n    \/\/\/ &lt;summary&gt;\n    \/\/\/ Executed at runtime, after the method.\n    \/\/\/ &lt;\/summary&gt;\n    public override void OnExit(MethodExecutionEventArgs eventArgs)\n    {\n        ViewModel viewModel = (ViewModel)eventArgs.Instance;\n        viewModel.OnPropertyChanged(_propertyName);\n    }\n\n    public override bool CompileTimeValidate(MethodBase method)\n    {\n        if (IsPropertySetter(method))\n        {\n            _propertyName = GetPropertyName(method);\n            return true;\n        }\n        return false;\n    }\n\n    private static string GetPropertyName(MethodBase method)\n    {\n        return method.Name.Replace&quot;set_&quot;, &quot;&quot;);\n    }\n\n    private static bool IsPropertySetter(MethodBase method)\n    {\n        return method.Name.StartsWith(&quot;set_&quot;);\n    }\n};\n<\/pre>\n<p>Note that we are validating if the method is in fact a property only during <strong>compilation time<\/strong> using <em>CompileTimeValidate<\/em> method.<\/p>\n<p>During compile time appropriate invocations of <em>OnPropertyChanged<\/em> method will be <strong>injected after every set operation<\/strong> applied to the <em>Message<\/em> property.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you are doing WPF development, most likely you are tired of writing property implementations that raise PropertyChanged event manually: public class MainWindowViewModel : ViewModel { private string _message; public string Message { get { return _message; } set { _message = value; OnPropertyChanged(&quot;Message&quot;); } } \/\/ &#8230; } PostSharp is a great tool to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[15,37,43,62],"class_list":["post-14","post","type-post","status-publish","format-standard","hentry","category-programming","tag-c","tag-mvvm","tag-postsharp","tag-wpf"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/posts\/14"}],"collection":[{"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/comments?post=14"}],"version-history":[{"count":0,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/posts\/14\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/media?parent=14"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/categories?post=14"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/tags?post=14"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}