Anda di halaman 1dari 320

1. Catel documentation Home . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

5
1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.1.1 Why Catel? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.1.2 Platform support explanation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.1.3 Introduction to data objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.1.4 Introduction to MVVM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.1.4.1 MVVM framework comparison sheet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.1.4.2 Different interpretations of MVVM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.1.4.3 Validation in model or view model? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.1.4.4 Introduction to MVVM and models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.1.4.5 Creating view models with Catel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.1.4.6 Introduction to services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.1.4.7 Introduction to the nested user controls problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
1.1.4.8 Introduction to unit testing in MVVM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
1.1.5 Introduction to MVC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
1.2 FAQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
1.2.1 General . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
1.2.2 MVVM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
1.3 Setup, deployment and projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
1.3.1 Getting prerelease (beta) versions via NuGet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
1.3.2 Stepping through the code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
1.3.3 Compiling from source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
1.3.4 Code snippets & templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
1.3.4.1 Using the code snippets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
1.3.4.2 Using the item templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
1.3.4.3 Using the project templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
1.3.5 Updating to a new version via NuGet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
1.4 Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
1.4.1 Quick introduction for developers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
1.4.2 Getting started with WPF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
1.4.2.1 Creating the project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
1.4.2.2 Creating the models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
1.4.2.3 Serializing data from/to disk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
1.4.2.4 Creating the view models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
1.4.2.5 Creating the views (user controls) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
1.4.2.6 Creating the views (windows) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
1.4.2.7 Hooking up everything together . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
1.4.2.8 Finalizing the application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
1.5 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
1.5.1 WPF Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
1.5.1.1 Advanced WPF example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
1.5.1.2 Authentication example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
1.5.1.3 Browser application example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
1.5.1.4 Master/detail example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
1.5.1.5 Multilingual example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
1.5.1.6 MVVM communication styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
1.5.1.7 Person application WPF example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
1.5.1.8 Validation example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
1.5.1.9 Viewmodel lifetime example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
1.5.2 Silverlight examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
1.5.2.1 Advanced Silverlight example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
1.5.2.2 Navigation example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
1.5.2.3 Nested user controls example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
1.5.2.4 Person application Silverlight example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
1.5.3 Windows Phone examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
1.5.3.1 Bing maps example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
1.5.3.2 Sensors example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
1.5.3.3 Shopping list example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
1.6 Performance considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
1.7 Catel.Core . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
1.7.1 Argument checking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
1.7.2 Caching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
1.7.3 Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
1.7.4 Data handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
1.7.4.1 ObservableObject . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
1.7.4.2 DispatcherObservableObject . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
1.7.4.3 ModelBase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
1.7.4.4 Using ModelBase as base for entities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
1.7.4.5 Advanced property change notifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
1.7.4.6 WCF services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
1.7.5 Exception handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
1.7.6 IoC (ServiceLocator and TypeFactory) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
1.7.6.1 Introductions to IoC components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
1.7.6.1.1 Introduction to the ServiceLocator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
1.7.6.1.2 Introduction to the TypeFactory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
1.7.6.1.3 Introduction to DependencyResolver and DependencyResolverManager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
1.7.6.1.4 Dependency injection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
1.7.6.1.5 Ensuring integrity of the ServiceLocator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
1.7.6.2 Automatic type registration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
1.7.6.2.1 Automatically registering types using attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
1.7.6.2.2 Automatically registering types using conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
1.7.6.3 Setting up the ServiceLocator using configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
1.7.6.4 Replacing the default components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
1.7.7 Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
1.7.7.1 Customizing listeners . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
1.7.7.2 Batch log listeners . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
1.7.7.3 Integration with external loggers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
1.7.7.3.1 Log4net . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
1.7.7.3.2 NLog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
1.7.7.4 Writing logs to disk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
1.7.7.5 Creating log listeners via configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
1.7.7.6 Anotar.Catel.Fody . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
1.7.8 Messaging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
1.7.8.1 MessageBase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
1.7.8.2 Message mediator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
1.7.8.3 Messaging via attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
1.7.9 Multilingual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
1.7.10 Parallel invocation and tasks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
1.7.11 Preventing memory leaks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
1.7.11.1 Change notification wrapper . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
1.7.11.2 Weak events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
1.7.12 Reflection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
1.7.13 Scoping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
1.7.14 Serialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
1.7.14.1 Introduction to serialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
1.7.14.2 Specifying what gets serialized . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
1.7.14.3 Customizing serialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
1.7.15 Thread safe code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
1.7.16 Validation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
1.7.16.1 Validation via validate methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
1.7.16.2 Validation via data annotations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
1.7.16.3 Validation via special model validators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
1.7.16.4 Validation via IValidator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
1.7.16.5 Using the validation context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
1.7.16.6 Getting a summary of validation results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
1.7.16.7 Deferring validation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
1.8 Catel.MVVM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
1.8.1 Auditing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
1.8.2 Behaviors & triggers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
1.8.2.1 Authentication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
1.8.2.2 DelayBindingUpdate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
1.8.2.3 DoubleClickToCommand . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
1.8.2.4 EventToCommand . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
1.8.2.5 Focus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
1.8.2.6 FocusFirstControl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
1.8.2.7 KeyPressToCommand . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
1.8.2.8 MouseInfo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
1.8.2.9 Navigate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
1.8.2.10 NumericTextBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
1.8.2.11 SelectTextOnFocus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
1.8.2.12 UpdateBindingOnPasswordChanged . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
1.8.2.13 UpdateBindingOnTextChanged . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
1.8.3 Commands & events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
1.8.3.1 Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
1.8.3.2 Application-wide commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
1.8.3.3 Asynchronous commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
1.8.3.4 Commands authentication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
1.8.3.5 Hooking a command to validation automatically . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
1.8.4 Converters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
1.8.5 Designers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
1.8.6 Handling application initialization parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
1.8.7 Locators and naming conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
1.8.7.1 ViewModelLocator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
1.8.7.2 ViewLocator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
1.8.7.3 UrlLocator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
1.8.7.4 Naming conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
1.8.8 Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
1.8.8.1 AccelerometerService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
1.8.8.2 CameraService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
1.8.8.3 CompassService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
1.8.8.4 GyroscopeService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
1.8.8.5 LocationService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
1.8.8.6 MessageService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
1.8.8.7 NavigationService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
1.8.8.8 OpenFileService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
1.8.8.9 PleaseWaitService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
1.8.8.10 ProcessService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
1.8.8.11 SaveFileService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
1.8.8.12 SchedulerService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
1.8.8.13 SelectDirectoryService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
1.8.8.14 SplashScreenService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
1.8.8.15 UIVisualizerService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
1.8.8.16 VibrateService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
1.8.8.17 ViewExportService . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
1.8.9 View models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
1.8.9.1 Creating a basic view model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
1.8.9.2 Creating a view model that watches over other view models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
1.8.9.3 Creating a view model with a model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
1.8.9.4 Creating a view model with a model and mappings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
1.8.9.5 Mapping properties from view to view model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
1.8.9.6 Nested view models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
1.8.9.7 Validation in view models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
1.8.9.8 Advanced view models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
1.8.9.8.1 Keeping view models alive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
1.8.9.8.2 Exposing properties of a model automatically . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
1.8.9.8.3 Determine the view model type dynamically at runtime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
1.8.9.8.4 Controlling the instantiation of view models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
1.8.10 Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260
1.8.10.1 DataWindow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260
1.8.10.2 UserControl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
1.8.10.3 MVVM behaviors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
1.8.10.4 Validation controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
1.8.10.5 Finding the view of a view model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
1.8.10.6 Using external controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
1.8.10.6.1 Using a custom control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
1.8.10.6.2 Using a custom window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
1.8.10.7 Advanced information about views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
1.8.10.7.1 DataWindow - under the hood . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
1.8.10.7.2 UserControl - under the hood . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
1.9 Catel.Mvc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
1.9.1 Configuring dependency injection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
1.10 Catel.Extensions.Controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
1.10.1 Controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
1.10.1.1 StackGrid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
1.10.1.2 TabControl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
1.10.1.3 TraceOutputControl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
1.10.1.4 WatermarkTextBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
1.10.2 Pixel shaders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
1.10.3 StyleHelper . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
1.10.4 Themes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
1.11 Catel.Extensions.CSLA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
1.12 Catel.Extensions.Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
1.12.1 Specifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
1.13 Catel.Extensions.DynamicObjects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
1.14 Catel.Extensions.EntityFramework5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
1.14.1 Using the DbContextManager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
1.14.2 Using the repositories and unit of work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
1.15 Catel.Extensions.FluentValidation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
1.16 Catel.Extensions.Interception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
1.16.1 Method interception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
1.16.2 Property interception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302
1.17 Catel.Extensions.Memento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303
1.17.1 Memento and collections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
1.17.2 Memento and methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
1.17.3 Memento and properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
1.18 Catel.Extensions.Prism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
1.18.1 Declaring modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
1.18.2 Translating or customizing the initialization task messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
1.18.3 Using the bootstrapper . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
1.19 Catel.Extensions.Wcf.Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
1.20 Catel.Fody . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
1.20.1 Weaving properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
1.20.2 Weaving argument checks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
1.20.3 Exposing properties on view models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
1.20.4 XmlSchema generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
1.21 Catel.ReSharper . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
1.21.1 Checking arguments of a method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
1.21.2 Converting regular properties into Catel properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
1.22 Reference documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
Catel documentation Home
Welcome to the documentation of Catel.The framework consists of several projects. Each project has it's reference documentation. The actual
technical documentation is available in the downloads sections. However, the wiki contains some real-life examples and additional explanation of
some of the features of Catel.
Supported platforms
Looking for documentation of other versions?
Articles or documentation?
Explanation about the documentation
Catel is an application toolkit with the focus on MVVM, and consists of two basic pillars and extensions.
contains an IoC container, data objects, validation, message mediator, argument checking, etc. This can be used in any application Catel.Core
and is not specific for Windows applications.
Catel.MVVM contains all the MVVM classes such as ViewModelBase, Command, services, etc.
Catel also provides the following extensions:
Catel.Extensions.Controls
Catel.Extensions.CSLA
Catel.Extensions.Data
Catel.Extensions.EntityFramework5
Catel.Extensions.EntityFramework6
Catel.Extensions.FluentValidation
Catel.Extensions.Interception
Catel.Extensions.Memento
Catel.Extensions.Prism
Below is a visual representation of the available blocks in Catel:
Supported platforms
The following platforms are supported by Catel:

Don't want to read much? Make sure that you at least read the with the absolute basics quick introduction
Looking for documentation of other versions?
Catel LATEST
Catel 3.8
Catel 3.7
Catel 3.6
Catel 3.5
Articles or documentation?
You have probably also found the articles on The Code Project. These articles are meant to be an introduction to a specific field of techniques that
can be found inside Catel. If you are looking for documentation, this is the place to be.
Are you missing documentation?
If you are missing documentation or feel that documentation is out of date, please let us know and we will will fix it!
Explanation about the documentation
You can either navigate through the left bar or via the search at the right top. Below are the top parts of the documentation:
Introduction
FAQ
Setup, deployment and projects
Getting started
Examples
Performance considerations
Catel.Core
Catel.MVVM
Catel.Mvc
Catel.Extensions.Controls
Catel.Extensions.CSLA
Catel.Extensions.Data
Catel.Extensions.DynamicObjects
Catel.Extensions.EntityFramework5
Catel.Extensions.FluentValidation
Catel.Extensions.Interception
Catel.Extensions.Memento
Catel.Extensions.Prism
Catel.Extensions.Wcf.Server
Catel.Fody
Catel.ReSharper
Reference documentation
Introduction
Welcome to the introduction of Catel. Catel is a framework (or enterprise library, just use whatever you like) with data handling, diagnostics,
logging, WPF controls, and an MVVM-framework. So Catel is more than "just" another MVVM-framework or some nice Extension Methods that
can be used. It's more like a library that you want to include in all the XAML applications you are going to develop in the near future.
For detailed information about platform support, see Platform support explanation
Don't forget to take a look at the code snippets and project templates, they will make your life much easier
Note that Catel is primarily meant for Line of Business (LoB) applications
It's important to realize that Catel is not just another Extension Methods library, nor only an MVVM-framework, but it is a combination of basic data
handling, useful controls, and an MVVM-framework.
Why another framework?
You might be thinking: why another framework, there are literally thousands of them out there. Well, first of all, thousands of them is quite a lot,
let's just say there are hundreds of them. A few years ago, the lead developer of Catel was using serialization to serialize data from/to disk. But,
as he noticed, he had to take care of different versions after every release. After every release, he had to take care of the serialization and
backwards compatibility. Also, he had to implement some very basic interfaces (such as INotifyPropertyChanged) for every data object. Then, he
decided to write a base class for data handling which can take care of different versions and serialization by itself, and implements the most basic
interfaces of the .NET Framework out of the box. The article was published on CodeProject as DataObjectBase.
Then, he was working on a WPF project with five other developers and needed an MVVM-framework since the application was not using MVVM
at the moment. Writing an MVVM-framework was no option because there were so many other frameworks out there. But, after looking at some
Open-Source MVVM-frameworks (such as the excellent Cinch framework, which was the best one we could find), none of them seemed to be a
real option. Creating the View Models was too much work, and the View Models still contained lots of repetitive code in, for example, the property
definitions. After taking a closer look at the source code of Cinch and other frameworks, the lead developer thought: if we use the DataObjectBase
published before as the base for a View Model class, it should be possible to create a framework in a very short amount of time.
Then, all other developers of the team he was working on the project got enthusiastic, and then the whole team decided to merge their personal
libraries into one big enterprise library, and Catel was born.
Why use this framework?
Before reading any further, it's important to know why you should use the framework. Below are a few reasons why Catel might be interesting for
you:
Catel is Open-Source. This way, you can customize it any way you want. If you want a new feature request, and the team does not
respond fast enough, you can simply implement it yourself.
The codebase for Catel is available on GitHub. This way, you have the option to either download the latest stable release, or live on the
edge by downloading the latest source code.
Catel uses unit tests to make sure that new updates do not break existing functionality.
Catel is very well documented. Every method and property has comments, and the comments are available in a separate reference help
file. There is also a lot of documentation available, and in the future, in-depth articles will be written.
Catel is developed by a group of talented software developers, and is heavily under development. This is a great advantage because the
knowledge is not at just one person, but at a whole group. The developers of Catel all have more than three years of development
experience with WPF, and are using Catel in real life applications for at least 2 years.
Continue reading
Why Catel?
Platform support explanation
Introduction to data objects
Introduction to MVVM
Introduction to MVC
Why Catel?
We care a lot about the freedom you need as a software developer. Most frameworks require a developer to learn its conventions, or use the
whole framework or nothing at all. When we, the developers of Catel, use an external framework, we choose that framework for a specific reason,
and dont want to be bothered by all the other superb stuff it has to offer (maybe later, but not now).
During the development of Catel, we tried to maintain this freedom aspect which is very important to us. Therefore, all functionality is loosely
coupled. Sounds great, but everything is called loosely coupled nowadays. Catel contains a lot of different aspects, such as logging, diagnostics,
Reflection, MVVM, user controls, windows, etc. All these aspects are complementary to each other, but the great thing about Catel is that you
decide whether to use just one, some, or maybe all aspects.
As an example: you have a legacy application and want to use the DataWindow to write simple entry windows, but you are not ready for MVVM
yet. No problem, the DataWindow is complementary to MVVM, but does not require it. Therefore, you have all the freedom to use just what you
need, whenever you need it.
Most frameworks require a bootstrapper that completely decides how your application structure should look like. For example, your Views must
have this name, your controls must have that name. Again, in Catel, we wanted to give you the freedom you would expect from a framework.
The great thing about this freedom is that the different aspects of Catel can be used side-by-side with other frameworks, so you as a developer
can use the best framework for every aspect in your application.
Another nice thing is that Catel is WPF-based. Now you might be thinking: but hey, I use Silverlight! However, the upside of this approach is that
all goodies that are well known in WPF, but not in Silverlight are also brought to Silverlight. For example, in Silverlight there is no automatic
command re-evaluation. Catel does this out of the box, even in Silverlight.
Catel offers a solution in the following fields:
Data handling
MVVM
And much more which you will find out during the use of Catel!
Platform support explanation
This page explains in detail what parts of Catel are available on specific platforms.

NET40 NET45 SL4 SL5 WP7.8 WP8 WIN80 WIN81 PCL


Catel.Core
Catel.MVV
M
Catel.Mvc

Catel.Exte
nsions.Co
ntrols
Catel.Exte
nsions.CS
LA
Catel.Exte
nsions.Da
ta
Catel.Exte
nsions.En
tityFrame
work5
Catel.Exte
nsions.Flu
entValidat
ion
Catel.Exte
nsions.Int
erception
Catel.Exte
nsions.Me
mento
Catel.Exte
nsions.Pri
sm
Introduction to data objects
It is very important to understand the data objects in Catel because they form the base pillar of all components used by the MVVM framework.
The ObservableObject class
The ModelBase class
1.
2.
Creating your first data object
Declaring properties
Simple properties
Properties with property change callback
Adding validation
Saving objects
Loading an object
Saving an object
The ObservableObject class
The ModelBase class
Creating your first data object
First of all, it is very important to realize that you shouldn't bore yourself with writing all the code below yourself. Catel contains lots of code
snippets that allow you to create data objects very easily in a short amount of time.
This example shows the simplest way to declare a data object using the class. By using a code snippet, the class is created in just 10 ModelBase
seconds.
Code snippets
model - Declares a data object based on the class ModelBase
Steps
Create a new class file called . FirstModel.cs
Inside the namespace, use the codesnippet and fill in the name of the class, in this case . model FirstModel
Code
This documentation is to be written in the future
This documentation is to be written in the future
/// <summary>
/// FirstModel class which fully supports serialization, property changed
notifications,
/// backwards compatibility and error checking.
/// </summary>
[Serializable]
public class FirstModel : ModelBase
{
#region Fields
#endregion
#region Constructors
/// <summary>
/// Initializes a new object from scratch.
/// </summary>
public FirstModel()
{ }
/// <summary>
/// Initializes a new object based on <see cref="SerializationInfo"/>.
/// </summary>
/// <param name="info"><see cref="SerializationInfo"/> that contains the
information.
/// </param>
/// <param name="context"><see cref="StreamingContext"/>.</param>
protected FirstModel(SerializationInfo info, StreamingContext context)
: base(info, context) { }
#endregion
#region Properties
// TODO: Define your custom properties here using the propdata code snippet
#endregion
#region Methods
/// <summary>
/// Validates the field values of this object. Override this method to enable
/// validation of field values.
/// </summary>
/// <param name="validationResults">The validation results, add additional results
to this list.</param>
protected override void ValidateFields(List<FieldValidationResult>
validationResults)
{
}
/// <summary>
/// Validates the field values of this object. Override this method to enable
/// validation of field values.
/// </summary>
/// <param name="validationResults">The validation results, add additional results
to this list.</param>
protected override void ValidateBusinessRules(List<BusinessRuleValidationResult>
validationResults)
{
}
#endregion
}
1.
2.
1.
2.
Declaring properties
The next step to learn on the class is how to declare properties. There are several types of properties, and they will all be handled in ModelBase
this part of the documentation.
The class uses a dependency property a-like notation of properties. ModelBase
Simple properties
This example shows how to declare the simplest property. In this example, a string property with a default value will be declared with the use of a
code snippet.
Code snippets
modelprop - Declares a simple property on a model
Steps
Open created in the previous step. FirstModel.cs
In the Properties region, use the code snippet , and use the following values: modelprop
Code snippet item Value
description Gets or sets the simple property
type string
name SimpleProperty
defaultvalue "Simple property"
Code
/// <summary>
/// Gets or sets the simple property.
/// </summary>
public string SimpleProperty
{
get { return GetValue<string>(SimplePropertyProperty); }
set { SetValue(SimplePropertyProperty, value); }
}
/// <summary>
/// Register the SimpleProperty property so it is known in the class.
/// </summary>
public static readonly PropertyDataSimplePropertyProperty =
RegisterProperty("SimpleProperty", typeof(string), "Simple property");
Properties with property change callback
Code snippets
modelpropchanged - Declares a simple property on a model with a property changed callback
Steps
Open created in the previous step. FirstModel.cs
In the Properties region, use the code snippet , and use the following values: modelpropchanged
Code snippet item Value
description Gets or sets the callback property
type string
name CallbackProperty
defaultvalue "Callback property"
Code
/// <summary>
/// Gets or sets the callback property.
/// </summary>
public string CallbackProperty
{
get { return GetValue<string>(CallbackPropertyProperty); }
set { SetValue(CallbackPropertyProperty, value); }
}
/// <summary>
/// Register the CallbackProperty property so it is known in the class.
/// </summary>
public static readonly PropertyDataCallbackPropertyProperty =
RegisterProperty("CallbackProperty", typeof(string), "Callback property",
(sender, e) => ((FirstDataObject)sender).OnCallbackPropertyChanged());
/// <summary>
/// Called when the CallbackProperty property has changed.
/// </summary>
private void OnCallbackPropertyChanged()
{
// TODO: Implement logic
}
Adding validation
It is very easy to add validation to a class (both the and ). There are several ways, but this getting started guide will ModelBase ViewModelBase
handle only the most simple one.
To enable validation, you must override at least one of the following methods:
1.
2.
3.
4.
/// <summary>
/// Validates the field values of this object. Override this method to enable
/// validation of field values.
/// </summary>
/// <param name="validationResults">The validation results, add additional results to
this list.</param>
protected override void ValidateFields(List<FieldValidationResult> validationResults)
{
if (string.IsNullOrEmpty(FirstName))
{
validationResults.Add(FieldValidationResult.CreateError(FirstNameProperty,
"First name cannot be empty"));
}
}
/// <summary>
/// Validates the field values of this object. Override this method to enable
/// validation of field values.
/// </summary>
/// <param name="validationResults">The validation results, add additional results to
this list.</param>
protected override void ValidateBusinessRules(List<BusinessRuleValidationResult>
validationResults)
{
if (SomeBusinessErrorOccurs)
{
validationResults.Add(BusinessRuleValidationResult.CreateError("A business
error occurred"));
}
}
After the validation is implemented into the object, the validation will occur every time a property on the object changes. It is also possible to
manually validate by calling the Validate method.
There are also other ways to add validation to a data object:
Validation via data annotations - attributes such as the RequiredAttribute
Validation via - custom validation such as IValidator FluentValidation
The great thing is that Catel will gather all validation results from all different mappings and combine these into the . This context ValidationContext
can be used to query all sorts of validation info about an object.
Saving objects
Saving and loading objects out of the box has never been so easy. can automatically save/load objects in several ways, such SavableModelBase
as memory, file in different modes (binary and XML). This example shows that making your objects savable is very easy and does not take any
time!
Code snippets
model - Declare a model based on the class ModelBase
modelprop - Declare a simple property on a model
Steps
Create a new class file called . Person.cs
Inside the namespace, use the codesnippet and fill in the name of the class, in this case . model Person
Change the base class from to . ModelBase SavableModelBase
In the Properties region, use the code snippet , and use the following values: modelprop
Note that this is just an introduction, more information about validation can be found in other parts of the documentation
Code snippet item Value
description Gets or sets the name
type string
name Name
defaultvalue "MyName"
Code
/// <summary>
/// Person class which fully supports serialization, property changed notifications,
/// backwards compatibility and error checking.
/// </summary>
[Serializable]
public class Person : SavableModelBase<Person>
{
#region Fields
#endregion
#region Constructors
/// <summary>
/// Initializes a new object from scratch.
/// </summary>
public Person()
{ }
/// <summary>
/// Initializes a new object based on <see cref="SerializationInfo"/>.
/// </summary>
/// <param name="info"><see
/// cref="SerializationInfo"/> that contains the information.
/// </param>
/// <param name="context"><see
// cref="StreamingContext"/>.</param>
protected Person(SerializationInfo info, StreamingContext context)
: base(info, context) { }
#endregion
#region Properties
/// <summary>
/// Gets or sets the name.
/// </summary>
public string Name
{
get { return GetValue<string>(NameProperty); }
set { SetValue(NameProperty, value); }
}
/// <summary>
/// Register the Name property so it is known in the class.
/// </summary>
public static readonly PropertyData NameProperty = RegisterProperty("Name",
typeof(string), "MyName");
#endregion
#region Methods
#endregion
}
Loading an object
Loading an object is really simple once the class has been created. It is important to use the static method on the class:
var person = Person.Load(@"c:\person.dob");
Saving an object
To save an object, an instance is required. Then simply call the method. Save
var person = new Person();
person.Name = "John Doe";
person.Save(@"c:\person.dob");
Introduction to MVVM
This part gives an introduction to MVVM in Catel.
MVVM framework comparison sheet
Different interpretations of MVVM
Validation in model or view model?
Introduction to MVVM and models
Creating view models with Catel
Introduction to services
Introduction to the nested user controls problem
Introduction to unit testing in MVVM
MVVM framework comparison sheet
In this MVVM framework comparison sheet includes as many aspects as possible. However, it might be possible that some were missed. If you
have features that are not included in the comparison sheet, or you find that information is incorrect, please let us know!
Below is short list of definitions:
Definition Explanation
VM View-Model
Frameworks reviewed
Framework Description Website
Catel Catel is more than just an MVVM toolkit. It
also includes user controls and lots of
enterprise library classes. The MVVM toolkit
differs itself from other frameworks of the
simplicity and solves the "nested user
control" problem with dynamic viewmodels
for user controls
http://catel.codeplex.com
Caliburn.Micro A small, yet powerful implementation of
Caliburn designed for WPF, Silverlight and
WP7. The framework implements a variety of
UI patterns for solving real-world problems.
Patterns that are enabled include MVC,
MVP, Presentation Model (MVVM), and
Application Controller.
http://caliburnmicro.codeplex.com
Cinch (V2) Cinch is a MVVM framework that exposes a
number of helper classes to allow the
developer to quickly get to grips with creating
scalable testable MVVM frameworks as
quickly as possible.
http://cinch.codeplex.com
MVVM light The MVVM Light Toolkit is a set of
components helping people to get started in
the Model - View - ViewModel pattern in
Silverlight and WPF. It is a light and
pragmatic framework that contains only the
essential components needed.
http://mvvmlight.codeplex.com
This comparison sheet is last updated on September 4th, 2012
Simple MVVM toolkit Simple MVVM Toolkit makes it easier to
develop Silverlight, WPF and WP7
applications using the
Model-View-ViewModel design pattern. The
purpose of the toolkit is to provide a simple
framework and set of tools for getting up to
speed quickly with applications based on the
MVVM design pattern. The emphasis is on
simplicity, but it contains everything you need
to implement MVVM for real-world line of
business applications.
http://simplemvvmtoolkit.codeplex.com/
WAF The WPF Application Framework (WAF) is a
lightweight Framework that helps you to
create well structured WPF Applications. It
supports you in applying a Layered
Architecture and the Model-View-ViewModel
(aka MVVM, M-V-VM, PresentationModel)
pattern.
http://waf.codeplex.com/
Platform support
Catel Caliburn.Micro Cinch (V2) MVVM light Simple MVVM WAF
WPF
Silverlight 4
Silverlight 5
Windows Phone
7
Windows Phone
8
WinRT
Available via
NuGet
UI features
Catel Caliburn.Micro Cinch (V2) MVVM light Simple MVVM WAF
MVVM specific
window
MVVM specific
user control
Dynamic view
model injection
Lazy loading of
view models
View to VM
communication
via attributes
Events when
views are
actually loaded
ViewModelBase functionality
Catel Caliburn.Micro Cinch (V2) MVVM light Simple MVVM WAF
INotifyProperty
Changed
IDataErrorInfo
IDataWarningInf
o
Support for
canceling data
Support for
confirming data
Automatic
property
definitions
Automatic
model
communication
s (mappings)
Generate features
Catel Caliburn.Micro Cinch (V2) MVVM light Simple MVVM WAF
Communication
with other VM
via messenger
Communication
with other VM
via attributes
RelayCommand
/
DelegateComm
and
EventToComma
nd trigger
IoC container
support
Unity support
MEF support
Background
task manager
ViewModelMana
ger with live VM
instances
Project and item
templates
Design time
example data
support
Memento
pattern
View model services
Catel Caliburn.Micro Cinch (V2) MVVM light Simple MVVM WAF
IMessage(Box)S
ervice
INavigationServ
ice
IOpenFileServic
e
IPleaseWaitServ
ice
IProcessService
ISaveFileServic
e
IUIVisualizerser
vice
Unit test
versions of
services
Windows Phone specific view model services
Catel Caliburn.Micro Cinch (V2) MVVM light Simple MVVM WAF
IAccelerometer
Service
ICameraService
ICompassServi
ce
IGyroscopeServ
ice
ILocationServic
e
INavigationServ
ice
IVibrateService
Different interpretations of MVVM
There are two different interpretations of MVVM, the "purist" way where the model is protected, or the "shortcut" way where the view model only
provides the instance of the model and the view then binds directly to the model.
Shortcut interpretation
This is what most people do. The view model once implements the model, and then provides the model to the view. The view then
Advantages
Easy to use
Fast since view model hardly contains any properties
Disadvantages
Always need to bind to Model.[PropertyName], but for view model properties it's just [PropertyName], might be confusing
Less control over validation (you cannot insert logic between View <=> Model where MVVM is all about
Purist interpretation
This is what the developers of Catel strongly believe in. It requires a bit more code, but gives great freedom and control and protection of the
model because all bindings go through the view model.
Advantages
Full contol and freedom, you can inject both logic and validation between view and model (what MVVM is actually about)
Everything is available on the view model, no need for "sub-bindings" (such as Model.[PropertyName])
Protection of your model from the view
Disadvantages
Needs a bit more code (but thanks to code snippets and the Expose attribute, this is not a big disadvantage)
Validation in model or view model?
I have had lots of discussion whether the validation should take place in the model or the view model. Some people think that the validation
should always occur inside the model because you dont want to persist invalid models to the persistence store. Others say that the models itself
dont need validation, but the state the view model is in requires the validation. I think both are true, and I will tell you why.
First of all, you dont want invalid models in your persistence store. Thus, the most basic checks such as type, ranges and required fields should
be validated in the model. But sometimes, it is required to restrict the user more than the model does, and thats where validation in the view
model comes in handy. Another reason why you want to implement (a part of) the validation in the view model is the state of the model inside a
workflow. If you have a workflow that updates the model step by step, the model isnt valid after the first step in the workflow. However, you
already want to persist the model because the user might decide to execute the following steps at a later time. You dont want to implement the
state logic of a workflow in your model (and if you did that, get rid of it, as soon as possible). This is another feature where the view model
validation comes in handy.
The good news is that with Catel, it doesnt matter what you want, because its all possible. If you want your model to do all the validation, then
this is possible using the Model and ViewModelToModel attributes which map the values of the properties and the errors directly to the model so
the view model acts as a proxy between the view and the model. If you want to do all of the validation inside the view model, then you can
implement the ValidateFields and ValidateBusinessRules methods in the view model. And, if you want the best of both worlds, such as me, than
you can use a combination of the techniques described above.
Introduction to MVVM and models
This part of the documentation will explain all the parts of MVVM, in the order in which we think they must be built. First of all, the Models, which
are the closest to the business. Then, the View Models which define what part of the Models should be visible to the user in a specific situation.
This also includes validation that is specific for the functionality that the View Model represents. Last, but not least, the View itself, which is the
final representation of the View Model to the end-user.
As you will notice (or maybe you don't), this framework has a lot in common with other MVVM frameworks out there. This is normal because all of
the frameworks are trying to implement the same pattern, which isn't that hard to understand if you think about it long enough. Before we started
writing the MVVM framework, we first investigated other frameworks because there already are enough, probably too many. However, even the
better (or best) still took too much time to use, and there was too much code we had to write to create a View Model. That's the point where we
decided to write our own framework that contains lots of luxury for lazy developers such as us.
Models
The Models part is one of the three major parts of MVVM. Therefore, I want to tell you a bit about what kind of Models we use to store our data.
Basically, you can use all types of objects as Models, as long as the Models implement the most commonly used interfaces required by WPF or
Silverlight.
For MVVM, it is very important that the following interfaces are implemented:
INotifyPropertyChanged
If this interface is not implemented, changes will not be reflected to the UI via bindings. In other words, your Model and View Model will
be useless in an MVVM setting.
Finally, it is strongly recommended to have your Models implement the following interfaces as well:
IDataErrorInfo
If this interface is not implemented, errors cannot be shown to the user.
IEditableObject
If this interface is not implemented, a Model cannot work with states. This means that a user cannot start editing an object and finally
cancel it (because there is no stored state that can be used to restore the values).
View Models
View models are the classes that contain the view logic. They can be seen as a container for all models in a specific view, including the behavior
to interact with these models (for example adding or removing them from a collection). It is very important that a view model also implements the I
interfaces just like the models do. NotifyPropertyChanged
Creating view models with Catel
The View Models in Catel are very easy to write, and give the end-user a great flexibility in how to approach the Models. This part of the article will
explain the classes that make it possible to easily create View Models.
The class is the most important class of all in the MVVM Framework of Catel. Of course, it can't do anything useful without the ViewModelBase
other classes, but all the View Models that are created using Catel derive of this class. is based on the class that ViewModelBase ModelBase
ships with Catel. Thanks to the existence of that class, the MVVM framework was set up very quickly (although very quickly is relative). Below is
a class diagram that shows the class tree:
The class diagram above shows how many default interfaces of the .NET Framework are supported in the class. Since most of these ModelBase
interfaces are used by WPF as well, the class itself can take huge advantage of the implementation of . ViewModelBase ModelBase
Because derives from , you can declare properties exactly the same way. Even better, you can simply use ViewModelBase ModelBase ModelBas
(or the extended ) to create (and save) your Models, and use as the base for all the View Models. e SavableModelBase ViewModelBase
Creating a view model
To declare a View Model, use the following code snippet:
vm - defines a new view model
When using the code snippet, this is the result: vm
/// <summary>
/// $name$ view model.
/// </summary>
public class $name$ViewModel : ViewModelBase
{
#region Fields
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="$name$ViewModel"/> class.
/// </summary>
public $name$ViewModel ()
{
}
#endregion
#region Properties
/// <summary>
/// Gets the title of the view model.
/// </summary>
/// <value>The title.</value>
public override string Title { get { return "View model title"; } }

// TODO: Register models with the vmpropmodel codesnippet
// TODO: Register view model properties with the vmprop or vmpropviewmodeltomodel
codesnippets
#endregion
#region Commands
// TODO: Register commands with the vmcommand or vmcommandwithcanexecute
codesnippets
#endregion

#region Methods
#endregion
}
Declaring properties
There are several code snippets available to create View Model properties:
vmprop - Defines a simple View Model property.
vmpropmodel - Defines a View Model property with . The property is also made private by default. ModelAttribute
vmpropviewmodeltomodel - Defines a View Model property with . ViewModelToModelAttribute
When using the code snippet, this is the result: vmprop
Note that declaring properties works exactly the same as declaring properties for the ModelBase
/// <summary>
/// Gets or sets the name.
/// </summary>
public string Name
{
get { return GetValue<string>(NameProperty); }
set { SetValue(NameProperty, value); }
}
/// <summary>
/// Register the Name property so it is known in the class.
/// </summary>
public static readonly PropertyData NameProperty = RegisterProperty("Name",
typeof(string));
In the View, it is now possible to bind to the property of the View Model, as long as is set to an instance of the View Model. Name DataContext
Declaring commands
There are several code snippets available to create View Model commands:
vmcommand - Defines a command that is always executable.
vmcommandwithcanexecute - Defines a command that implements a method to determine whether the command can be CanExecute
invoked on the View Model in its current state.
When using the code snippet, this is the result: vmcommandwithcanexecute
/// <summary>
/// Gets the Add command.
/// </summary>
public Command<object, object> Add { get; private set; }
// TODO: Move code below to constructor
Add = new Command<object, object>(OnAddExecute, OnAddCanExecute);
// TODO: Move code above to constructor
/// <summary>
/// Method to check whether the Add command can be executed.
/// </summary>
/// <param name="parameter">The parameter of the command.</param>
private bool OnAddCanExecute(object parameter)
{
return true;
}
/// <summary>
/// Method to invoke when the Add command is executed.
/// </summary>
/// <param name="parameter">The parameter of the command.</param>
private void OnAddExecute(object parameter)
{
// TODO: Handle command logic here
}
The only thing left to do now is to move the creation of the command to the constructor (as the comments already instructs you to).
In the View, it is now possible to bind any property (such as the property of a ) to the property of the View Model, Command Command Button Add
as long as DataContext is set to an instance of the View Model.
Adding validation
Because the class derives from , it provides the same power of validation that the class has to offer. ViewModelBase ModelBase ModelBase Mode
(and thus ) offers the following types of validation: lBase ViewModelBase
Field warnings
Business warnings
Field errors
Business errors
ViewModelBase uses smart validation. This means that if the object is already validated, the object is not validated again to make sure that the
View Models don't hit too much on the performance. Only when a property on the View Model changes, validation will be invoked. Of course, if
required, it is still possible to force validation when the View Model must be validated, even when no properties have changed.
To implement field or business rule validation, you only have to override and/or the method: ValidateFields ValidateBusinessRules
/// <summary>
/// Validates the field values of this object. Override this method to enable
/// validation of field values.
/// </summary>
/// <param name="validationResults">The validation results, add additional results to
this list.</param>
protected override void ValidateFields(List<FieldValidationResult> validationResults)
{
if (!string.IsNullOrEmpty(FirstName))
{
validationResults.Add(FieldValidationResult.CreateError(FirstNameProperty,
"First name cannot be empty"));
}
}
/// <summary>
/// Validates the field values of this object. Override this method to enable
/// validation of field values.
/// </summary>
/// <param name="validationResults">The validation results, add additional results to
this list.</param>
protected override void ValidateBusinessRules(List<BusinessRuleValidationResult>
validationResults)
{
if (SomeBusinessErrorOccurs)
{
validationResults.Add(BusinessRuleValidationResult.CreateError("A business
error occurred"));
}
}
There are also other ways to add validation to a data object:
Validation via data annotations - attributes such as the RequiredAttribute
Validation via - custom validation such as IValidator FluentValidation
The great thing is that Catel will gather all validation results from all different mappings and combine these into the . This context ValidationContext
can be used to query all sorts of validation info about an object.
Interaction with models
Note that it is also possible to re-use validation in a model using mappings or even external validation such as ModelToViewModel Flue
ntValidation
One of the most important reasons why a View Model is created is because it serves as the glue between a View and the Model. The
communication between the View and the View Model is fully taken care of by WPF in the form of Bindings. The problem is that most of the time,
a View Model is used to show a subset of a Model (which is, for example, a database entity).
Most MVVM frameworks (actually, I haven't seen anyone not requiring manual updating) require manual updating, which brings us back to the
stone age (remember the WinForms time setting the controls at startup, and reading the values at the end?). Catel solves this issue by providing
convenience attributes that take care of this dumb getting/setting story between the View Model and the Model. Catel fully supports getting/setting
the values from/to the Model, but believe me: you will love the attributes that are described next.
ModelAttribute
To be able to map values from/to a Model, it is important to know the actual Model. So, to let the View Model know what property represents the
Model, can be used like shown below: ModelAttribute
/// <summary>
/// Gets or sets the person.
/// </summary>
[Model]
public Person Person
{
get { return GetValue<Person>(PersonProperty); }
private set { SetValue(PersonProperty, value); }
}
/// <summary>
/// Register the Person property so it is known in the class.
/// </summary>
public static readonly PropertyData PersonProperty = RegisterProperty("Person",
typeof(Person));
A Model setter is normally written as private (you normally don't want a UI to be able to change a Model), but the getter is public because you
might want to read info from it.
Models in Catel are handled as very, very special objects. This means that as soon as a Model is set, Catel tries to call the IEditableObject.Begin
method. Then, as soon as the Model is changed without being saved, or if the View Model is canceled, the Model is correctly canceled via Edit IE
. If the Model is saved, the active Models will be committed via . I will leave the rest of the magic ditableObject.CancelEdit IEditableObject.EndEdit
out of this article, but if you have any questions about it, don't hesitate to contact us!
ViewModelToModelAttribute
Now that we know how to declare a property has a Model, it is time to learn how we can communicate with it. Normally, you would have to watch
the Model to make sure it is synchronized correctly when the Model is updated. With Catel, this is not necessary any longer. Simply use ViewMod
, and you will get the following advantages: elToModelAttribute
Models are automatically being watched for changes, thus if a mapped property changes, the View Model is updated accordingly;
When a View Model is changed, this property is automatically mapped to the Model;
When the Model changes, the View Model is initialized automatically with the values of the new Model;
When a Model has an error or warning (business or field), the warnings are mapped to the View Model so you can re-use the validation
of the Model inside your View Model.
So, you get all of this for free? No, you will have to decorate your property with , like shown below: ViewModelToModelAttribute
Note that you should use the code snippet to create Model properties vmpropmodel
/// <summary>
/// Gets or sets the first name.
/// </summary>
[ViewModelToModel("Person")]
public string FirstName
{
get { return GetValue<string>(FirstNameProperty); }
set { SetValue(FirstNameProperty, value); }
}
/// <summary>
/// Register the FirstName property so it is known in the class.
/// </summary>
public static readonly PropertyData FirstNameProperty = RegisterProperty("FirstName",
typeof(string));
The code example is the easiest usage of the attribute that is available. It only provides the name of the Model property. This is required because
it is possible (but not likely) to have multiple Models. But what if the property on your Model has a different name than your View Model? No
problem, use the overload of the attribute as shown below:
[ViewModelToModel("Person", "RealFirstName")]
public string FirstName
///... (remaining code left out for the sake of simplicity)
The code above will map the property of the View Model to the property of the Person model. FirstName RealFirstName
ExposeAttribute
The is a great way to map properties between the model and the view model. However, sometimes the mappings are ViewModelToModelAttribute
not required for manual coding and should only be exposed from inside the view model to the view. The is great way to simplify ExposeAttribute
this process. The code below is the same as declaring a model property named Person and 3 additional properties using the ViewModelToModel
: Attribute
/// <summary>
/// Gets or sets the person.
/// </summary>
[Model]
[Expose("FirstName")]
[Expose("MiddleName")]
[Expose("LastName")]
private Person Person
{
get { return GetValue<Person>(PersonProperty); }
set { SetValue(PersonProperty, value); }
}
/// <summary>
/// Register the Person property so it is known in the class.
/// </summary>
public static readonly PropertyData PersonProperty = RegisterProperty("Person",
typeof(Person));
This feature is only available in WPF because Silverlight does not provide the or an equivalent feature ICustomTypeDescriptor
Interaction with other view models
Now that we've seen how easy it is to communicate between the View Model and the Model, you want more, right? I know how it is: You let 'em
have one finger, they take your whole hand. No worries, you can have my right hand, as long as I can keep my left one. Anyway, the developers
of Catel are prepared for this. So, let's talk about the interaction with other View Models.
Say, you have a multiple document interface (MDI as it was called in the old days). If you are following MVVM principles, every document (or tab)
has its own View Model. Then, you want to be aware of updates of a single type of View Model. Say, for example, that there is a View Model
representing a family called . This View Model is probably interested in changes in the . FamilyViewModel PersonViewModel
ViewModelManager
Let's start with the basics. As we have learned earlier in this article, all View Models created with the help of Catel derive from the ViewModelBase
class. One of the things that this class does is that it registers itself with the class when it is being created, and it unregisters ViewModelManager
itself again when it is closed. So, simply said, is a class that holds a reference to all existing View Models at the moment. ViewModelManager
InterestedInAttribute
Now that we know about the class, and know that there is a repository that holds all of the live instances of all View Model ViewModelManager
classes, it should be fairly easy to communicate with other View Models. It actually is; you just have to decorate a View Model with InterestedInAtt
, as shown below: ribute
[InterestedIn(typeof(FamilyViewModel))]
public class PersonViewModel : ViewModelBase
A View Model can have multiple instances, so it is possible to subscribe to multiple View Model types at the same time. Once InterestedInAttribute
a View Model is decorated with , the View Model will receive all changes (and of course, the View Model that caused the InterestedInAttribute
change) via the method, as shown below: OnViewModelPropertyChanged
/// <summary>
/// Called when a property has changed for a view model type that the current view
model is interested in. This can
/// be accomplished by decorating the view model with the <see
cref="InterestedInAttribute"/>.
/// </summary>
/// <param name="viewModel">The view model.</param>
/// <param name="propertyName">Name of the property.</param>
protected override void OnViewModelPropertyChanged(IViewModel viewModel, string
propertyName)
{
// You can now do something with the changed property
}
MessageMediator
Catel also offers a solution to the message mediator pattern in the form of the class. This is all described in the next section MessageMediator
"Message mediator".
Introduction to services
Services are very important in MVVM. They define a way to interact with the user without using fixed controls such as or MessageBox SaveFileDi
. The interfaces defined in Catel only define generic functionality of what to expect from a specific service. Using services is a great way to alog
abstract away all specific functionality from a view model into a service that can be mocked during unit testing and can be used by other view
models as well.
ServiceLocator
The key behind services is the . The is the IoC (Inversion of Control) container that Catel provides. This is a ServiceLocator ServiceLocator
Note that it is also possible to get notified of commands that are being executed on other view models
container that contains all registrations and service instances available throughout the application. Retrieving services from the defaultServiceLoc
in Catel is very simple: ator
var dependencyResolver = this.GetDependencyResolver();
var messageService = dependencyResolver.Resolve<IMessageService>();
Dependency injection
A slightly better way to manage dependencies is to use dependency injection. The reason is that to instantiate a class, you always have to
provide all the dependencies. This way, all dependencies are always known to the caller which gives is a bit easier to control than having to know
what services are being used by a component (such as a view model).
Catel fully supports dependency on view models. This means that a view model can have a constructor with several services. Catel will
automatically inject the services via the constructor. An example is below:
public class PersonViewModel : ViewModelBase
{
private readonly IMessageService _messageService;
private readonly IPleaseWaitService _pleaseWaitService;
public PersonViewModel(IMessageService messageService, IPleaseWaitService
pleaseWaitService)
{
_messageService = messageService;
_pleaseWaitService = pleaseWaitService;
}
}
Overview of services
The services below are available in Catel:
Name Description
IAccelerometerService Allows a developer to access the accelerometer of a Windows Phone
device.
ICameraService Allows a developer to use the PhotoCamera class in an MVVM
manner.
ICompassService Allows a developer to access the compass of a Windows Phone
device.
IGyroscopeService Allows a developer to access the compass of a Windows Phone
device.
ILocationService Allows a developer to use GPS devices inside a view model.
IMessageService Allows a developer to show message boxes from a view model.
INavigationService Allows a developer to navigate to other pages inside an application
using view models only.
IOpenFileService Allows a developer to let the user choose a file from inside a view
model.
IPleaseWaitService Allows a developer to show a please wait message (a.k.a. busy
indicator) from a view model.
IProcessService Allows a developer to run processes from inside a view model.
It is also possible to get services injected into the constructor, which is the recommended approach
ISaveFileService Allows a developer to let the user choose a file from inside a view
model.
IUIVisualizerService Allows a developer to show (modal) windows or dialogs without
actually referencing a specific view.
IVibrateService Allows a developer to start and stop vibration of the device via a
service.
Introduction to the nested user controls problem
One of the issues most users of MVVM face is that nested user controls problem. The problem is that most (actually all that weve seen) MVVM
Frameworks only support one view model for a window (or if youre lucky, a user control). However, the nested user controls problem raises lots
of questions:
What if the requirements are to build a dynamic UI where the nested user controls are loaded dynamically when they are required?
What about validation in nested user controls?
When should the nested user control view models be saved?
Most MVVM developers just answer: Put all the properties of the nested user controls on the main view model. Say that again? Are you kidding
me? Thats not a real world solution for a real world problem. So, we as developers of Catel offer you a real world solution for the nested user
controls problem in the form of the . UserControl
The real power of the class lays in the fact that it is able to construct view models dynamically based on its data context. So, the only UserControl
thing the developers have to take care of is to set the right data context. Below is a graphical presentation of the nested user controls problem:
As the images above show, the method that Catel uses to solve the problem is much more professional. Below are a few reasons:
Separation of concerns (each control has a view model only containing the information for itself, not for children);
User controls are built so they can be re-used. Without the user controls to be able to have their own view models, how should one
actually use user controls with MVVM?
The idea behind the user control is pretty complex, especially because WPF (and thus Silverlight and WP7) isnt very good at runtime data
context type changing. However, with a few workarounds (very well described in the source code of ), it is possible to dynamically UserControl
construct view models. The user control constructs the view model with or without a constructor as described earlier in this article. When the view
model is constructed, the user control tries to find a (logical or visual) parent that implements the interface. Thanks to this IViewModelContainer
interface, a view model can subscribe itself to a parent view model and the validation chain is created as shown below:
Note that this section is not always fully up-to-date, Catel might provide more services than listed here
As the image above shows, all children in the chain are validated, and when the last child is validated, the view model reports the result of its
children and itself back to its parent. This way, it is still possible to disable a command when one of the nested user control view models has an
error.
Saving a chain of nested view models works exactly the same as the validation. First, the view model saves all children, then itself and finally
reports back its result to the parent.
Now, lets go to some real-life example. I dont want to make it too complex, but not too easy as well, but dont want to put the focus on the
content of the data, but on the user control and view model creation. Therefore, I have chosen for the data model below:
The image shows that we have a house. In that house, we have multiple rooms. In each room, there can be several tables with chairs and beds.
This shows a complex UI tree with lots of different user controls (each object has its own representation and thus user control). Now our goal is
to create user controls that can be used in the window that shows the full house, but also in sub-parts and we want to be fully independent of the
(which is the only view model that would be created in a regular MVVM Framework). HouseWindowViewModel
The example below shows only the control and the corresponding view model. The full source code of this article is provided in the source Room
code repository of Catel, so the whole example is available if you are interested or need a more complete example.
First, we start with a simple model. For the model, we use the class. By using the provided code snippets, this model is setup within a ModelBase
minute:
/// <summary>
/// Bed class which fully supports serialization, property changed notifications,
/// backwards compatibility and error checking.
/// </summary>
[Serializable]
public class Room : ModelBase<Room>
{
#region Constructor & destructor
/// <summary>
/// Initializes a new object from scratch.
/// </summary>
public Room()
: this(NameProperty.GetDefaultValue<string>()) { }

/// <summary>
/// Initializes a new instance of the <see cref="Room"/> class.
/// </summary>
/// <param name="name">The name.</param>
public Room(string name)
{
// Create collections
Tables = new ObservableCollection<Table>();
Beds = new ObservableCollection<Bed>();
// Store values
Name = name;
}

/// <summary>
/// Initializes a new object based on <see cref="SerializationInfo"/>.
/// </summary>
/// <param name="info"><see cref="SerializationInfo"/> that contains the
information.</param>
/// <param name="context"><see cref="StreamingContext"/>.</param>
protected Room(SerializationInfo info, StreamingContext context)
: base(info, context) { }
#endregion

#region Properties
/// <summary>
/// Gets or sets the name.
/// </summary>
public string Name
{
get { return GetValue<string>(NameProperty); }
set { SetValue(NameProperty, value); }
}
/// <summary>
/// Register the Name property so it is known in the class.
/// </summary>
public static readonly PropertyData NameProperty = RegisterProperty("Name",
typeof(string), "Room");

/// <summary>
/// Gets or sets the table collection.
/// </summary>
public ObservableCollection<Table> Tables
{
get { return GetValue<ObservableCollection<Table>>(TablesProperty); }
set { SetValue(TablesProperty, value); }
}

/// <summary>
/// Register the Tables property so it is known in the class.
/// </summary>
public static readonly PropertyData TablesProperty = RegisterProperty("Tables",
typeof(ObservableCollection<Table>));

/// <summary>
/// Gets or sets the bed collection.
/// </summary>
public ObservableCollection<Bed> Beds
{
get { return GetValue<ObservableCollection<Bed>>(BedsProperty); }
set { SetValue(BedsProperty, value); }
}

/// <summary>
/// Register the Beds property so it is known in the class.
/// </summary>
public static readonly PropertyData BedsProperty = RegisterProperty("Beds",
typeof(ObservableCollection<Bed>));
#endregion
}
Next, we are going to create the view model. Again, by the use of code snippets explained earlier in this article, the view model is set up within a
few minutes:
/// <summary>
/// Room view model.
/// </summary>
public class RoomViewModel : ViewModelBase
{
#region Variables
private int _bedIndex = 1;
private int _tableIndex = 1;
#endregion
#region Constructor & destructor
/// <summary>
/// Initializes a new instance of the <see cref="RoomViewModel"/> class.
/// </summary>
public RoomViewModel(Models.Room room)
{
// Store values
Room = room;
// Create commands
AddTable = new Command(OnAddTableExecuted);
AddBed = new Command(OnAddBedExecuted);
}
#endregion
#region Properties
/// <summary>
/// Gets the title of the view model.
/// </summary>
/// <value>The title.</value>
public override string Title { get { return "Room"; } }
#region Models
/// <summary>
/// Gets or sets the room.
/// </summary>
[Model]
public Models.Room Room
{
get { return GetValue<Models.Room>(RoomProperty); }
private set { SetValue(RoomProperty, value); }
}
/// <summary>
/// Register the Room property so it is known in the class.
/// </summary>
public static readonly PropertyData RoomProperty = RegisterProperty("Room",
typeof(Models.Room));
#endregion
#region View model
/// <summary>
/// Gets or sets the name.
/// </summary>
[ViewModelToModel("Room")]
public string Name
{
get { return GetValue<string>(NameProperty); }
set { SetValue(NameProperty, value); }
}
/// <summary>
/// Register the Name property so it is known in the class.
/// </summary>
public static readonly PropertyData NameProperty = RegisterProperty("Name",
typeof(string));
/// <summary>
/// Gets or sets the table collection.
/// </summary>
[ViewModelToModel("Room")]
public ObservableCollection<Models.Table> Tables
{
get { return GetValue<ObservableCollection<Models.Table>>(TablesProperty); }
set { SetValue(TablesProperty, value); }
}
/// <summary>
/// Register the Tables property so it is known in the class.
/// </summary>
public static readonly PropertyData TablesProperty = RegisterProperty("Tables",
typeof(ObservableCollection<Models.Table>));
/// <summary>
/// Gets or sets the bed collection.
/// </summary>
[ViewModelToModel("Room")]
public ObservableCollection<Models.Bed> Beds
{
get { return GetValue<ObservableCollection<Models.Bed>>(BedsProperty); }
set { SetValue(BedsProperty, value); }
}
/// <summary>
/// Register the Beds property so it is known in the class.
/// </summary>
public static readonly PropertyData BedsProperty = RegisterProperty("Beds",
typeof(ObservableCollection<Models.Bed>));
#endregion
#endregion
#region Commands
/// <summary>
/// Gets the AddTable command.
/// </summary>
public Command AddTable { get; private set; }
/// <summary>
/// Method to invoke when the AddTable command is executed.
/// </summary>
private void OnAddTableExecuted()
{
Tables.Add(new Models.Table(string.Format("Table {0}", _tableIndex++)));
}
/// <summary>
/// Gets the AddBed command.
/// </summary>
public Command AddBed { get; private set; }
/// <summary>
/// Method to invoke when the AddBed command is executed.
/// </summary>
private void OnAddBedExecuted()
{
Beds.Add(new Models.Bed(string.Format("Bed {0}", _bedIndex++)));
}
#endregion
}
As you can see, the view model can only be constructed by passing a model object. It is very important to be aware of this construction. Room
The reason that there is no empty constructor is because there is no support for views that do not represent a model. Room
In the view model, the properties of the Room model are mapped by the use of the attribute and the attribute. Last but Model ViewModelToModel
not least, commands are defined to be able to add new tables and beds to the model. Room
Now the model and the view model are fully set up, the last thing to do is to create the actual view. To accomplish this, add a new WPF user
control to the project. First thing to do is to implement the code-behind, since that is the easiest to do:
<summary>
/// Interaction logic for Room.xaml
/// </summary>
public partial class Room : UserControl
{
/// <summary>
/// Initializes a new instance of the <see cref="Room"/> class.
/// </summary>
public Room()
{
// Initialize component
InitializeComponent();
}
}
The only thing we changed from the default user control template is that the user control now derives from the generic control instead UserControl
of the default control. Then, the view model that the user control should use is provided as generic System.Windows.Controls.UserControl
argument. This is it for the code-behind, lets move up to the view.
The last thing to do now is the actual xaml view. For the sake of simplicity, the actual content is left out (its just a grid with a textbox and
itemscontrols for the children):
<catel:UserControl
x:Class="Catel.Articles._03___MVVM.Examples.NestedUserControls.Room"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:catel="http://catel.codeplex.com"

xmlns:NestedUserControls="clr-namespace:Catel.Articles._03___MVVM.Examples.NestedUserC
ontrols">
<!-- For the sake of simplicity, the content is left out -->
</catel:UserControl>
A few things are very important to notice in the xaml code shown above. The first thing to notice is that (like the code-behind), the base class is
now instead of . catel:UserControl UserControl
Thats all that can be learned about solving the nested user control problem. We have set up the model, view model and finally the view. Now,
lets take a look at how it looks in a screenshot (and notice the construction time of the view model, they are really constructed on-demand):
Another way to add a new user control is to use the item templates
The red border is the control that we just created. It shows the name of the room, the view model construction time and the child objects (inside
expanders).

1.
2.
3.
Introduction to unit testing in MVVM
If you are wondering why you should even write unit tests, you should also wonder why you arent still living in a cage and writing stuff on the
walls (don't feel offended, continue reading...). Writing unit tests makes sure that you dont break existing functionality in an application when
making changes. This lowers the cost of QA (since you dont need a technical tester executing regression tests all the time). I dont say that a
tester isnt needed; my opinion is that at least someone else besides the developer should take a human look at the software before it is even
released. If you are still not convinced why you should write unit tests, please go back to your cave and stop reading this article for the sake of
your own pleasure.
This documentation does not cover the basics of unit testing. It assumes that you already know what unit tests are, and how to write them. This
documentation is specifically written to explain how view models of the MVVM pattern can be unit tested,especially with the use of Catel.
Testing commands
Thanks to commands (which implement the interface), testing view models and UI logic has never been so easy. Now commands can ICommand
be invoked programmatically without having to automate the UI; it is very simple to reproduce a button click during a unit test.
When testing commands, it is very important to test the state as well. The command implementation of Catel has a and an CanExecute Execute
method which can be invoked manually. Therefore, it is very easy to test a command. The code below shows a test that checks whether the Rem
command can be executed. At first, the command cannot be executed because there is no selected person. After the selected person is set, ove
the command should be able to execute:
Assert.IsFalse(mainWindowViewModel.Remove.CanExecute(null));
mainWindowViewModel.SelectedPerson = mainWindowViewModel.PersonCollection[0];
Assert.IsTrue(mainWindowViewModel.Remove.CanExecute(null));
To execute a command in code, one should use the following code:
mainWindowViewModel.Remove.Execute(null);
Testing services
For more information about unit testing services, see the unit testing services documentation.
Introduction to MVC
FAQ
Welcome to the FAQ. Please pick a section:
General
MVVM
General
I want to change the bitmap effects, what should I do?
StyleHelper.CreateStyleForwardersForDefaultStyles does not work in Silverlight
I want to change the bitmap effects, what should I do?
Download the DirectX SDK
Compile the .fx file into a .ps file using the following command: "$(DXSDKDIR)Utilities\Bin\x86\fxc.exe" /T ps2_0 /E main /Fo
"MyEffect.ps" "MyEffect.fx"
Now, the fx file is updated and Catel should be recompiled
StyleHelper.CreateStyleForwardersForDefaultStyles does not work in Silverlight
Probably, the application resources are defined like this:
Note that this documentation has to be written
1.
2.
3.
4.
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="MyApp">
<Application.Resources>
<ResourceDictionary Source="/CWP.Shared;component/themes/generic.xaml" />
</Application.Resources>
</Application>
However, Silverlight does not allow to add resources to a where the source is set. To be able to use default styles, use this ResourceDictionary
code:
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="MyApp">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/MyApp.Shared;component/themes/generic.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
MVVM
How to support example data with view models?
How to use events with MVVM?
Silverlight throws error about type that cannot be created?
How can I add the MVVM behaviors via code (programmatically)?
How can I inject or manipulate the view model of a UserControl?
How can I prevent validation of required fields?
How to support example data with view models?
To find out how to create design time data, see the topic. designers
How to use events with MVVM?
When writing MVVM, it's "forbidden" (read: not a best practice) to use click handlers (or other UI events) in your view-model. But then should you
react to events?
Start with creating a command like you are used to using MVVM. This command will be executed when the event occurs.
Add a reference to (ships with Catel). If you have used NuGet to add a reference, it is automatically System.Windows.Interactivity.dll
included for you.
Add the following namespace definitions to your view declaration:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Inter
activity"
xmlns:catel="http://catel.codeplex.com"
Use the following code to convert an event to a command:
4.
<i:Interaction.Triggers>
<i:EventTrigger EventName="[YourEvent]">
<catel:EventToCommand Command="{Binding [YourCommand]}"
DisableAssociatedObjectOnCannotExecute="False" />
</i:EventTrigger>
</i:Interaction.Triggers>
An example for a double click: ListBox
<ListBox ItemsSource="{Binding PersonCollection}" SelectedItem="{Binding
SelectedPerson}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<catel:EventToCommand Command="{Binding Edit}"
DisableAssociatedObjectOnCannotExecute="False" />
</i:EventTrigger>
</i:Interaction.Triggers>

<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding FirstName}" />
<Label Content="{Binding MiddleName}" />
<Label Content="{Binding LastName}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Silverlight throws error about type that cannot be created?
If you are using type creation via xaml this way:
<i:Interaction.Behaviors>
<catel:WindowBehavior ViewModelType="viewmodels:DemoWindowViewModel"
Save="okButton.Click" Cancel="cancelButton.Click" />
</i:Interaction.Behaviors>
It might be possible that Silverlight throws an exception with these details:
{System.Windows.Markup.XamlParseException: Failed to create a 'System.Type' from the
text 'ViewModels:DemoWindowViewModel'. [Line: 13 Position: 67]
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
at Catel.Examples.AdvancedDemo.Views.LogicInBehavior.DemoWindow.InitializeComponent()
at Catel.Examples.AdvancedDemo.Views.LogicInBehavior.DemoWindow..ctor()}
This happens in Silverlight 4 when the Silverlight 5 (beta) tools are not installed. To resolve this issue, install the Silverlight 5 (beta) tools.
How can I add the MVVM behaviors via code (programmatically)?
Silverlight has a known issue, and sometimes installing the Silverlight 5 (beta) toolkit isn't the right option to solve the issue. Luckily, it is also
possible to add one of the MVVM behaviors via code to any control or window.
Below is the code-behind of a view that adds the via code: UserControlBehavior
public partial class DynamicBehaviorView : UserControl, IViewModelContainer
{
private Catel.Windows.Controls.MVVMProviders.UserControlBehavior _mvvmBehavior;

/// <summary>
/// Initializes a new instance of the <see cref="DynamicBehaviorView"/> class.
/// </summary>
public DynamicBehaviorView()
{
InitializeComponent();
_mvvmBehavior = new Catel.Windows.Controls.MVVMProviders.UserControlBehavior();
_mvvmBehavior.ViewModelType = typeof(ViewModels.MyViewModel);
System.Windows.Interactivity.Interaction.GetBehaviors(this).Add(_mvvmBehavior);
_mvvmBehavior.ViewModelChanged += (sender, e) =>
ViewModelChanged.SafeInvoke(this, e);
_mvvmBehavior.ViewModelPropertyChanged += (sender, e) =>
ViewModelPropertyChanged.SafeInvoke(this, e);
}
/// <summary>
/// Gets the view model that is contained by the container.
/// </summary>
/// <value>The view model.</value>
public IViewModel ViewModel
{
get { return _mvvmBehavior.ViewModel; }
}
/// <summary>
/// Occurs when the <see cref="ViewModel"/> property has changed.
/// </summary>
public event EventHandler<EventArgs> ViewModelChanged;
/// <summary>
/// Occurs when a property on the <see cref="ViewModel"/> has changed.
/// </summary>
public event EventHandler<PropertyChangedEventArgs> ViewModelPropertyChanged;
#if !SILVERLIGHT
/// <summary>
/// Occurs when a property on the container has changed.
/// </summary>
/// <remarks>
/// This event makes it possible to externally subscribe to property changes of a
<see cref="DependencyObject"/>
/// (mostly the container of a view model) because the .NET Framework does not
allows us to.
/// </remarks>
public event EventHandler<PropertyChangedEventArgs> PropertyChanged;

/// <summary>
/// Invoked whenever the effective value of any dependency property on this <see
cref="T:System.Windows.FrameworkElement"/> has been updated. The specific dependency
property that changed is reported in the arguments parameter. Overrides <see
cref="M:System.Windows.DependencyObject.OnPropertyChanged(System.Windows.DependencyPro
pertyChangedEventArgs)"/>.
/// </summary>
/// <param name="e">The event data that describes the property that changed, as
well as old and new values.</param>
protected override void
OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
PropertyChanged.SafeInvoke(this, new PropertyChangedEventArgs(e.Property.Name));
1.
2.
}
#endif
}
Using this technique, it is even possible to determine the view model of any view dynamically at runtime.
How can I inject or manipulate the view model of a UserControl?
The is a very powerful control. It allows lazy loaded dynamic view model construction. However, sometimes you just don't want the UserControl
user control to dynamically create the view model. Luckily, the user control instantiates a new view model with this logic:
The of the control can be injected into a constructor of the view model DataContext
The view model has an empty constructor
You can set the of the control to a view model, and this way "inject" a view model into a control instead of letting it be created first. In DataContext
fact, the user control first checks whether the is already a valid view model for the user control. If so, it keeps it that way. DataContext
How can I prevent validation of required fields?
Catel does not validate the properties with data annotations at startup. It will only validate the data annotations when properties change or when
the view model is about to be saved. This is implemented this way to allow a developer to show required fields with an asterisk (*) instead of
errors. If a developer still wants to initially display errors, only a single call has to be made in the constructor:
Validate(true, false);
If the validation is implemented in the models and not in the view model, set the to false. ValidateModelsOnInitialization

Setup, deployment and projects


Getting prerelease (beta) versions via NuGet
Stepping through the code
Compiling from source
Code snippets & templates
Updating to a new version via NuGet

Getting prerelease (beta) versions via NuGet


Starting on December 21, 2011, beta versions of Catel are published to NuGet. This way, it is possible to give users that like to live on the edge a
change to update their packages via NuGet.
Installing via package manager
Installing viapackage manager console
Strange versioning
Installing via package manager
Please make sure to select the same settings as in the screenshow below:
Installing viapackage manager console
This example installs Catel.Extensions.Controls as a package. However, to install other packages simple change the ID (name) of the package.
Installing the latest beta
Install-Package Catel.Extensions.Controls -IncludePrerelease
Installing a specific beta
Install-Package Catel.Extensions.Controls -IncludePrerelease -version
2.4.1112211041-beta
Updating to the latest beta
Update-Package Catel.Extensions.Controls -IncludePrerelease
Updating to a specific beta
Update-Package Catel.Extensions.Controls -IncludePrerelease -version
2.4.1112211041-beta
Updating to the latest stable version
Update-Package Catel.Extensions.Controls
Strange versioning
The versioning of the beta versions is a bit strange. This is due to a bug in NuGet which does not support the full SemVer standard to include
build numbers. Therefore, the beta versions are always 1 less than the next official version.
For example, say that version 2.4 is currently the official version, and the team is working towards version 2.5. Then all beta versions for 2.5 will
have this version number:
2.4.[yyMMddHHmm]-beta (thus on December 21st 2011, 10:41, the version would be 2.4.1112211041-beta).
Stepping through the code
Starting with the Catel 2.5 beta versions, all beta versions are deployed via NuGet. For more information on getting the beta versions via NuGet,
see . However, together with the official and beta versions, the symbols for each version are deployed to . this documentation SymbolSource.org
This way, it is possible to step through the source of every package that is released for Catel, which is very handy if you want to know what
happens under the hood.
Visual Studio can be configured to automatically download PDB files associated with installed packages and allow the developer to use a
debugger to step into source files on-demand from Visual Studio. This is a built-in feature of the IDE, that can also be used to debug .NET
Framework code using Microsoft Reference Source servers. It is only required to add a new symbol source in the debugger configuration (see her
for detailed instructions): e
http://srv.symbolsource.org/pdb/Public
Compiling from source
In order to compile, the following 3rd party software is r equired:
Visual Studio 2012
Silverlight 4 tools
Silverlight 5 tools
Windows Phone 7 tools
Windows Phone 8 tools
All other libraries required are located inside the folder or are retrieved via NuGet. lib
Code snippets & templates
Using the code snippets
Using the item templates
Using the project templates

Using the code snippets


This part of the documentation explains all the code snippets.
Code snippet Explanation
modelobject Defines a model using the ModelBase class.
modelprop Defines a new property on a model class.
modelpropchanged Defines a new property with change notification on a model class.
vm Defines a new view model.
vmcommand Defines a new view model command with only an executed action.
vmcommandwithcanexecute Defines a new view model command with an executed action, but
also a canexecute function.
First idea was to include the full year, but then the number became too large. Therefore, 20 of 2011 is stripped (we will think of a
solution for this in the year 2099)
vmprop Defines a new property on a view model.
vmpropmodel Defines a new property on a view model and decorates it with the
ModelAttribute.
vmpropviewmodeltomodel Defines a new property on a view model and decorates it with the
ViewModelToModelAttribute.
Using the item templates
There are lots of item templates available for WPF, Silverlight and Windows Phone 7 so it is really easy to develop new views very fast.
Difference between logic in view base or behavior
As you might have noticed, there are lots of "double" item templates. However, there is a substantial difference between the item templates that
implement the logic in the view base or the logic in a behavior.
Shortly said, a view with the logic in the view base is defined like this:
public class MyView : Catel.Windows.Controls.UserControl
{
// rest of the class definition
}
This means that the logic for MVVM is located in the view base (in this example, the UserControl).
An item template where the logic is located in a behavior uses regular controls and uses one of the available MVVM behaviors to implement the
logic. The behaviors are extremely powerful, but we still recommend the use of logic in the view base since that takes more work out of the hands
from the developer.
View model
The view model is the easiest and smallest item template available. The question is even whether a new view model should be created via an
item template or by using the vm code snippet.
User control
The user control templates create a user control deriving from UserControl. First it is very important to make a decision whether the logic should
be implemented in the view base or a behavior. Then, select the appropriate template:
The item template will assume that a view model with the same name is already created. For example, if a view with the name is PersonView
created, the template assumes that the view model name is . If you prefer a different naming convention, simply change the PersonViewModel
view model type name after the item has been created.
Window
The window templates create a window deriving from DataWindow. First it is very important to make a decision whether the logic should be
implemented in the view base or a behavior. Then, select the appropriate template:
Unfortunately, there is a bug in the item templates system of Visual Studio so it is not possible to also set the namespace of the view
models to [ProjectRootNamespace].ViewModels, so this has to be done manually
1.
2.
The item template will assume that a view model with the same name is already created. For example, if a view with the name PersonView is
created, the template assumes that the view model name is PersonViewModel. If you prefer a different naming convention, simply change the
view model type name after the item has been created.
Using the project templates
There are several project templates available for WPF, Silverlight and Windows Phone 7. The easiest way is to follow these steps.
Installing the project templates
Copy the project templates to %MyDocuments%\Visual Studio 2xxx\Templates\ProjectTemplates\Visual C#\
You can now create new projects using the new templates. If the templates are not visible, try using at least the .NET framework 3.5
because this is required for the templates to show up.
Using the project templates
Create a new project. Make sure that at least .NET Framework 4.0 is selected as target framework. The templates can be found under the Catel
folder as shown in the image below:
Unfortunately, there is a bug in the item templates system of Visual Studio so it is not possible to also set the namespace of the view
models to [ProjectRootNamespace].ViewModels, so this has to be done manually
As soon as the project is created, the only thing left to do is add references to the Catel libraries. You can either do this manually or use NuGet.
Updating to a new version via NuGet
NuGet makes the life very easy for developers. You can simply add new dependencies to projects via the package manager. However, there are
some pitfalls one has to be aware of. If you are using NuGet to install Catel packages, please use this guide to update Catel to a new version.
The pitfall
How to update without causing problems
The pitfall
Catel ships with many different extensions. This means that each extensions ships in its own NuGet package. This might cause NuGet packages
to be installed with different versions throughout the solution. Assume the solution below:
MyProject.DAL => contains Catel.Core (3.5)
MyProject => contains Catel.Core (3.5), Catel.MVVM (3.5)
When you go to the NuGet package manager, you will notice that updates are available. When you just click update on , you will end Catel.MVVM
up with a version mismatch, which is shown below:
MyProject.DAL => contains Catel.Core (3.5)
MyProject => contains Catel.Core (3.6), Catel.MVVM (3.6)
This is because NuGet will install (3.6) which has a dependency on (3.6). Because it notices this dependency, it will Catel.MVVM Catel.Core
automatically update , but only for the project, not for all projects. Now there is a mismatch and you won't be able to update Catel.Core MyProject
the anymore via the NuGet package manager because it already notices that you already installed 3.6 somewhere MyProject.DAL Catel.Core
else.
How to update without causing problems
To prevent the pitfall described above, below are some simple steps. If you follow these steps, you will never have any issues with version
dependencies that go wrong.
1.
2.
3.
1.Right-click on the solution => manage NuGet packages
2. Go toUpdatesand search forCatel as you can see in the image below:
3. Make sure to Update in the following order:
Catel.Core
Catel.MVVM (if used)
Any other extensions can now be updated without any issues

Getting started
The getting started series focuses on the main features of Catel.
Quick introduction for developers
Getting started with WPF
Quick introduction for developers
This is a quick introduction for developers who don't have a lot of time to read all the docs. This document contains the absolute basics of what a
developer needs to know.
Core
Logging / debugging
Catel properties
MVVM
Handling of viewmodels
Handling hierarchy and parent/child view models
Communication between view models
Resolving views and view models
Core
This pare contains the core functionality of Catel and what you should know when using Catel.
Logging / debugging
If you ever think Catel is behaving strange or does not work as expected, make sure to enable the logging. Below is an example on how to enable
the logging:
#if DEBUG
LogManager.RegisterDebugListener();
#endif
Catel will then log everything to the output window and provide all the information about its internals.
For more information, read about . logging
Catel properties
All properties in classes deriving from (thus also ) require a special property definition. ModelBase ViewModelBase
Normally one would write something like this:
private string _firstName;
public string FirstName
{
get { return _firstName; }
set
{
RaisePropertyChanging("FirstName");
_firstName = value;
RaisePropertyChanged("FirstName");
}
}
In Catel one should write this:
public string FirstName
{
get { return GetValue< string>(FirstNameProperty); }
set { SetValue(FirstNameProperty, value); }
}
public static readonly PropertyData FirstNameProperty = RegisterProperty("FirstName",
typeof(string), null);
Catel will automatically take care of change notifications.
MVVM
This part is especially meant for the MVVM part.
Handling of viewmodels
In other MVVM frameworks, you are obliged to set the data context of a view manually. It will look something like this:
var view = new PersonView();
view.DataContext = new PersonViewModel();
Note that you can use the or to easily create these properties using code snippets. You can also use inste dataprop vmprop Catel.Fody
ad
Catel automatically resolves the right view model based on the view. If a view is created, Catel automatically creates the view model:
var view = new PersonView();
// view model is automatically created
It goes even further. Catel can create view models based on the data context. For more information, read . nested user controls
Handling hierarchy and parent/child view models
Note thatCatelis already fully aware of parent/child relations of view models so you dont have to do anything
for this yourself. For more information,read . nested user controls
Communication between view models
There are available to communicate between view models. Just make sure that you never directly reference other view model several methods
and keep everything loosely coupled.
Resolving views and view models
Catel resolves views and view models by naming convention. This means that based on the name of a view, the view model can be determined.
This also works the other way around where the view model can be determined based on the view. For more information, read about naming
. conventions
Getting started with WPF
Welcome to the guide for Catel and WPF. In this guide, a very simple application will be created with the most commonly used Getting started
aspects of Catel and WPF.
The application will manage family members and will display the families in separate views.
Creating the project
Creating the models
Serializing data from/to disk
Creating the view models
Creating the views (user controls)
Creating the views (windows)
Hooking up everything together
Finalizing the application
Download the final result:WPF.GettingStarted.zip
Note that this guide assumes that the reader has a basic understanding of XAML and WPF since this guide will not cover these basics
Note that this guide will recommend code snippets that can be found . They are not required, just recommended to speed up here
creating Catel classes and properties.
Creating the project
In this step we will create the project and add the relevant NuGet packages.
Creating the project
Adding the NuGet packages
Running the project
Explanation of the project structure
Up next
Creating the project
To create the project, start Visual Studio and choose ... Then switch to the as you can see in the File => New Project on-line template section
screenshot below and search for Catel:
This guide uses the on-line templates that are available in the Visual Studio gallery. If you can't find the templates on-line, please
download them . here
Pick a good name, in our case and click OK. The template will now be downloaded and the project will be created. WPF.GettingStarted
Adding the NuGet packages
As soon as the project is created, the will be opened and instruct your what to do. Right-click on the solution => Readme.txt Manage NuGet
Then search for and click . packages... Catel.Extensions.Controls Install
Running the project
Now the NuGet packages are installed, the project is created and can be built. The basics are created and the application is ready:
Explanation of the project structure
The project template creates the project structure that fits best with Catel. Below is an explanation of the new project structure:
The folder contains the , which contains the logic for the interaction with the view. ViewModels MainWindowViewModel MainWindow
The folder contains the , which represents the actual view. Views MainWindow
Up next
Creating the models

Creating the models


In this step we will create models.Since this application is about families and persons inside those families, we need to create the following
models: , and . Settings Family Person
Creating the model classes
Settings class
Family class
Person class
Adding properties to the models
Settings class
Family class
Person class
Up next
Creating the model classes
The models that will be used in this application will derive from the or class of Catel. These classes enable ModelBase SavableModelBase
support for change notifications, validations and persistence. The adds additional methods to save and load from/to streams SavableModelBase
or files without having to create a serializer first.
To create the model classes, create the following classes in the folder. Models
Settings class
The settings class is the top container that will store all families and other settings (which might be added in the future).
namespace WPF.GettingStarted.Models
{
using Catel.Data;
public class Settings : SavableModelBase<Settings>
{
}
}
Family class
namespace WPF.GettingStarted.Models
{
using Catel.Data;
public class Family : ModelBase
{
}
}
Person class
namespace WPF.GettingStarted.Models
{
using Catel.Data;
public class Person : ModelBase
{
}
}
The code snippet is available to create models model
Adding properties to the models
The next step is to add properties to the models. An important concept to understand is that Catel uses specific "dependency-a-like" properties in
order to provide all the functionality in the classes. Below are the properties per model that need to be registered. ModelBase
At first sight, these properties might look very overwhelming. Let's take a look at how the property system works. The most important thing is the
actual property registration:
public static readonly PropertyData PersonsProperty = RegisterProperty("Persons",
typeof(ObservableCollection<Person>), () => new ObservableCollection<Person>());
This defines a property on the model with the following data:
Name => Persons
Type => ObservableCollection<Person>
DefaultValue => new ObservableCollection<Person>()
This will create a property in the property bag of the model. The next piece of the property is the actual wrapper around the property value which
is managed by the property bag. The Catel properties always need a wrapper to be exposed to the "outside world" of the class.
public ObservableCollection<Person> Persons
{
get { return GetValue<ObservableCollection<Person>>(PersonsProperty); }
set { SetValue(PersonsProperty, value); }
}
Settings class
public class Settings : SavableModelBase<Settings>
{
/// <summary>
/// Gets or sets all the families.
/// </summary>
public ObservableCollection<Family> Families
{
get { return GetValue<ObservableCollection<Family>>(FamiliesProperty); }
set { SetValue(FamiliesProperty, value); }
}
/// <summary>
/// Register the Families property so it is known in the class.
/// </summary>
public static readonly PropertyData FamiliesProperty =
RegisterProperty("Families", typeof(ObservableCollection<Family>), () => new
ObservableCollection<Family>());
}
Family class
The code snippet is available to create models modelprop
public class Family : ModelBase
{
/// <summary>
/// Gets or sets the family name.
/// </summary>
public string FamilyName
{
get { return GetValue<string>(FamilyNameProperty); }
set { SetValue(FamilyNameProperty, value); }
}
/// <summary>
/// Register the FamilyName property so it is known in the class.
/// </summary>
public static readonly PropertyData FamilyNameProperty =
RegisterProperty("FamilyName", typeof(string), null);
/// <summary>
/// Gets or sets the list of persons in this family.
/// </summary>
public ObservableCollection<Person> Persons
{
get { return GetValue<ObservableCollection<Person>>(PersonsProperty); }
set { SetValue(PersonsProperty, value); }
}
/// <summary>
/// Register the Persons property so it is known in the class.
/// </summary>
public static readonly PropertyData PersonsProperty = RegisterProperty("Persons",
typeof(ObservableCollection<Person>), () => new ObservableCollection<Person>());

public override string ToString()


{
return FamilyName;
}
}
Person class
public class Person : ModelBase
{
/// <summary>
/// Gets or sets the first name.
/// </summary>
public string FirstName
{
get { return GetValue<string>(FirstNameProperty); }
set { SetValue(FirstNameProperty, value); }
}
/// <summary>
/// Register the FirstName property so it is known in the class.
/// </summary>
public static readonly PropertyData FirstNameProperty =
RegisterProperty("FirstName", typeof(string), null);
/// <summary>
/// Gets or sets the last name.
/// </summary>
public string LastName
{
get { return GetValue<string>(LastNameProperty); }
set { SetValue(LastNameProperty, value); }
}
/// <summary>
/// Register the LastName property so it is known in the class.
/// </summary>
public static readonly PropertyData LastNameProperty =
RegisterProperty("LastName", typeof(string), null);

public override string ToString()


{
string fullName = string.Empty;
if (!string.IsNullOrEmpty(FirstName))
{
fullName += FirstName;
}
if (!string.IsNullOrEmpty(FirstName) && !string.IsNullOrWhiteSpace(LastName))
{
fullName += " ";
}
if (!string.IsNullOrWhiteSpace(LastName))
{
fullName += LastName;
}
return fullName;
}
}
Up next
Serializing data from/to disk
Serializing data from/to disk
In this step we will create services that will serialize the models from/to disk. Services are a great way to abstract functionality that can be used in
every part of the application. This guide will also register the service in the so it can be injected in view models. ServiceLocator
Creating the service definition
Creating the service implementation
Registering the service in the ServiceLocator
Adding the service usage to the MainWindowViewModel
Injecting the service via dependency injection
Creating theFamilies property on the MainWindowViewModel
Loading the families at startup
Saving the families at shutdown
Up next
Creating the service definition
The first thing to do is to create the folder to group the services. Below is a screenshot of how to solution will look after creating the Services
folders:
Then add a new interface to the folder named . This will manage the families that are avaiable. Below is the interface Interfaces IFamilyService
defined:
namespace WPF.GettingStarted.Services
{
using WPF.GettingStarted.Models;
public interface IFamilyService
{
IEnumerable<Family> LoadFamilies();
void SaveFamilies(IEnumerable<Family> families);
}
}
Creating the service implementation
Below is the implementation of the service which will actually take care of saving and loading of the families:
namespace WPF.GettingStarted.Services
{
using System.Collections.Generic;
using System.IO;
using Catel.Collections;
using Catel.Data;
using WPF.GettingStarted.Models;
public class FamilyService : IFamilyService
{
private readonly string _path;
public FamilyService()
{
string directory =
Catel.IO.Path.GetApplicationDataDirectory("CatenaLogic", "WPF.GettingStarted");
_path = Path.Combine(directory, "family.xml");
}
public IEnumerable<Family> LoadFamilies()
{
if (!File.Exists(_path))
{
return new Family[] { };
}
var settings = Settings.Load(_path, SerializationMode.Xml);
return settings.Families;
}
public void SaveFamilies(IEnumerable<Family> families)
{
var settings = new Settings();
settings.Families.ReplaceRange(families);
settings.Save(_path, SerializationMode.Xml);
}
}
}
Registering the service in the ServiceLocator
Now we have created the service, it is time to register it in the . In the , add the following code: ServiceLocator App.xaml.cs
var serviceLocator = ServiceLocator.Default;
serviceLocator.RegisterType<IFamilyService, FamilyService>();
Adding the service usage to the MainWindowViewModel
Now the service is registered, it can be used anywhere in the application. A great place to load and save the families is in theMainWindowViewM
which contains all the logic of the main application window. odel
Injecting the service via dependency injection
To get an instance of the service in the view model, change the constructor to the following definition.
private readonly IFamilyService _familyService;
/// <summary>
/// Initializes a new instance of the <see cref="MainWindowViewModel"/> class.
/// </summary>
public MainWindowViewModel(IFamilyService familyService)
{
Argument.IsNotNull(() => familyService);
_familyService = familyService;
}
As you can see in the code above, a new field is created to store the dependency Then the constructor ensures that the argument IFamilyService.
is not null and stores it in the field.
Creating theFamilies property on the MainWindowViewModel
The next thing we need is a property on the to store the families in we load from disk. Below is the property Families MainWindowViewModel
definition for that:
/// <summary>
/// Gets the families.
/// </summary>
public ObservableCollection<Family> Families
{
get { return GetValue<ObservableCollection<Family>>(FamiliesProperty); }
private set { SetValue(FamiliesProperty, value); }
}
/// <summary>
/// Register the Families property so it is known in the class.
/// </summary>
public static readonly PropertyData FamiliesProperty = RegisterProperty("Families",
typeof(ObservableCollection<Family>), null);
Loading the families at startup
Now we have the and the property, it is time to combine these two. To do this, we need to override the method IFamilyService Families Initialize
on the view model which is automatically called as soon as the view is loaded by Catel:
protected override void Initialize()
{
var families = _familyService.LoadFamilies();
Families = new ObservableCollection<Family>(families);
}
Saving the families at shutdown
To save the families at shutdown, override the method on the view model which is automatically called as soon as the view is closed by Close
Catel:
protected override void Close()
{
_familyService.SaveFamilies(Families);
}
After running the application once, a new file will be stored in the following directory:
C:\Users\[yourusername]\AppData\Roaming\CatenaLogic\WPF.GettingStarted
Up next
Creating the view models
Creating the view models
In this step we will create the view models. Since this is a very simple application, just a few view models are required.A view model in essence is
nothing more than a class that derives from the class ViewModelBase
Creating the PersonViewModel
Enabling model injection
Exposing properties of a model
Creating the FamilyViewModel
Up next
Creating the PersonViewModel
Below is the class definition of the . This view model will be used to show the details of a model. PersonViewModel Person
namespace WPF.GettingStarted.ViewModels
{
using Catel.MVVM;
public class PersonViewModel : ViewModelBase
{
}
}
Enabling model injection
In hierarchy views, it is important to manage the state of views and view models based on the actual context where the view (thus view model) is
located. Catel does this by allowing model injection. The view models will only be created when the model is available within the context of the
view.
The vm code snippet is available to create view models. There is also an on-line item template available for Catel view models
public class PersonViewModel : ViewModelBase
{
public PersonViewModel(Person person)
{
Argument.IsNotNull(() => person);
Person = person;
}
/// <summary>
/// Gets or sets the person.
/// </summary>
[Model]
public Person Person
{
get { return GetValue<Person>(PersonProperty); }
set { SetValue(PersonProperty, value); }
}
/// <summary>
/// Register the Person property so it is known in the class.
/// </summary>
public static readonly PropertyData PersonProperty = RegisterProperty("Person",
typeof(Person), null);
}
Exposing properties of a model
One very powerful feature of Catel is that it can automatically map properties from a model to a view model. This way the user does not have to
write repetitive code to map the properties from the model to the view model at startup and map the properties from view model to model when
the view model is closed. Catel will take care of this all automatically.
Note that the property is decorated with the attribute. This automatically makes sure that if a view model is saved, the Person Model IEd
is called. When the view model is canceled, the is called and all changes on the model itableObject.EndEdit IEditableObject.CancelEdit
will be reverted.
/// <summary>
/// Gets or sets the first name.
/// </summary>
[ViewModelToModel("Person")]
public string FirstName
{
get { return GetValue<string>(FirstNameProperty); }
set { SetValue(FirstNameProperty, value); }
}
/// <summary>
/// Register the FirstName property so it is known in the class.
/// </summary>
public static readonly PropertyData FirstNameProperty = RegisterProperty("FirstName",
typeof(string), null);
/// <summary>
/// Gets or sets the last name.
/// </summary>
[ViewModelToModel("Person")]
public string LastName
{
get { return GetValue<string>(LastNameProperty); }
set { SetValue(LastNameProperty, value); }
}
/// <summary>
/// Register the LastName property so it is known in the class.
/// </summary>
public static readonly PropertyData LastNameProperty = RegisterProperty("LastName",
typeof(string), null);
Creating the FamilyViewModel
The must be set up the same way as the above. FamilyViewModel PersonViewModel
namespace WPF.GettingStarted.ViewModels
{
using System.Collections.ObjectModel;
using Catel;
using Catel.Data;
using Catel.MVVM;
using WPF.GettingStarted.Models;
public class FamilyViewModel : ViewModelBase
{
public FamilyViewModel(Family family)
{
Argument.IsNotNull(() => family);

Family = family;
}
Note that the properties are decorated with the attribute which enables the automatic mappings feature in Catel. ViewModelToModel
/// <summary>
/// Gets the family.
/// </summary>
[Model]
public Family Family
{
get { return GetValue<Family>(FamilyProperty); }
private set { SetValue(FamilyProperty, value); }
}
/// <summary>
/// Register the Family property so it is known in the class.
/// </summary>
public static readonly PropertyData FamilyProperty =
RegisterProperty("Family", typeof(Family), null);
/// <summary>
/// Gets the family members.
/// </summary>
[ViewModelToModel("Family")]
public ObservableCollection<Person> Persons
{
get { return GetValue<ObservableCollection<Person>>(PersonsProperty); }
private set { SetValue(PersonsProperty, value); }
}
/// <summary>
/// Register the Persons property so it is known in the class.
/// </summary>
public static readonly PropertyData PersonsProperty =
RegisterProperty("Persons", typeof(ObservableCollection<Person>), null);
/// <summary>
/// Gets or sets the family name.
/// </summary>
[ViewModelToModel("Family")]
public string FamilyName
{
get { return GetValue<string>(FamilyNameProperty); }
set { SetValue(FamilyNameProperty, value); }
}
/// <summary>
/// Register the FamilyName property so it is known in the class.
/// </summary>
public static readonly PropertyData FamilyNameProperty =
RegisterProperty("FamilyName", typeof(string));
}
}
Up next
Creating the views (user controls)
Creating the views (user controls)
In this step we will create the views for the application. There are several views that will be created and both user controls and windows will be
handled in this part of the guide.Catel makes it very easy to create views as user controls with their own view models. In the previous step we
already created the view models.
Person view
Family view
Up next
Person view
To create a new view, right-click the folder in the solution => => => => and search for Catel as you can see in the Views Add New item... On-line
screen below:
Give the new view the name . The view will be added to the folder. PersonView Views
Now we only need to modify the view itself, the code-behind can stay untouched. Since xaml isn't very interesting for this guide, simply copy/paste
the xaml below and set it as content of the view:
Catel will automatically link the and together by naming convention PersonViewModel PersonView
<catel:StackGrid>
<catel:StackGrid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</catel:StackGrid.RowDefinitions>
<catel:StackGrid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</catel:StackGrid.ColumnDefinitions>
<Label Content="First name" />
<Label Content="{Binding FirstName}" />
<Label Content="Last name" />
<Label Content="{Binding LastName}" />
</catel:StackGrid>
Family view
The must be created exactly the same way as the . Use the following xaml as content: FamilyView PersonView
<catel:StackGrid>
<catel:StackGrid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</catel:StackGrid.RowDefinitions>
<catel:StackGrid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</catel:StackGrid.ColumnDefinitions>
<Label Content="Family name" />
<Label Content="{Binding FamilyName}" />
<Label Grid.ColumnSpan="2" Content="Persons" />

<ItemsControl Grid.ColumnSpan="2" ItemsSource="{Binding Persons}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<views:PersonView DataContext="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</catel:StackGrid>
Since this view uses the , it must be defined as a namespace at the top of the file: PersonView
xmlns:views="clr-namespace:WPF.GettingStarted.Views"
The thing that is important to notice in the is how it uses the and injects the models into the data FamilyView PersonView Person PersonView
context.
Up next
Creating the views (windows)
Creating the views (windows)
In this step we will create the windows for the application. In the previous step we already created the user controls.Windows are a great way to
show in an edit-context. Catel provides great edit-windows in the form of the . This is a window that automatically adds and DataWindow OK Canc
buttons (but of course allows customization of the buttons and behavior). el
Person window
Family window
Creating theFamilyWindowViewModel
Creating the FamilyWindow
Up next
Person window
To add a new ,right-click the folder in the solution => => => => and search for Catel as you can see DataWindow Views Add New item... On-line
in the screen below:
Give the new view the name . The view will be added to the folder. PersonWindow Views
Note that we can use the PersonViewModel for both the PersonView (user control) and PersonWindow. Both views represent the same
models and view models, just a different context. To make sure that the IUIVisualizerService knows what view to pick first, register the
PersonWindow in the IUIVisualizerService at application startup:
var uiVisualizerService = serviceLocator.ResolveType<IUIVisualizerService>();
uiVisualizerService.Register(typeof(PersonViewModel), typeof(PersonWindow));
The template will also create a constructor to inject a view model into the window. Please make sure that the constructor takes a view model of
the type instead of the generated . Then replace the content of the view with the xaml below: PersonViewModel PersonWindowModel
<catel:StackGrid>
<catel:StackGrid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</catel:StackGrid.RowDefinitions>
<catel:StackGrid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</catel:StackGrid.ColumnDefinitions>
<Label Content="First name" />
<TextBox Text="{Binding FirstName, ValidatesOnDataErrors=True,
NotifyOnValidationError=True}" />
<Label Content="Last name" />
<TextBox Text="{Binding LastName, ValidatesOnDataErrors=True,
NotifyOnValidationError=True}" />
</catel:StackGrid>
Family window
The is a bit different because we want additional logic in this window. We want to create add / edit / remove buttons for the family FamilyWindow
members. Therefore we need to create a separate view model which contains this logic.
Creating theFamilyWindowViewModel
Since the will look a lot like the , just copy/paste the and rename the copy to FamilyWindowViewModel FamilyViewModel FamilyViewModel Family
. WindowViewModel
Creating the FamilyWindow
Once the is created, the must be created exactly the same way as the . Again make sure FamilyWindowViewModel FamilyWindow PersonWindow
to use the right view model ( ) in the constructor of the window in the code-behind. Then use the following xaml: FamilyWindowViewModel
Note that the needs additional logic, but that will be handled in the next part of this getting started guide FamilyWindowViewModel
<catel:StackGrid>
<catel:StackGrid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</catel:StackGrid.RowDefinitions>
<catel:StackGrid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</catel:StackGrid.ColumnDefinitions>
<Label Content="Family name" />
<TextBox Text="{Binding FamilyName, NotifyOnValidationError=True,
ValidatesOnDataErrors=True}" />
<Label Grid.ColumnSpan="2" Content="Persons" />
<catel:StackGrid Grid.ColumnSpan="2">
<catel:StackGrid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</catel:StackGrid.ColumnDefinitions>
<ListBox ItemsSource="{Binding Persons}" SelectedItem="{Binding
SelectedPerson}">
<ListBox.ItemTemplate>
<DataTemplate>
<views:PersonView DataContext="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

<StackPanel>
<Button Command="{Binding AddPerson}" Content="Add..." />
<Button Command="{Binding EditPerson}" Content="Edit..." />
<Button Command="{Binding RemovePerson}" Content="Remove" />
</StackPanel>
</catel:StackGrid>
</catel:StackGrid>
Up next
Hooking up everything together
Hooking up everything together
In this step we will hook everything together and add additional logic to the remaining view models.
Hooking up the view models
Adding additional logic toFamilyWindowViewModel
Adding additional dependencies being injected
Adding the properties
Adding the commands
Adding additional logic to the MainWindowViewModel
Adding additional dependencies being injected
Adding the properties
Adding the commands
Hooking up the views
Up next
Hooking up the view models
We now have most of the application ready. However we need some logic in the view models to hook up everything together.
Adding additional logic toFamilyWindowViewModel
The first thing we are going to do is to finalize the we created in the previous step. To do this, we are going to add a few FamilyWindowViewModel
properties and commands to the view model.
Adding additional dependencies being injected
Since we will be using additional services inside the , it is important to add them as dependency via the constructor. The FamilyWindowViewModel
updated constructor will look like this:
public FamilyWindowViewModel(Family family, IUIVisualizerService uiVisualizerService,
IMessageService messageService)
{
Argument.IsNotNull(() => family);
Argument.IsNotNull(() => uiVisualizerService);
Argument.IsNotNull(() => messageService);
Family = family;
_uiVisualizerService = uiVisualizerService;
_messageService = messageService;
}
Adding the properties
We need a property representing the currently selected person in edit mode of a family. Below is the property definition which needs to be added
to the view model:
/// <summary>
/// Gets or sets the selected person.
/// </summary>
public Person SelectedPerson
{
get { return GetValue<Person>(SelectedPersonProperty); }
set { SetValue(SelectedPersonProperty, value); }
}
/// <summary>
/// Register the SelectedPerson property so it is known in the class.
/// </summary>
public static readonly PropertyData SelectedPersonProperty =
RegisterProperty("SelectedPerson", typeof(Person), null);
Adding the commands
Below is the code which comes in two parts.
1.Add this code to the constructor:
Don't forget to create the right backing fields and _uiVisualizerService _messageService
Note that we recommend that you use the and code snippets available vmcommand vmcommandwithcanexecute here
AddPerson = new Command(OnAddPersonExecute);
EditPerson = new Command(OnEditPersonExecute, OnEditPersonCanExecute);
RemovePerson = new Command(OnRemovePersonExecute, OnRemovePersonCanExecute);
2. Add this code to the view model itself:
/// <summary>
/// Gets the AddPerson command.
/// </summary>
public Command AddPerson { get; private set; }
/// <summary>
/// Method to invoke when the AddPerson command is executed.
/// </summary>
private void OnAddPersonExecute()
{
var person = new Person();
person.LastName = FamilyName;
// Note that we use the type factory here because it will automatically take care
of any dependencies
// that the PersonViewModel will add in the future
var typeFactory = this.GetTypeFactory();
var personViewModel =
typeFactory.CreateInstanceWithParametersAndAutoCompletion<PersonViewModel>(person);
if (_uiVisualizerService.ShowDialog(personViewModel) ?? false)
{
Persons.Add(person);
}
}
/// <summary>
/// Gets the EditPerson command.
/// </summary>
public Command EditPerson { get; private set; }
/// <summary>
/// Method to check whether the EditPerson command can be executed.
/// </summary>
/// <returns><c>true</c> if the command can be executed; otherwise
<c>false</c></returns>
private bool OnEditPersonCanExecute()
{
return SelectedPerson != null;
}
/// <summary>
/// Method to invoke when the EditPerson command is executed.
/// </summary>
private void OnEditPersonExecute()
{
// Note that we use the type factory here because it will automatically take care
of any dependencies
// that the PersonViewModel will add in the future
var typeFactory = this.GetTypeFactory();
var personViewModel =
typeFactory.CreateInstanceWithParametersAndAutoCompletion<PersonViewModel>(SelectedPer
son);
_uiVisualizerService.ShowDialog(personViewModel);
}
/// <summary>
/// Gets the RemovePerson command.
/// </summary>
public Command RemovePerson { get; private set; }
/// <summary>
/// Method to check whether the RemovePerson command can be executed.
/// </summary>
/// <returns><c>true</c> if the command can be executed; otherwise
<c>false</c></returns>
private bool OnRemovePersonCanExecute()
{
return SelectedPerson != null;
}
/// <summary>
/// Method to invoke when the RemovePerson command is executed.
/// </summary>
private void OnRemovePersonExecute()
{
if (_messageService.Show(string.Format("Are you sure you want to delete the person
'{0}'?", SelectedPerson),
"Are you sure?", MessageButton.YesNo, MessageImage.Question) ==
MessageResult.Yes)
{
Persons.Remove(SelectedPerson);
SelectedPerson = null;
}
}
Adding additional logic to the MainWindowViewModel
The same edit functionality we added to the must be added to the . The difference is that FamilyWindowViewModel MainWindowViewModel
instead of adding / editing / removing persons, the will do this for families. MainWindowViewModel
Adding additional dependencies being injected
We will again need additional dependencies. Below is the updated constructor for the : MainWindowViewModel
public MainWindowViewModel(IFamilyService familyService, IUIVisualizerService
uiVisualizerService, IMessageService messageService)
{
Argument.IsNotNull(() => familyService);
Argument.IsNotNull(() => uiVisualizerService);
Argument.IsNotNull(() => messageService);
_familyService = familyService;
_uiVisualizerService = uiVisualizerService;
_messageService = messageService;
}
Adding the properties
We will again need a property to handle the selected family:
/// <summary>
/// Gets or sets the selected family.
/// </summary>
public Family SelectedFamily
{
get { return GetValue<Family>(SelectedFamilyProperty); }
set { SetValue(SelectedFamilyProperty, value); }
}
/// <summary>
/// Register the SelectedFamily property so it is known in the class.
/// </summary>
public static readonly PropertyData SelectedFamilyProperty =
RegisterProperty("SelectedFamily", typeof(Family), null);
Adding the commands
Last but not least, we will also add the commands to the to handle the logic. MainWindowViewModel
1.Add this code to the constructor:
AddFamily = new Command(OnAddFamilyExecute);
EditFamily = new Command(OnEditFamilyExecute, OnEditFamilyCanExecute);
RemoveFamily = new Command(OnRemoveFamilyExecute, OnRemoveFamilyCanExecute);
2. Add this code to the view model itself:
/// <summary>
/// Gets the AddFamily command.
/// </summary>
public Command AddFamily { get; private set; }
/// <summary>
/// Method to invoke when the AddFamily command is executed.
/// </summary>
private void OnAddFamilyExecute()
{
var family = new Family();
// Note that we use the type factory here because it will automatically take care
of any dependencies
// that the FamilyWindowViewModel will add in the future
var typeFactory = this.GetTypeFactory();
var familyWindowViewModel =
typeFactory.CreateInstanceWithParametersAndAutoCompletion<FamilyWindowViewModel>(famil
y);
if (_uiVisualizerService.ShowDialog(familyWindowViewModel) ?? false)
{
Families.Add(family);
}
}
/// <summary>
/// Gets the EditFamily command.
/// </summary>
public Command EditFamily { get; private set; }
/// <summary>
/// Method to check whether the EditFamily command can be executed.
/// </summary>
/// <returns><c>true</c> if the command can be executed; otherwise
<c>false</c></returns>
private bool OnEditFamilyCanExecute()
{
return SelectedFamily != null;
}
/// <summary>
/// Method to invoke when the EditFamily command is executed.
/// </summary>
private void OnEditFamilyExecute()
{
// Note that we use the type factory here because it will automatically take care
of any dependencies
// that the PersonViewModel will add in the future
var typeFactory = this.GetTypeFactory();
var familyWindowViewModel =
typeFactory.CreateInstanceWithParametersAndAutoCompletion<FamilyWindowViewModel>(Selec
tedFamily);
_uiVisualizerService.ShowDialog(familyWindowViewModel);
}
/// <summary>
/// Gets the RemoveFamily command.
/// </summary>
public Command RemoveFamily { get; private set; }
/// <summary>
/// Method to check whether the RemoveFamily command can be executed.
/// </summary>
/// <returns><c>true</c> if the command can be executed; otherwise
<c>false</c></returns>
private bool OnRemoveFamilyCanExecute()
{
return SelectedFamily != null;
}
/// <summary>
/// Method to invoke when the RemoveFamily command is executed.
/// </summary>
private void OnRemoveFamilyExecute()
{
if (_messageService.Show(string.Format("Are you sure you want to delete the family
'{0}'?", SelectedFamily),
"Are you sure?", MessageButton.YesNo, MessageImage.Question) ==
MessageResult.Yes)
{
Families.Remove(SelectedFamily);
SelectedFamily = null;
}
}
Hooking up the views
We now have all the views ready, but we don't see anything yet. The reason for this is that we haven't modified the view yet. To do MainWindow
so, replace the xaml content with the xaml below:
<catel:StackGrid>
<catel:StackGrid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</catel:StackGrid.ColumnDefinitions>
<ListBox ItemsSource="{Binding Families}" SelectedItem="{Binding SelectedFamily}">
<ListBox.ItemTemplate>
<DataTemplate>
<views:FamilyView DataContext="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel>
<Button Command="{Binding AddFamily}" Content="Add..." />
<Button Command="{Binding EditFamily}" Content="Edit..." />
<Button Command="{Binding RemoveFamily}" Content="Remove" />
</StackPanel>
</catel:StackGrid>
Now run the application and you should see your fully functional family management application.
Up next
Finalizing the application
Finalizing the application
The application we have created so far is fully functional, but misses a bit of the "magic". Below are some additional steps that might make your
application more appealing and more user friendly. Of course you can go as far as you want by creating custom animations and such, but this
guide focuses purely on making the basics more appealing.
Adding validation
Adding behaviors to enable double-click on the list boxes
Adding search functionality to the main window
Adding additional properties to the view model
Adding the search functionality to the view
Adding validation
Adding validation with Catel is extremely easy. There are two flavors to pick from, but they work exactly the same (since both the models and view
models internally derive from ). To add validation to the model, use this code: ModelBase Person
protected override void ValidateFields(List<IFieldValidationResult> validationResults)
{
if (string.IsNullOrWhiteSpace(FirstName))
{
validationResults.Add(FieldValidationResult.CreateError(FirstNameProperty,
"The first name is required"));
}
if (string.IsNullOrWhiteSpace(LastName))
{
validationResults.Add(FieldValidationResult.CreateError(LastNameProperty, "The
last name is required"));
}
}
The validation for the model is very easy as well: Family
protected override void ValidateFields(List<IFieldValidationResult> validationResults)
{
if (string.IsNullOrWhiteSpace(FamilyName))
{
validationResults.Add(FieldValidationResult.CreateError(FamilyNameProperty,
"The family name is required"));
}
}
Adding behaviors to enable double-click on the list boxes
The user must manually click the buttons in the editable views to edit a specific model. To make it easier for the user, we can enable double Edit
click to command behaviors. To do so, navigate to the and add this to the definition: MainWindow ListBox
<ListBox x:Name="listBox" ItemsSource="{Binding Families}" SelectedItem="{Binding
SelectedFamily}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<i:Interaction.Behaviors>
<catel:DoubleClickToCommand Command="{Binding ElementName=listBox,
Path=DataContext.EditFamily}" />
</i:Interaction.Behaviors>
<views:FamilyView DataContext="{Binding}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The same goes for the : FamilyWindow
Note that this validation code can be used in both the model and/or the view models
<ListBox x:Name="listBox" ItemsSource="{Binding Persons}" SelectedItem="{Binding
SelectedPerson}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<i:Interaction.Behaviors>
<catel:DoubleClickToCommand Command="{Binding ElementName=listBox,
Path=DataContext.EditPerson}" />
</i:Interaction.Behaviors>
<views:PersonView DataContext="{Binding}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Adding search functionality to the main window


A functionality that is needed in a lot of applications is search functionality. To implement this we will need to modify the . MainWindowViewModel
Below are the steps required to implement search functionality.
Adding additional properties to the view model
Lets start by adding the additional properties required to implement searching in the : MainWindowViewModel
Note that the must be added in order for the code above to xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
compile
/// <summary>
/// Gets the filtered families.
/// </summary>
public ObservableCollection<Family> FilteredFamilies
{
get { return GetValue<ObservableCollection<Family>>(FilteredFamiliesProperty); }
private set { SetValue(FilteredFamiliesProperty, value); }
}
/// <summary>
/// Register the FilteredFamilies property so it is known in the class.
/// </summary>
public static readonly PropertyData FilteredFamiliesProperty =
RegisterProperty("FilteredFamilies", typeof(ObservableCollection<Family>));
/// <summary>
/// Gets or sets the search filter.
/// </summary>
public string SearchFilter
{
get { return GetValue<string>(SearchFilterProperty); }
set { SetValue(SearchFilterProperty, value); }
}
/// <summary>
/// Register the SearchFilter property so it is known in the class.
/// </summary>
public static readonly PropertyData SearchFilterProperty =
RegisterProperty("SearchFilter", typeof(string), null, (sender, e) =>
((MainWindowViewModel)sender).UpdateSearchFilter());
Add this method to the view model:
Note that this property contains an additional change callback function which will be called when the property has changed.
/// <summary>
/// Updates the filtered items.
/// </summary>
private void UpdateSearchFilter()
{
if (FilteredFamilies == null)
{
FilteredFamilies = new ObservableCollection<Family>();
}
if (string.IsNullOrWhiteSpace(SearchFilter))
{
FilteredFamilies.ReplaceRange(Families);
}
else
{
var lowerSearchFilter = SearchFilter.ToLower();
FilteredFamilies.ReplaceRange(from family in Families
where
!string.IsNullOrWhiteSpace(family.FamilyName) &&
family.FamilyName.ToLower().Contains(lowerSearchFilter)
select family);
}
}
Then, add this code to the function: OnAddFamilyExecute
private void OnAddFamilyExecute()
{
var family = new Family();
// Note that we use the type factory here because it will automatically take care
of any dependencies
// that the FamilyWindowViewModel will add in the future
var typeFactory = this.GetTypeFactory();
var familyWindowViewModel =
typeFactory.CreateInstanceWithParametersAndAutoCompletion<FamilyWindowViewModel>(famil
y);
if (_uiVisualizerService.ShowDialog(familyWindowViewModel) ?? false)
{
Families.Add(family);
UpdateSearchFilter();
}
}
Last but not least, add this to the method the is set from the Initialize after Families IFamilyService
protected override void Initialize()
{
var families = _familyService.LoadFamilies();
Families = new ObservableCollection<Family>(families);
UpdateSearchFilter();
}
Adding the search functionality to the view
Replace the xaml of the main window by the following content:
<catel:StackGrid>
<catel:StackGrid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</catel:StackGrid.RowDefinitions>
<catel:StackGrid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</catel:StackGrid.ColumnDefinitions>
<catel:StackGrid Grid.ColumnSpan="2">
<catel:StackGrid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</catel:StackGrid.ColumnDefinitions>
<Label Content="Filter:" />
<TextBox Text="{Binding SearchFilter}">
<i:Interaction.Behaviors>
<catel:UpdateBindingOnTextChanged UpdateDelay="500" />
</i:Interaction.Behaviors>
</TextBox>
</catel:StackGrid>
<ListBox x:Name="listBox" ItemsSource="{Binding FilteredFamilies}"
SelectedItem="{Binding SelectedFamily}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<i:Interaction.Behaviors>
<catel:DoubleClickToCommand Command="{Binding
ElementName=listBox, Path=DataContext.EditFamily}" />
</i:Interaction.Behaviors>
<views:FamilyView DataContext="{Binding}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel>
<Button Command="{Binding AddFamily}" Content="Add..." />
<Button Command="{Binding EditFamily}" Content="Edit..." />
<Button Command="{Binding RemoveFamily}" Content="Remove" />
</StackPanel>
</catel:StackGrid>
Examples
There are lots of examples written for Catel. Most of the examples are located in the , but there are some examples Catel Examples repository
which can are listed below:
MyMediaStuff - WPF demo application that uses media display, nested user controls and timers

If you have an example application that you want to share, let us know!

WPF Examples
Advanced WPF example
Authentication example
Browser application example
Master/detail example
Multilingual example
MVVM communication styles
Person application WPF example
Validation example
Viewmodel lifetime example
Silverlight examples
Advanced Silverlight example
Navigation example
Nested user controls example
Person application Silverlight example
Windows Phone examples
Bing maps example
Sensors example
Shopping list example
WPF Examples
Advanced WPF example
Authentication example
Browser application example
Master/detail example
Multilingual example
MVVM communication styles
Person application WPF example
Validation example
Viewmodel lifetime example
Advanced WPF example
This example shows advanced functionality such as MEF, Unity, Nested User Controls and MVVM behaviors.
The first groupbox at the left shows how to instantiate a Window both where the MVVM logic is implemented in the view base ( ) and DataWindow
a behavior ( ). WindowBehavior
The second groupbox shows how to instantiate the both where the MVVM logic is implemented in the view base ( ) and a UserControl UserControl
behavior ( ). UserControlBehavior
The third groupbox shows the usage of the (both in determinate and indeterminate mode) using the ServiceLocator, MEF and IPleaseWaitService
Unity.
Screenshots

Authentication example
This example shows how to use authentication for views. You can either choose to run the window as read-only user or as administrator. When
running as read-only user, you will notice that the controls are disabled, hidden and collapsed. When running as administrator, the controls will all
be available.
Screenshots
Browser application example
This example shows how to run a browser application in WPF by using the . INavigationService
Screenshots
Master/detail example
This example shows how to create a master/detail with a as detail which automatically responds to changes in the master. UserControl
Screenshots
Multilingual example
This example show how to use the multiple languages in Catel. This example is also used to test new languages that are translated for Catel.
Screenshots
MVVM communication styles
There are several ways to implement communication between view models. This example shows the different communication styles:
InterestedIn
MessageMediator
InterestedIn
The InterestedIn method in Catel is the easiest way to communicate between view models. This can be done by simply adding theInterestedInAtt
on top of a view model and override the and methods. ribute OnViewModelPropertyChanged OnViewModelCommandExecuted
MessageMediator
Thought more flexible, the technique requires more work because the developer is responsible for defining custom messages, MessageMediator
registering and unregistering specific messages and sending the messages via the . MessageMediator
Screenshots
Person application WPF example
This example is a small application that allows adding persons via a model popup window. Is shows how to add validation, modal dialogs (via
MVVM) and view model to model mappings.
Screenshots
Validation example
This example shows all the different validation techniques available in Catel. The following validation techniques are shown:
Validation via validate methods
Validation via data annotations
Validation in model
Validation in IValidator
Validation via FluentValidation Extension
Screenshots
Viewmodel lifetime example
This example shows how to manually control the lifetime of view models. When adding new tabs, you can either choose the default behavior
(close view model when a control is unloaded) or to keep the view model alive. When a tab is unselected, the view model will be closed because
the view is unloaded from the visual tree. When the control should keep the view model alive, you will note that the total number of view models
will not decrease when switching from tabs.
All view models are explicitly closed when the close button on the tab is clicked. In that case, you will see the total number of alive view models
decrease.
Screenshots
Silverlight examples
Advanced Silverlight example
Navigation example
Nested user controls example
Person application Silverlight example
Advanced Silverlight example
This example shows advanced functionality such as MEF, Unity, Nested User Controls and MVVM behaviors.
The first groupbox at the left shows how to instantiate a both where the MVVM logic is implemented in the view base ( ) and Window DataWindow
a behavior ( ). WindowBehavior
The second groupbox shows how to instantiate the both where the MVVM logic is implemented in the view base ( ) and a UserControl UserControl
behavior ( ). UserControlBehavior
The third groupbox shows the usage of the (both in determinate and indeterminate mode) using the , MEF and IPleaseWaitService ServiceLocator
Unity.
Screenshots
Navigation example
This example shows how to create a page navigation application using Silverlight. It uses the to implement navigation. INavigationService
Screenshots
Nested user controls example
This example shows how to use nested user controls without instantiating all the view models of the nested user controls first. As you can see by
the view model creation time, the view models are actually created on-demand (we also call this lazy loading of view models).
Screenshots
Person application Silverlight example
This example is a small application that allows adding persons via a model popup window. Is shows how to add validation, modal dialogs (via
MVVM) and view model to model mappings.
Screenshots
Windows Phone examples
Bing maps example
Sensors example
Shopping list example

Bing maps example


This example shows how to access the current location in MVVM in Windows Phone and show it using Bing maps.
Screenshots
Sensors example
This example shows how to access all Windows Phone sensors and how to emulate them (for example, during unit tests or in the emulator).
Screenshots
Shopping list example
This example shows a shopping list application with navigation via arguments and several views and how to store data in the isolated storage.
Screenshots
Performance considerations
While developer software, it is very important to keep an eye on the performance. Catel itself does perform very well, but there are some caveats
that you should be aware of. If you have the feeling the the application is laggy or slow, or if you want to make sure to squeeze the best
performance out of Catel, the checklist below is very important.
General
Disable the call to LogManager.RegisterDebugListener
Disabling validation during activities where validation is not required
Use LeanAndMeanModel property on ModelBase
Preloading assemblies into the AppDomain
Warming up the serializers
MVVM
Set SkipSearchingForInfoBarMessageControl on UserControl to true
Use the FastObservableCollection
Implementing IDependencyPropertySelector
Specify throttling on the ViewModelBase
General
Disable the call to LogManager.RegisterDebugListener
The is a very useful class while developing an application. It throws all the logging of Catel to the output window of Visual Studio DebugListener
which allows you to view exactly what happens behind the scenes. However, writing all these logs to the output window is very expensive and
might cause an application to perform badly.
Therefore, it is important to disable any call to when releasing an application or while performance testing. LogManager.RegisterDebugListener
Disabling validation during activities where validation is not required
Validation inside Catel is very powerful, but sometimes it is not needed. To disable all validation inside Catel, use the following code:
ModelBase.SuspendValidationForAllModels = true;
Use LeanAndMeanModel property on ModelBase
When loading lots of models, it is not required to get support for validation and change notifications. Notifications and validation can be suspended
per model (using the property) or globally using the property. LeanAndMeanModel GlobalLeanAndMeanModel
Preloading assemblies into the AppDomain
Preloading assemblies might result in a slower startup time, but will not cause slow downs for reflection or assembly loading during the actual
application execution. To preload assemblies using Catel, simply call this extension method:
WPF application
In App.xaml.cs, add the following code
var directory = typeof(MainWindow).Assembly.GetDirectory();
AppDomain.Current.PreloadAssemblies(directory);

ASP.NET application
In global.asax, add the following code:
var directory = Server.MapPath("~/bin");
AppDomain.Current.PreloadAssemblies(directory);
Warming up the serializers
To improve performance for serialization, . warm up the serializers
MVVM
Set SkipSearchingForInfoBarMessageControl on UserControl to true
By default, Catel assumes that an is located on any window. However, it might be that this control is not located on a InfoBarMessageControl
window that contains an instance of the class. This might decrease the performance, especially when lots of user controls are used in UserControl
a hierarchical way. The cause is that the searches for an to register the view model to. UserControlLogic InfoBarMessageControl
If no is located on a container, make sure to set to . InfoBarMessageControl SkipSearchingForInfoBarMessageControl true
Use the FastObservableCollection
The does not raise events for every item, but only invokes events for the complete range of items added to or removed FastObservableCollection
from the collection.
When modifying a large collection of items, it is not required to raise change events for each added / removed value. Therefore the FastObservabl
will disable change notifications until the full collection modification is done and then raise the change events just once. eCollection
Implementing IDependencyPropertySelector
Catel uses a special wrapping technology to wrap bindings to dependency properties to be able to add change notifications for all target
platforms. Though this technology works great, it might have impact on performance and this is not always necessary. By implementing a custom
, developers can tweak the interesting dependency properties per type. IDependencyPropertySelector
It is best to always create a default dependency instead.
public class CustomDependencyPropertySelector : DependencyPropertySelector
{
public override bool MustSubscribeToAllDependencyProperties(Type
targetControlType)
{
return false;
}
}
Then register it in theServiceLocator:
ServiceLocator.Default.RegisterType<IDependencyPropertySelector,
CustomDependencyPropertySelector>();
Even when the custom implementation returns an empty list, Catel will always subscribe to the depen IDependencyPropertySelector DataContext
dency property because it depends on that.
Specify throttling on the ViewModelBase
The allows the specify the throttling of the property change notifications. In normal situations it is best to directly raise property ViewModelBase
change notifications. However, when a lot of properties change a lot within a very short timeframe, it might be interesting to enable throttling. By
using throttling, the change notifications are not directly sent to the UI but instead added to a dictionary. Then each time the is ThottlingRate
reached, the change notifications are sent in batches to the view. If the same property has changed several times in a specific time frame, it will
only be raised once which might give a performance boost in very specific situations.
By default, throttling is disabled but can be enabled by setting the property: ThrottlingRate
ThrottlingRate = new TimeSpan(0, 0, 0, 0, 200);
By default Catel subscribes to all dependency properties to not cause breaking changes. It is however possible to override the
registration using the that ships with Catel FastDependencyPropertySelector
Catel.Core
Argument checking
Caching
Configuration
Data handling
Exception handling
IoC (ServiceLocator and TypeFactory)
Logging
Messaging
Multilingual
Parallel invocation and tasks
Preventing memory leaks
Reflection
Scoping
Serialization
Thread safe code
Validation

Argument checking
It is best practice to always check if the input to a method is correct. If not, an exception should be thrown. Most people do not check for
exceptions correctly and lots of null reference exceptions inside a deep stacktrace are hard to solve.
Catel does check the input on every method. Normally, a check would look like this:
public void CheckForException(object obj)
{
if (obj == null)
{
throw new ArgumentNullException("obj");
}
}
However, Catel extensively logs all behavior, thus all the checks started to look like this:
public void CheckForException(object obj)
{
if (obj == null)
{
Log.Debug("Argument 'obj' is null in CheckForException");
throw new ArgumentNullException("obj");
}
}
Handling input correctly in such a case takes a lot of space and repetitive code. Therefore the Argument class is developed. This way, it is very
simple to check for arguments:
public void CheckForException(object obj)
{
Argument.IsNotNull("obj", obj);
}
Or, if a range should be checked:
The example contains a demo that shows the impact of throttling AdvancedDemo
public void CheckForException(int myInt)
{
Argument.IsNotOutOfRange("myInt", myInt, 0, 10);
}
A final example is to check whether a type implements a specific interface:
public void CheckForException(object obj)
{
Argument.ImplementsInterface("obj", obj, typeof(INotifyPropertyChanged));
}
Caching
Caching is about improve applications performance. The most expensive performance costs of the applications are related with the data
retrieving, typically when this data requires to be moved a cross the network or loaded from disk. But some data have an slow changing behavior
(a.k.a non-volatile) and doesn't requires to be re-read with the same frequency of the volatile data.
So, to improve your application performance and handling this "nonvolatile" data from a pretty clean approach, Catel comes with a CacheStorage
class. Notice that the first generic parameter is the type of the key and the second the type of the value the will be store, just like <TKey, TValue>
a but CacheStorage isn't it just a Dictionary. This class allows you to retrieve data and storing it into the cache with Dictionary<TKey, TValue>
single statement and also helps you to handle expiration policy if you need it.
Initializing a cache storage
To initialize a cache storage field into your class use the follow code:
private readonly CacheStorage<string, Person> _personCache = new CacheStorage<string,
Person>(storeNullValues: true);
Retrieve data and storing into cache with single statement
To retrieve data and storing into a cache with a single statement use the follow code:
var person = _personCache.GetFromCacheOrFetch(Id, () => service.FindPersonById(Id));
When this statement is executed more than once times with the with the same key, the value will be retrieved from the cache storage instead from
the service call. The service call will be executed just the first time or if the item is removed from the cache manually or automatically due by the
expiration policy.
Using cache expiration policies
The cache expiration policies adds a removal behavior to the cache storage items. A policy signals that an item is expired to makes that cache
storage removes the item automatically.
A default cache expiration policy initialization code can be specified during cache storage initialization constructor:
CacheStorage<string, Person> _personCache = new CacheStorage<string, Person>(() =>
ExpirationPolicy.Duration(TimeSpan.FromMinutes(5)), true);
You can specify an specific expiration policy for an item when it's storing:
_personCache.GetFromCacheOrFetch(id, () => service.GetPersonById(id),
ExpirationPolicy.Duration(TimeSpan.FromMinutes(10)));
The default cache policy specified at cache storage initialization will be used if during item storing the expiration policy is not specified.
Build-in expiration policies
Catel comes with build-in expiration policies. They are listed in the follow table:
Expiration policy Type Description Initialization code sample
AbsoluteExpirationPolicy Time-base The cache item will expire on the
absolute expiration DateTime ExpirationPol
icy.Absolute(
new
DateTime(21,
12, 2012))
DurationExpirationPolicy Time-base The cache item will expire using
the duration TimeSpan to
calculate the absolute expiration
from DateTime.Now
ExpirationPol
icy.Duration(
TimeSpan.From
Minutes(5))
SlidingExpirationPolicy Time-base The cache item will expire using
the duration TimeSpan to
calculate the absolute expiration
from DateTime.Now, but
everytime the item is requested,
it is expanded again with the
specified TimeSpan
ExpirationPol
icy.Sliding(T
imeSpan.FromM
inutes(5))
CustomExpirationPolicy Custom The cache item will expire using
the expire function and execute
the reset action if is specified.
The example shows how create
an sliding expiration policy with a
custom expiration policy.
var
startDateTime
=
DateTime.Now;
var duration
=
TimeSpan.From
Minutes(5);
ExpirationPol
icy.Custom(()
=>
DateTime.Now
>
startDateTime
.Add(duration
), () =>
startDateTime
=
DateTime.Now)
;
CompositeExpirationPolicy Custom Combines several expiration
policy into a single one. It can be
configured to expires when any
policy expires or when all
policies expires.
new
CompositeExpi
rationPolicy(
).Add(Expirat
ionPolicy.Sli
ding(
TimeSpan.From
Minutes(5))).
Add(Expiratio
nPolicy.Custo
m(()=>...))
Implementing your own expiration cache policy
If the is not enough, you can implement you own expiration policy to makes that cache item expires triggered from a CustomExpirationPolicy
custom event. You are also able to add some code to reset the expiration policy if the item is read from the cache before it expires (just like Slidin
does). gExpirationPolicy
To implement an expiration cache policy use the follow code template:
public class MyExpirationPolicy : ExpirationCachePolicy
{
public MyExpirationPolicy():base(true)
{
}
public override bool IsExpired
{
get
{
// Add your custom expiration code to detect if the item expires
}
}
public override void OnReset()
{
// Add your custom code to reset the policy if the item is read.
}
}
Configuration
Catel makes it very easy to use configurations on all supported platforms.
Getting values from the configuration
Setting values to the configuration
Customizing the way values are stored
Below is a table to explain what technology is used per platform to retrieve and store configuration values.
Platform Technology
.NET ConfigurationManager.AppSettings
Silverlight IsolatedStorageSettings.ApplicationSettings
Windows Phone IsolatedStorageSettings.ApplicationSettings
WinRT ApplicationData.Current.LocalSettings
PCL Not supported
Getting values from the configuration
To retrieve values from the configuration, use the following code:
var configurationService = new ConfigurationService();
var mySetting = configurationService.GetValue<int>("mySetting", 42);
The code above will retrieve the values from the configuration. If the configuration value does not exist, it will return as default value. 42
Setting values to the configuration
The base constructor have a parameter to indicates if the policy can be reset. Therefore, is you call the base constructor with false then
the OnReset method will never called.
It's best to retrieve the service from the dependency resolver or let it be injected into the classes using it
To store values in the configuration, use the following code:
var configurationService = new ConfigurationService();
configurationService.SetValue("mySetting", 42);
Customizing the way values are stored
The is written with extensibility in mind. Though it defaults to the .NET local storage system, it is very easy to create a ConfigurationService
customized configuration service. Below is an example on how to customize the service so it reads and writes values from/to a database.
public class DbConfigurationService : ConfigurationService
{
protected override bool ValueExists(string key)
{
using (var context = new ConfigurationContext())
{
return (from config in context.Configurations
where config.Key == key
select config).Any();
}
}

protected override string GetValueFromStore(string key)


{
using (var context = new ConfigurationContext())
{
return (from config in context.Configurations
where config.Key == key
select config.Value).First();
}
}
protected override void SetValueToStore(string key, string value)
{
using (var context = new ConfigurationContext())
{
var configuration (from config in context.Configurations
where config.Key == key
select config).FirstOrDefault();
if (configuration == null)
{
configuration = context.CreateObject<Configuration>();
configuration.Key = key;
}
configuration.Value = value;
context.SaveChanges();
}
}
}
It's best to retrieve the service from the dependency resolver or let it be injected into the classes using it
Data handling
This part of the documentation is all about data handling the way it should that is available via Catel. Some parts are based on the article on Code
Project, but this documentation is more up-to-date.
The first thing that is important is that lots of developers lose way too much time writing custom serializable objects. Serialization is a field of
expertise, and only a handful of developers I know really master the serialization of objects (think of version changes of the assembly, class
changes (new or removed properties), etc.). Most developers think they master serialization by creating a object like the code BinaryFormatter
belows show:
var serializer = new BinaryFormatter();
var myObject = (MyObject)serializer.Deserialize(stream);
Most developers dont know that reflection breaks when:
You change the version number of your assembly;
You add or remove a property or field;
You add or remove an event.
And even if you know, it takes a lot of knowledge and courage to start beating the beast of burden. Like every developer, I also encountered this
and was writing backwards compatibility code until I had enough of it and decided to master the field of serialization. The result is the ModelBase
class, which can be used as a base class for all data objects that need to be held in memory and maybe serialized to disk (or a stream, or XML, or
...).
ObservableObject
DispatcherObservableObject
ModelBase
Using ModelBase as base for entities
Advanced property change notifications
WCF services
ObservableObject
The is a very lightweight class that only implements the and interfaces. This ObservableObject INotifyPropertyChanging INotifyPropertyChanged
class is ideal for simple objects that only need property notification. Below is an example:
Don't forget to register the customized in the ConfigurationService ServiceLocator
public class Person : ObservableObject
{
private string _firstName;
private string _middleName;
private string _lastName;
public Person(string firstName, string middleName, string lastName)
{
FirstName = firstName;
MiddleName = middleName;
LastName = lastName;
}
public string FirstName
{
get { return _firstName; }
set
{
RaisePropertyChanging(() => FirstName);

var oldValue = _firstName;
_firstName = value;
RaisePropertyChanged(() => FirstName, oldValue, value);
}
}
public string MiddleName
{
get { return _middleName; }
set
{
RaisePropertyChanging(() => MiddleName);
var oldValue = _middleName;
_middleName = value;
RaisePropertyChanged(() => MiddleName, oldValue, value);
}
}
public string LastName
{
get { return _lastName; }
set
{
RaisePropertyChanging(() => LastName);
var oldValue = _lastName;
_lastName = value;
RaisePropertyChanged(() => LastName, oldValue, value);
}
}
}
DispatcherObservableObject
Note that the is located in because it uses the DispatcherObservableObject Catel.MVVM IDispatcherService
The is a class that derives from the class. The only difference is that the DispatcherObservableObject ObservableObject DispatcherObservableO
will dispatch all property change notifications to the UI thread. Below is a class that uses the and is thread-safe bject DispatcherObservableObject
for the change notifications.
public class Person : DispatcherObservableObject
{
private string _firstName;
private string _middleName;
private string _lastName;
public Person(string firstName, string middleName, string lastName)
{
FirstName = firstName;
MiddleName = middleName;
LastName = lastName;
}
public string FirstName
{
get { return _firstName; }
set
{
RaisePropertyChanging(() => FirstName);

var oldValue = _firstName;
_firstName = value;
RaisePropertyChanged(() => FirstName, oldValue, value);
}
}
public string MiddleName
{
get { return _middleName; }
set
{
RaisePropertyChanging(() => MiddleName);
var oldValue = _middleName;
_middleName = value;
RaisePropertyChanged(() => MiddleName, oldValue, value);
}
}
public string LastName
{
get { return _lastName; }
set
{
RaisePropertyChanging(() => LastName);
var oldValue = _lastName;
_lastName = value;
RaisePropertyChanged(() => LastName, oldValue, value);
}
}
}
ModelBase
Using the class
Defining properties
Default values for reference types
Functionality provided out of the box
The (previously known as the class is a generic base class that can be used for all your data classes. ModelBase DataObjectBase)
Fully serializable
It is now really easy to store objects on disk or serialize them into memory, either binary or in XML. The data object supports this out of
the box, and automatically handles the (de)serialization.
Support property changed notifications
The class supports the and interfaces so this class can easily be used in WPF, INotifyPropertyChanging INotifyPropertyChanged
Silverlight and applications to reflect changes to the user.
Backwards compatibility
When serializing your objects to binary, it is hard to maintain the right versions. When you add a new property to a binary class, or
change a namespace, the object cannot be loaded any longer. The data object base takes care of this issue and supports backwards
compatibility.
Validation
The class implements the interface so it is possible to validate the data object and check the errors. This way, no custom IDataErrorInfo
validation code needs to be written outside the data class.
Backup & revert
The class implements the interface which makes it possible to create a state of the object. Then all properties can be IEditableObject
edited, and finally, the changes can be applied or cancelled.
Using the class
Using the class is extremely simple. Just declare a new class that derives from and you are ready to go: ModelBase
/// <summary>
/// MyObject class which fully supports serialization,
/// property changed notifications, backwards compatibility and error checking.
/// </summary>
#if !SILVERLIGHT
[Serializable]
#endif
public class MyObject : ModelBase<MyObject>
{
/// <summary>
/// Initializes a new object from scratch.
/// </summary>
public MyObject() { }
#if !SILVERLIGHT
/// <summary>
/// Initializes a new object based on <see cref="SerializationInfo"/>.
/// </summary>
/// <param name="info"><see cref="SerializationInfo"/>
// that contains the information.</param>
/// <param name="context"><see cref="StreamingContext"/>.</param>
protected MyObject(SerializationInfo info, StreamingContext context)
: base(info, context) { }
#endif
}
As you can see in the code above, the class derives from and provides an empty constructor, but also a constructor that is MyObject ModelBase
used for binary deserialization. The code above might look complex, but it is created using the model code snippet, and you only have to type the
name of the class.
Defining properties
Defining properties for the class is very easy, and works the same like dependency properties. The advantages of this way of defining properties
are:
Properties defined like this are automatically included during serialization; no need to specify complex data contracts;
You can specify a default value for a property which will be used when the class is constructed or the property is not found during
deserialization (in case this property is added to an existing class);
The object can be used to retrieve property values so the compiler checks for errors; PropertyData
You can directly subscribe to change notifications, and all properties automatically support out of the box. INotifyPropertyChanged
Below is the code that defines a new property Name of type string:
/// <summary>
/// Gets or sets the name.
/// </summary>
public string Name
{
get { return GetValue<string>(NameProperty); }
set { SetValue(NameProperty, value); }
}
/// <summary>
/// Register the Name property so it is known in the class.
/// </summary>
public static readonly PropertyData NameProperty = RegisterProperty("Name",
typeof(string), string.Empty);
A registered property can be excluded from serialization if wanted. When the object is deserialized, the default value will be used for the property
in that case.
Default values for reference types
In lots of cases, a default value for reference types is required in the property definitions. However, and you might have noticed this behavior in for
example dependency properties, using an instance as default value can result in unexpected behavior.
Below is an example of a "regular" property registration using a default value for a collection property:
public static readonly PropertyData NameProperty =
RegisterProperty("PersonCollection", typeof(Collection<Person>), new
Collection<Person>());
However, instead of creating a new collection for each new object with this property, only one collection will be created that will be used by all
classes that have this property registered. One solution is to pass null as default value and create the collection in the constructor. A better
solution is to use the override of with the callback parameters: RegisterProperty
public static readonly PropertyData NameProperty =
RegisterProperty("PersonCollection", typeof(Collection<Person>), () => new
Collection<Person>());
This way, every time a new value is needed, the callback will be invoked to create the default value and you will have a true default value for
reference types.
Functionality provided out of the box
The provides a lot of functionality out of the box. A few points I want to mention are: ModelBase
INotifyPropertyChanged
All properties registered using the method automatically take care of change notifications. RegisterProperty
IDataErrorInfo
It is very easy to set field and business errors using the and methods that can be used in the overridable SetFieldError SetBusinessError Validate
and methods. Fields ValidateBusinessRules
IEditableObject
The data object can automatically create an internal backup and restore it, if required, using the interface. IEditableObject
Serialization
As told many times before, using the you can simply save your file to a stream (file on disk, stream in memory, etc.). SavableModelBase,
Keep in mind that this class is not suitable for database communication, there are much better ways to handle this (ORM mappers such as Entity
Framework, NHibernate, LLBLGen Pro, etc.).
Using ModelBase as base for entities
It is possible to use the as base class when using EF or any other OR mapper. ModelBase
Setting up ModelBase as base class
Ignoring default Catel properties in models
Setting up ModelBase as base class
There are a few caveats when using the as base class for your entities. One of them is that is always true because the ModelBase IsDirty
properties from the persistence store are set after the constructor. This guide will explain how to work past that problem.
1. Create a class named with the following code: EntityBase
public class EntityBase<T> : ModelBase<T>
where T : class
{
protected EntityBase() { }

protected EntityBase(SerializationInfo info, StreamingContext context)
: base(info, context) { }

internal void ClearDirtyFlag()
{
IsDirty = false;
}
}
2. Derive from instead of so the layer that loads the data can clear the flag. EntityBase ModelBase IsDirty
3. When loading the data from the database and setting the initial values, use this code:
var company = new DTO.Company()
{
Address = domainEntity.Address,
City = domainEntity.City,
CompanyID = domainEntity.CompanyID,
CompanyName = domainEntity.CompanyName,
PostalCode = domainEntity.PostalCode,
PostalCodeAndCity = domainEntity.PostalCodeAndCity
};
company.ClearDirtyFlag();
return company;
Note the call, which is very important to make the property behave correctly. ClearDirtyFlag IsDirty
4. Check the of the model, not the view model when checking whether the model is dirty inside a view model. IsDirty
Ignoring default Catel properties in models
It is possible to ignore the default Catel properties in the models for EF code-first. To accomplish this, use the following code:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<MyModel>().Ignore(t => t.IsDirty);
base.OnModelCreating(modelBuilder);
}
Advanced property change notifications
Sometimes the old value is needed in case of property change event. However, the interface does not provide any of INotifyPropertyChanged
this. To support this behavior, a new version of the is created called This PropertyChangedEventArgs AdvancedPropertyChangedEventArgs.
class derives from so the interfaces are not broken, but it does add additional functionality to the software system. PropertyChangedEventArgs
Getting old value automatically
Getting more information from the inside
Getting mode information from the outside
Providing old value manually
Some sidenotes
Getting old value automatically
When using the or classes, the old and new value of a property are automatically provided on a property change. ModelBase ViewModelBase
There are two ways to get more information about a property change event.
Getting more information from the inside
The easiest way to get more information on the inside is to override the method. It automatically provides an instance of the OnPropertyChanged
AdvancedPropertyChangedEventArgs:
protected override void OnPropertyChanged(AdvancedPropertyChangedEventArgs e)
{
}
Getting mode information from the outside
Getting the information from outside the objects is a bit more work. This is because the event still provides a value of the PropertyChanged Proper
class. Therefore, it is required to cast the value: tyChangedEventArgs
private void OnObjectPropertyChanged(PropertyChangedEventArgs e)
{
var advancedArgs = e as AdvancedPropertyChangedEventArgs;
if (advancedArgs != null)
{
// a value of AdvancedPropertyChangedEventArgs is now available
}
}
Providing old value manually
When using the dependency property a-like property registration, the old and new value are automatically provided by the classes. However,
when using the the old and new value are not automatically provided. Therefore, it is possible to provide these values ObservableObject,
manually:
private string _firstName;
public string FirstName
{
get { return _firstName; }
set
{
var oldValue = _firstName;
_firstName = value;

RaisePropertyChanged(() => FirstName, oldValue, value);
}
}
When the values are not provided, the old and new value are set to null.
Some sidenotes
As you might have noticed, the also provide the and the Th AdvancedPropertyChangedEventArgs IsOldValueMeaningful IsNewValueMeaningful.
ese are introduced because it is not always possible to determine the old or new value (for example, when the property name is string.Empty,
there is no old value or new value). Therefore, the and properties are null, but doesn't mean that those are the actual old and OldValue NewValue
new values.
It is always required to check whether the values are meaningful before actually handing them:
protected override void OnPropertyChanged(AdvancedPropertyChangedEventArgs e)
{
if (e.IsOldValueMeaningful)
{
// Handle old value
}
if (e.IsNewValueMeaningful)
{
// Handle new value
}
}
WCF services
Starting with version 2.3, both the windows and Silverlight (Silverlight and WP7) libraries use the to (de)serialize xml by DataContractSerializer
default for the The xml serialization technique supports complex nested object graphs. This means that classes deriving from ModelBase. ModelB
can be used to transfer data using WCF services. ase

There is no need to decorated the classes with or attributes with one single exception: when a class contains DataMember DataContract
properties that are defined using a base class, the descending (or inherited) classes must be known. Catel could, in theory, reflect the whole App
to gather these classes, but that would be a major hit on performance. Therefore the inherited classes must be defined manually using Domain
the attribute. KnownType
With the help of the plugin, it is possible to dynamically weave custom methods so no custom code is Catel.Fody GetXmlSchema
required to support WCF and DataContracts
[Serializable, KnownType(Manager), KnownType(Employee)]
public class Job : ModelBase<Job>
{
// abstract Person class which can be Manager or Employee
public Person Person { get; set; }
}
When adding the service reference, make sure to check the "Reuse types in all referenced assemblies" like shown in the image below:
Exception handling
With exception handling in Catel, it is possible to create an exception handling policy and execute code in a safe way without have to check all the
exception types manually.Catel exposes this technique via the IExceptionService.
Setting up the IExceptionService
Executing code using the IExceptionService
Executing an action
Executing a function
Use the retry capabilities
Retry Immediately
Retry defined
Process with retry
Subscribe to the retry events
Handling exceptions manually
Unregistering exceptions
Buffering
Define the way to buffer
Subscribe to the buffering events
Determine if an exception type are registered for handling
Get a specific exception handler
Setting up the IExceptionService
It is important to register an exception in the service and let Catel know how it should be handled. The service handles exceptions in the way they
are added to the . IExceptionService
The example below registers several exceptions and how they should be handled. When a occurs, it will show a message FileNotFoundException
to the user. For any other exception, it will log the exception and show a message that the user should contact the developers.
var dependencyResolver = this.GetDependencyResolver();
var exceptionService = dependencyResolver .Resolve<IExceptionService>();
exceptionService.Register<FileNotFoundException>(exception =>
dependencyResolver.Resolve<IMessageService>().Show(exception.Message));
exceptionService.Register<Exception>(exception =>
{
Log.Error(exception);
dependencyResolver.Resolve<IMessageService>().Show("An unknown exception occurred,
please contact the developers");
});
Executing code using the IExceptionService
The Process method is responsible to keep track of all exceptions which might occur and will handle them if they are registered. If one of your
registered exceptions is thrown by the code, the method will handle it and perform the action defined while the registration operation (for Process
example, by showing a message box).
The method comes in two flavors: as action and as function. Process
Executing an action
var dependencyResolver = this.GetDependencyResolver();
var exceptionService = dependencyResolver.Resolve<IExceptionService>();
exceptionService.Process(() => { throw new ArgumentOutOfRangeException(); });
Executing a function
The IExceptionService checks for type hierarchy. For example, when an exception as type Exception is registered, this handler will
handle all exceptions
var dependencyResolver = this.GetDependencyResolver();
var exceptionService = dependencyResolver.Resolve<IExceptionService>();
var result = exceptionService.Process<int>(() => 1 + 1);
Use the retry capabilities
In some cases, you can want to have possibility to retry an action a certain number of times before finally handle your exception. Let see how the I
allows us to handle this kind of cases. ExceptionService
Firstly, you need to define how the will retry your action in case of error, two possibilities are provided for that. IExceptionService
Retry Immediately
When you setting up your exceptions on , you have to additionnallyuse the method like shown below IExceptionService OnErrorRetryImmediately
:
var dependencyResolver = this.GetDependencyResolver();
var exceptionService = dependencyResolver.Resolve<IExceptionService>();
exceptionService.Register<ArgumentNullException>(exception => { /* Do something */ })
.OnErrorRetryImmediately();
This method will say to the to retry the action each times this one throw an exception until it succeed and without to wait before IExceptionService
the next retry.
Retry defined
You have also the possibility to define more deeply the way you want your actions to be retried by using the method like shown OnErrorRetry
below.
var dependencyResolver = this.GetDependencyResolver();
var exceptionService = dependencyResolver.Resolve<IExceptionService>();
exceptionService.Register<ArgumentNullException>(exception => { /* Do something */ })
.OnErrorRetry(5, TimeSpan.FromMinutes(2));
Where 5 represents the nombre of times the action will be retried and the interval between theretries. TimeSpan.FromMinutes(2)
Process with retry
If you have provided a retry policy, you can use the method to expect have your policy applied on error. Below an example : ProcessWithRetry
var dependencyResolver = this.GetDependencyResolver();
var exceptionService = dependencyResolver.Resolve<IExceptionService>();
exceptionService.ProcessWithRetry(() =>
{
/* Do something */
});
In .NET 4.5, you can process yours actions asynchronously by using the method. ProcessAsync
You can also specify the number of times you want the to retry immediately like this for example : IExceptionService OnErrorRetryImme
diately(5)
Subscribe to the retry events
Can you subscribe to the events which are thown each time an action is retried like this :
var dependencyResolver = this.GetDependencyResolver();
var exceptionService = dependencyResolver.Resolve<IExceptionService>();
exceptionService.RetryingAction +=
(sender, eventArgs) =>
Console.WriteLine("The '{0}' have caused retrying action for the
'{1}' times.",
eventArgs.LastException, eventArgs.CurrentRetryCount);
Handling exceptions manually
It is possible to manually handle exceptions using the service. This is useful when you don't want to wrap code in the Process method, but still
want to be able to create a generic exception handling policy.
var dependencyResolver = this.GetDependencyResolver();
var exceptionService = dependencyResolver.Resolve<IExceptionService>();
try
{
var value = 150/0;
}
catch (DivideByZeroException exception)
{
exceptionService.HandleException(exception);
}
If the exception can be handled, the registered action will be executed, but your code can safely continue. If the exception (in this case DivideByZ
) is not registered, the method will rethrow the exception. eroException HandleException
Unregistering exceptions
Although it will probably hardly used, it is possible to unregister exceptions again using the code below:
var exceptionService = dependencyResolver.Resolve<IExceptionService>();
exceptionService.Unregister<ArgumentException>();
Buffering
Define the way to buffer
You can want to throttle downthe number of exceptions you receive when a production process goes awry for example. You can do it through the
extension method as shown below : UsingTolerance
var dependencyResolver = this.GetDependencyResolver();
var exceptionService = dependencyResolver.Resolve<IExceptionService>();
exceptionService.Register<DivideByZeroException>(exception => { })
.UsingTolerance(9, TimeSpan.FromSeconds(10.0));
Here, the idea is to only receive the 10 exception message.
th
Subscribe to the buffering events
Can you subscribe to the events which are thown each time an exception is buffered like this :
var dependencyResolver = this.GetDependencyResolver();
var exceptionService = dependencyResolver.Resolve<IExceptionService>();
exceptionService.ExceptionBuffered +=
(sender, eventArgs) =>
Console.WriteLine("The '{0}' is buffered for at '{1}'.",
eventArgs.BufferedException, eventArgs.DateTime);
Determine if an exception type are registered for handling
If you want to know if an exception type have its policy registered on the , you can do this by using the m IExceptionService IsExceptionRegistered
ethod like shown below:
var dependencyResolver = this.GetDependencyResolver();
var exceptionService = dependencyResolver.Resolve<IExceptionService>();
if (exceptionService.IsExceptionRegistered<ArgumentNullException>())
{
//Do something
}
Get a specific exception handler
If you want to retrieve the registered exception handler for an exception type, you have to use the method like shown below : GetHandler
var dependencyResolver = this.GetDependencyResolver();
var exceptionService = dependencyResolver.Resolve<IExceptionService>();
var exceptionHandler = exceptionService.GetHandler<ArgumentException>();
IoC (ServiceLocator and TypeFactory)
Before Catel 2.0, the IoC container used internally was Unity. However, this forced all users to use and configure Unity as the IoC container in
their apps and required the shipping of the libraries as well. Since Catel 2.0, a different technique is used which allows the end-developer to use
the IoC container technique of their choice.
Different components in IoC
Getting components for any object
Also see:
Introductions to IoC components
Automatic type registration
Setting up the ServiceLocator using configuration
Replacing the default components
Different components in IoC
There are several different components that are very important for the IoC in Catel:
ServiceLocator
Component that is responsible for the registrations of all types. This is the actual IoC container.
TypeFactory
Component that is responsible to create types. This uses the to retrieve the types which are required to instantiate a IServiceLocator
type.
DependencyResolver
Light-weight implementation of the which does not expose any register methods, but only allows to resolve types. IServiceLocator
Getting components for any object
In every object, it is possible to use the properties to retrieve the instances of each component. This will cause problems when different Default
scoping is used. To always be sure to get the right component for the object you are working with, it is recommended to use the following
extension methods:
using Catel.IoC; // Contains ObjectExtensions which allow use of below extension
methods
public class MyService
{
public void SomeMethod()
{
// If you need to create a type with the current scope type factory
var typeFactory = this.GetTypeFactory();

// If you need to register a type with the current scope service locator
var serviceLocator = this.GetServiceLocator();

// If you need to resolve a type with the current scope and the type is not
injected via dependency injection
var dependencyResolver = this.GetDependencyResolver();
}
}
Introductions to IoC components
This section contains the introductions.
Introduction to the ServiceLocator
Introduction to the TypeFactory
Introduction to DependencyResolver and DependencyResolverManager
Dependency injection
Ensuring integrity of the ServiceLocator
Introduction to the ServiceLocator
The services as the container inside Catel. ServiceLocator
Internally it uses the as instantiator for the services. TypeFactory
Catel uses it's own implementing the to gather all services required by Catel. For example, default services are ServiceLocator IServiceLocator
the and the . By default, when the first view model is instantiated, Catel registers all default out of the box IPleaseWaitService IUIVisualizerService
services to the . However, it only does this when the specific services are not already registered. This allows an end-developer to ServiceLocator
register his/her own implementations of the services before any view model is instantiated (for example, at application startup).
The can be instantiated, but Catel instantiates one instance that can be used and shared amongst all objects inside the same ServiceLocator App
. The can be retrieved by using . . Domain ServiceLocator ServiceLocator Default
Registering a type
Use the following code to register a specific type in the : ServiceLocator
ServiceLocator.Default.RegisterType<IPleaseWaitService, PleaseWaitService>();
For more information how types are instantiated and dependency injection, take a look at the TypeFactory documentation
1.
2.
3.
Registering a late-bound type
Use the following code to register a late-bound type in the : ServiceLocator
ServiceLocator.Default.RegisterType<IPleaseWaitService>(x => new PleaseWaitService());
Registering an instance of a type
Catel uses the or to create the interface implementations when the object is first resolved. However, TypeFactory Activator.CreateInstance
sometimes a service constructor requires parameters or takes a long time to construct. In such cases, it is recommended to create the type
manually and register the instance of the type:
var pleaseWaitService = new PleaseWaitService();
ServiceLocator.Default.RegisterInstance<IPleaseWaitService>(pleaseWaitService);
Registering a type via MissingType event
The gives the end-developer a last-resort chance to register a type when it is not registered in the ServiceLocator or any of the ServiceLocator
external containers. This event is very useful for logging (then the developer in the log knows exactly what type is missing from the IoC container)
or it can be used to determine at runtime in a very late stage what implementation of the service must be used. To register a type via the event,
subscribe to the event and then use the following code:
private void OnMissingType(object sender, MissingTypeEventArgs e)
{
if (e.InterfaceType == typeof(IPleaseWaitService))
{
// Register an instance
e.ImplementingInstance = new PleaseWaitService();
// Or a type
e.ImplementingType = typeof(PleaseWaitService);
}
}
If both the and are filled, the will be used. ImplementingInstance ImplementingType ImplementingIntance
Resolving a type
To retrieve the implementation of a service, use the following code:
var pleaseWaitService = ServiceLocator.Default.ResolveType<IPleaseWaitService>();
Introduction to the TypeFactory
Dependency injection
Introduction to dependency injection
Using dependency injection in Catel
Disabling dependency injection
Custom initialization
The is responsible for actually creating types inside Catel. It uses the following mechanism: TypeFactory
List all the constructors, order them from most parameters to least parameters
While (constructors available)
try to construct type using injection
If all constructors fail, the will fallback to TypeFactory Activator.CreateInstance()
Dependency injection
The ServiceLocator in Catel supports dependency injection.
Introduction to dependency injection
Some people make dependency injection hard to understand, or maybe they don't understand it themselves. Dependency injection simply means
that instead of hard referencing or instantiating other classes (dependendies), the dependencies are injected into the class via the constructor.
Example 1: bad, instantiates the dependencies itself
public class MyClass
{
private IFirstDependency _firstDependency;
private ISecondDependency _secondDependency;
public MyClass()
{
_firstDependency = new FirstDependency();
_secondDependency = new SecondDependency();
}
}
Example 2: good, retrieves the dependencies via the service locator
public class MyClass
{
private IFirstDependency _firstDependency;
private ISecondDependency _secondDependency;
public MyClass()
{
_firstDependency = ServiceLocator.Instance.ResolveType<IFirstDependency>();
_secondDependency = ServiceLocator.Instance.ResolveType<ISecondDependency>();
}
}

Example 3: good, gets the dependencies injected


1.
2.
3.
public class MyClass
{
private IFirstDependency _firstDependency;
private ISecondDependency _secondDependency;
public MyClass(IFirstDependency firstDependency, ISecondDependency
secondDepdenceny)
{
Argument.IsNotNull("firstDependency", firstDependency);
Argument.IsNotNull("secondDependency", secondDependency);
_firstDependency = firstDependency;
_secondDependency = secondDependency;
}
}
Using dependency injection in Catel
Dependency injection via the ServiceLocator in Catel is enabled by default. This means that when a type is resolved from the container, it will
automatically use dependency injection to construct the type if it is not registered as instance.
It will first search for all available constructors on the type that will be instantiated. Then, for each constructor, starting with the one with the most
parameters, it will try to retrieve all values. If one fails, it will go to the next. If all fail, it will try to use the default constructor without parameters. If
that fails as well, then the type cannot be constructed and an exception will be thrown.
To get a better understanding of what happens, see the class below:
public class MyClass
{
private IFirstDependency _firstDependency;
private ISecondDependency _secondDependency;
public MyClass()
: this(null) { }
public MyClass(IFirstDependency firstDependency)
: this(firstDependency, null) { }
public MyClass(IFirstDependency firstDependency, ISecondDependency
secondDepdenceny)
{
_firstDependency = firstDependency;
_secondDependency = secondDependency;
}
}
When the MyClass will be retrieved from the ServiceLocator, this will happen:
Find constructor with most parameters (the one with both firstDependency and secondDependency). If both IFirstDependency and
ISecondDependency can be resolved from the ServiceLocator, the type will be constructed with the constructor. Otherwise it will proceed
with step 2.
Find next constructor with most parameters (the one with only firstDependency). If IFirstDependency can be resolved from the
ServiceLocator, the type will be constructed with the constructor. Otherwise it will proceed with step 3.
At this point, no constructor could be used. In this case, the ServiceLocator will try to use the default constructor (the one without
parameters) as last resort to instantiate the type.
There are other ways of using dependency injection, for example via attributes. This documentation will focus on dependency injection
via the constructor only
Disabling dependency injection
Maybe you don't want dependency injection because it does not give you what you need or you want a very, very small improvement in
performance. In that case, the dependency injection can be disabled using the code below:
ServiceLocator.Default.SupportedDependencyInjection = false
Custom initialization
All types created with the can be initialized with custom code. This can be done by implementing the interf TypeFactory INeedCustomInitialization
ace.As soon as a type is created, the will check whether it implements the interface. If so, it will call the TypeFactory INeedCustomInitialization Ini
method of the interface. tialize
Introduction to DependencyResolver and DependencyResolverManager
Why the need for a DependencyResolver
Managing the dependency resolvers per instance
Registering a dependency resolver for an instance
Retrieving a dependency resolver for an instance
Managing the dependency resolvers per type
Registering a dependency resolver for a type
Retrieving a dependency resolver for a type
Customizing the default DependencyResolver
Customizing the DependencyResolverManager
Managing different scoping of service locators and dependency injection can be hard. To aid developers with this, the and IDependencyResolver
are introduced. DependencyResolverManager
Why the need for a DependencyResolver
That's a good question. Catel already provides the which allows to resolve types. The downside is that if you want to customize IServiceLocator
the way dependencies are resolved in Catel, you will have to implement a custom version of the . To make it simple to customize ServiceLocator
this behavior, the is introduced. DependencyResolver
Though in simple situations, Catel will resolve and inject all types automatically, there are a few exceptions to the rule. One of these exceptions
are extension methods. These are static classes which can be used to add functionality to an object. The downside is that you cannot use
dependency injection in static classes, and each object that is extended can have their own scoping of dependency resolvers. To solve this issue,
Catel introduces the . This is a manager that keeps track of all types and objects and the that DependencyResolverManager DependencyResolver
were used to create the object. This way it is still possible to retrieve additional dependencies in extensions methods in the dependency same
resolver the type was created with.
To illustrate this issue, take a look at the view model below:
// Set up a different scoping with a custom service locator
var serviceLocator = new ServiceLocator();
// ... register custom services here
var typeFactory = serviceLocator.ResolveType<ITypeFactory>();

var vm = typeFactory.CreateInstance<MyViewModel>();
In this example, a view model is created with a custom dependency scope. When writing an extension method for the view models, it is
impossible to get to this custom scope:
To prevent misuse of the method, it is best to implement the interface explicitly Initialize
The main strategy will be to use the instead of to resolve the types in Catel, starting with version DependencyResolver ServiceLocator
3.8
public static class MyViewModelExtensions
{
public static void DoSomething(this MyViewModel myViewModel)
{
// You can use ServiceLocator.Default here, but that is a *different and
wrong* scope
var additionalDependency =
ServiceLocator.Default.ResolveType<IAdditionalDependency>();
}
}
One option to solve this is to create a property on the view model called or . However, it is the DependencyResolver ServiceLocator not
responsibility of the view model to store this property. In fact, the view model does not know which scoping was used to create itself. The only way
to solve this is to inject the into the view model, but that's not a good practice. IServiceLocator
Below is a rewritten version of the extensions class which uses the : DependencyResolverManager
public static class MyViewModelExtensions
{
public static void DoSomething(this MyViewModel myViewModel)
{
// Get the *right* scope
var dependencyResolverManager = DependencyResolverManager.Default;
var dependencyResolver =
dependencyResolverManager.GetDependencyResolverForInstance(myViewModel);
var additionalDependency =
dependencyResolver.Resolve<IAdditionalDependency>();
}
}
Now you have the actual that was use to create the view model and can easily provide the right logic with the right scoping. IDependencyResolver
Managing the dependency resolvers per instance
The can manage dependency resolvers per instance. This way it is possible to retrieve the actual dependency DependencyResolverManager
resolver for a specific object instance.
Registering a dependency resolver for an instance
To register a dependency resolver for an instance, use this code:
var serviceLocator = new ServiceLocator();
var dependencyResolver = new CatelDependencyResolver(serviceLocator);
var myObject = new MySpecialObject();

var dependencyResolverManager = DependencyResolverManager.Default;


dependencyResolverManager.RegisterDependencyResolverForInstance(myObject,
dependencyResolver);
Note that there will only be a single instance of a . It is possible to customize the default instance, but DependencyResolverManager
there is no need for different scoping of instances so it is valid to use the static instance DependencyResolverManager
Note that it is not required to register a for instances created with the . The automaticall DependencyResolver TypeFactory TypeFactory
y registers the used in the . DependencyResolver DependencyResolverManager
Retrieving a dependency resolver for an instance
To retrieve the dependency resolver for a specific instance, use this code:
var dependencyResolverManager = DependencyResolverManager.Default;
var dependencyResolver =
dependencyResolverManager.GetDependencyResolverForInstance(myObject);
Below is a graph that shows how the dependency resolver of an instance is determined:
Managing the dependency resolvers per type
The can manage dependency resolvers per type. This way it is possible to retrieve the actual dependency resolver DependencyResolverManager
for a specific type.
Registering a dependency resolver for a type
To register a dependency resolver for a type, use this code:
var serviceLocator = new ServiceLocator();
var dependencyResolver = new CatelDependencyResolver(serviceLocator);

var dependencyResolverManager = DependencyResolverManager.Default;


dependencyResolverManager.RegisterDependencyResolverForType(typeof(MyClass),
dependencyResolver);
Retrieving a dependency resolver for a type
To retrieve the dependency resolver for a specific instance, use this code:
var dependencyResolverManager = DependencyResolverManager.Default;
var dependencyResolver =
dependencyResolverManager.GetDependencyResolverForType(typeof(MyClass));
Customizing the default DependencyResolver
By default, the creates a that wraps the instance. In simple DependencyResolverManager CatelDependencyResolver ServiceLocator.Default
applications this is sufficient to get everything working. However sometimes it might be needed to customize the default . To DependencyResolver
change the default one, use the code below:
Note that these registrations are type-specific. You cannot register an interface and all classes deriving from that interface will return the
same . All actual types must be registered separately. DependencyResolver
var dependencyResolverManager = DependencyResolverManager.Default;
dependencyResolverManager.DefaultDependencyResolver = new
MyCustomDependencyResolver();
Customizing the DependencyResolverManager
Customizing the is not recommended. If you still want to do this for whatever reason, create a class implementing DependencyResolverManager
the or derive from the : IDependencyResolverManager DependencyResolverManager
public class CustomizedDependencyResolverManager : DependencyResolverManager
{
public override IDependencyResolver GetDependencyResolverForType(Type type)
{
if (type == typeof(MySpecialClass))
{
return new MySpecialDependencyResolver();
}

return base.GetDependencyResolverForType(type);
}
}
Then set the static property: DependencyResolverManager.Default
DependencyResolverManager.Default = new CustomizedDependencyResolverManager();
Dependency injection
The ServiceLocator in Catel supports dependency injection.
Introduction to dependency injection
Using dependency injection in Catel
Constructor injection
Manually defining the constructor to use for dependency injection
Advanced dependency injection
Property injection
Type is automatically determined based on property type
Type is manually defined
Using tags
Disabling dependency injection
Introduction to dependency injection
Some people make dependency injection hard to understand, or maybe they don't understand it themselves. Dependency injection simply means
that instead of hard referencing or instantiating other classes (dependendies), the dependencies are injected into the class via the constructor.
Example 1: bad, instantiates the dependencies itself
Note that there is no use to override the as the example, but this keeps it easy to understand DependencyResolverManager
public class MyClass
{
private IFirstDependency _firstDependency;
private ISecondDependency _secondDependency;
public MyClass()
{
_firstDependency = new FirstDependency();
_secondDependency = new SecondDependency();
}
}

Example 2: good, retrieves the dependencies via the service locator


public class MyClass
{
private IFirstDependency _firstDependency;
private ISecondDependency _secondDependency;
public MyClass()
{
_firstDependency = ServiceLocator.Instance.ResolveType<IFirstDependency>();
_secondDependency = ServiceLocator.Instance.ResolveType<ISecondDependency>();
}
}

Example 3: good, gets the dependencies injected


public class MyClass
{
private IFirstDependency _firstDependency;
private ISecondDependency _secondDependency;
public MyClass(IFirstDependency firstDependency, ISecondDependency
secondDepdenceny)
{
Argument.IsNotNull("firstDependency", firstDependency);
Argument.IsNotNull("secondDependency", secondDependency);
_firstDependency = firstDependency;
_secondDependency = secondDependency;
}
}
Using dependency injection in Catel
There are other ways of using dependency injection, for example via attributes. This documentation will focus on dependency injection
via the constructor only
1.
2.
3.
Constructor injection
Dependency injection via the ServiceLocator in Catel is enabled by default. This means that when a type is resolved from the container, it will
automatically use dependency injection to construct the type if it is not registered as instance.
It will first search for all available constructors on the type that will be instantiated. Then, for each constructor, starting with the one with the most
parameters, it will try to retrieve all values. If one fails, it will go to the next. If all fail, it will try to use the default constructor without parameters. If
that fails as well, then the type cannot be constructed and an exception will be thrown.
To get a better understanding of what happens, see the class below:
public class MyClass
{
private IFirstDependency _firstDependency;
private ISecondDependency _secondDependency;
public MyClass()
: this(null) { }
public MyClass(IFirstDependency firstDependency)
: this(firstDependency, null) { }
public MyClass(IFirstDependency firstDependency, ISecondDependency
secondDependency)
{
_firstDependency = firstDependency;
_secondDependency = secondDependency;
}
}
When the MyClass will be retrieved from the ServiceLocator, this will happen:
Find constructor with most parameters (the one with both firstDependency and secondDependency). If both IFirstDependency and
ISecondDependency can be resolved from the ServiceLocator, the type will be constructed with the constructor. Otherwise it will proceed
with step 2.
Find next constructor with most parameters (the one with only firstDependency). If IFirstDependency can be resolved from the
ServiceLocator, the type will be constructed with the constructor. Otherwise it will proceed with step 3.
At this point, no constructor could be used. In this case, the ServiceLocator will try to use the default constructor (the one without
parameters) as last resort to instantiate the type.
Manually defining the constructor to use for dependency injection
Catel first sorts the constructors based on the number of parameters. Then it will "sub-sort" the same number of parameters and puts parameters
with Object and DynamicObject as last so it will first try all constructors with the best possible matches
If Catel is still unable to pick the right constructor in a class, this behavior can be overridden by decorating the constructor with theDependencyInj
attribute: ectionConstructor
public MyClass(IPerson person)
{

[InjectionConstructor]
public MyClass(Person person)
{
// Catel will now first try to use this constructor, no matter the order or number
of parameters
}
Advanced dependency injection
Starting with Catel 3.7, a new type of dependency injection is supported. It allows a developer to instantiate types that combine custom
constructor injection with dependency injection. The class belows shows an interesting combination of custom values that need to be injected and
dependencies that can be retrieved from the IoC container. Before Catel 3.7, one had to manually retrieve the dependencies from the IoC
container when it also required other dependencies to be injected that were not registered in the IoC container:
public class PersonViewModel : ViewModelBase
{
private readonly IMessageService _messageService;
private readonly IProcessService _processService;

public PersonViewModel(IPerson person)


{
Argument.IsNotNull(() => person);

Person = person;

_messageService = ServiceLocator.Default.ResolveType<IMessageService>();
_processService = ServiceLocator.Default.ResolveType<IProcessService>();
}

...
}
With the new technology, such a constructor can be rewritten to truly support dependency injection:
public class PersonViewModel : ViewModelBase
{
private readonly IMessageService _messageService;
private readonly IProcessService _processService;

public PersonViewModel(IPerson person, IMessageService messageService,


IProcessService processService)
{
Argument.IsNotNull(() => person);
Argument.IsNotNull(() => messageService);
Argument.IsNotNull(() => processService);

Person = person;

_messageService = messageService;
_processService = processService
}

...
}

The advanced dependency injection can be used by using the class. Below is an example on how to create a new type using TypeFactory
advanced dependency injection:
This feature is initially written to support dependency injection in combination with nested user controls
var personViewModel =
TypeFactory.Default.CreateInstanceWithParametersAndAutoCompletion<PersonViewModel>(new
Person());
As you can see it is only required to pass in the objects that are not registered in the IoC container. All other dependencies will be automatically
resolved from the . ServiceLocator
Property injection
Starting with Catel 3.8, it is also possible to use property injection. The difference with constructor injection is that the will TypeFactory
automatically set up all properties that required dependency injection.
To use property injection, simply decorate the properties of a class with the attribute. Below are several options: Inject
Type is automatically determined based on property type
public class MyClass
{
[Inject]
public IMyDependency MyDependency { get; set; }
}
Type is manually defined
public class MyClass
{
[Inject(typeof(IMySubclassedDependency))]
public IMyDependency MyDependency { get; set; }
}
Using tags
It is also possible to determine the tag of a registered dependency:
public class MyClass
{
[Inject(Tag = "myTag")]
public IMyDependency MyDependency { get; set; }
}
Disabling dependency injection
Maybe you don't want dependency injection because it does not give you what you need or you want a very, very small improvement in
performance. In that case, the dependency injection can be disabled using the code below:
Note that the order of the parameters must be the same as the constructor, otherwise the cannot determine the right TypeFactory
constructor to use
Note that the Catel team recommends using constructor injection over property injection because it allows you to check for values null
and store dependencies in private fields
ServiceLocator.Default.SupportedDependencyInjection = false
Ensuring integrity of the ServiceLocator
Starting with Catel 3.6, a very useful feature has been added to the and . This features is called "integrity checker" ServiceLocator TypeFactory
and will ensure you with useful information about type registration paths. This protection mechanism is very useful in complex applications. When
people start building services, sometimes they accidentally inject other services that via injection to other services cause a stack overflow.
Debugging and determining which type is causing the issue can be very time-consuming.To make the example a bit more simple, below are a
few classes which demonstrate a common issue in enterprises.
public class X
{
public X(Y y) { }
}
public class Y
{
public Y(Z z) { }
}
public class Z
{
public Z(X x) { }
}
Note how a round-trip of dependencies is created which will result in a StackOverflowException somewhere in your code.Below is a graphical
example what happens. Note that the dotted line is showing the circular dependency causing the . StackOverflowException
TypeRequestInfo
The first step for the integrity checker is to make sure that it knows what types are being requested from the (which will be ServiceLocator
instantiated by the if required). This class contains all the information about a type being created by the TypeFactory TypeFactory:
Type
Tag (optional, can be used to differentiate different instances of the same type registration)
TypeRequestPath
Now we have detailed information about the types being constructed, it is very important to keep track of the types which are being created by the
. During the construction of a type, the will request the for a type, which will ask the to TypeFactory TypeFactory ServiceLocator TypeFactory
construct the type again.Each time the starts constructing a type (and currently has a ), it will create a new TypeFactory TypeRequestPath
instance of the and add it to the . The diagram below shows how the will evolve. TypeRequestInfo TypeRequestPath TypeRequestPath
Once the will contain a duplicate instance of a , it will become invalid (which means there is a circular type TypeRequestPath TypeRequestInfo
dependency).
Checking the integrity of the type request
To resolve and construct a type, a lot of communication will happen between the and the . TypeFactory ServiceLocator This flow is show in the
diagram below.
As you can see, there is a lot of communication between the and . In the example we already saw ServiceLocator TypeFactory TypeRequestPath
how the path will become invalid when it contains a duplicate instance of the . The will then throw a TypeRequestInfo TypeRequestPath CircularD
with all the necessary information to solve the issue: ependencyException
Note that this is a very simple example, but normally a type will have several services injected which can have dependencies on their
own as well which can cause a very complex type request path
Now you will find the issue in no-time and save yourself a lot of your valuable time!
Automatic type registration
This section contains all the information about automatic type registration.
Automatically registering types using attributes
Automatically registering types using conventions
Automatically registering types using attributes
The in Catel can be set up to discover attribute based registration. ServiceLocator
Declaring a registration since the type definition
There is a way to automatically register types into a service locator. Using it is possible to register types into ServiceLocatorRegistrationAttribute
the service locator in a declarative way. The following code shows how use this attribute:
[ServiceLocatorRegistration(typeof(IMyClass))]
public class MyClass : IMyClass
{
}
All registration options are available in attribute based registration, such as registration type and tag, as const ServiceLocatorRegistrationAttribute
ructor arguments. The following code shows how use such options (it registers the using the interface in a transient way (new MyClass IMyClass
type every time it is resolved) using the tag : MyTag
[ServiceLocatorRegistration(typeof(IMyClass), RegistrationType.Transient, "MyTag")]
public class MyClass : IMyClass
{
}
Activating service locator to scan for automatically registration
By default the service locator doesn't scan for automatic registration. In order to activate this you should set to AutoRegisterTypesViaAttributes tru
. e
var serviceLocator = ServiceLocator.Default;
serviceLocator.AutoRegisterTypesViaAttributes = true;
Automatically registering types using conventions
The in Catel can be set up to automatically register types based on the conventions. ServiceLocator
Register using Naming Convention
Register using FirstInterfaceConvention
Filter types to register
Exclude all types of the namespace containing the specified type
Exclude a specific type
Exclude types using predicate
Some conventions are provided by default to allow us to register types.
Register using Naming Convention
You can want to register all types which match with the default naming convention, means when I have a interface, I expect the IService
convention to find and register the class as implementation. Service
To discover types for naming convention registration, we have to simply do :
var serviceLocator = new ServiceLocator();
serviceLocator.RegisterTypesUsingDefaultNamingConvention();
Register using FirstInterfaceConvention
You can want to register all types which match with the default first interface convention, means when I have a class which implements Service
more than one interface, I expect the convention to find the first interface and use it as service registration.
To discover types for first interface convention registration, we have to simply do :
var serviceLocator = new ServiceLocator();
serviceLocator.RegisterTypesUsingDefaultFirstInterfaceConvention();
Filter types to register
You have the ability to apply filtering on the registration process to exclude for example or include some types.
Exclude all types of the namespace containing the specified type
If you want to exclude all types of the namespace which belong to a particular type, just do that:
var serviceLocator = new ServiceLocator();
serviceLocator.RegisterTypesUsingDefaultNamingConvention()
.ExcludeAllTypesOfNamespaceContaining<IFooService>();
Here, we say to the to ignore all types included into the namespace which belong to the type. ServiceLocator IFooService
The convention based registration should to be run first than the others registration methods to be sure to have all your types registered
correctly.
Exclude a specific type
If you want to exclude a specific type, you can do that by using the method like shown below: ExcludeType
var serviceLocator = new ServiceLocator();
serviceLocator.RegisterTypesUsingDefaultNamingConvention()
.ExcludeType<IFooService>();
The will be exclude on the registration process. IFooService
Exclude types using predicate
You also have the possibility to filter types by using a predicate, below an example :
var serviceLocator = new ServiceLocator();
serviceLocator.RegisterTypesUsingDefaultNamingConvention()
.ExcludeTypesWhere(type => type == typeof(IFooService));

Setting up the ServiceLocator using configuration


The in Catel can be set up from configuration file. ServiceLocator
Importing IoC configuration section
Configuring a service locator from the default configuration
Configuring a service locator from a named configuration
Importing IoC configuration section
The first step to setup the service locator from the configuration file is import the custom section type from Catel.IoC.IoCConfigurationSection Cat
. The following example shows how to import this configuration section and make it available for the configuration file as : el.Core ioc
<configuration>
<configSections>
<sectionGroup name="catel">
<section name="ioc" type="Catel.IoC.IoCConfigurationSection, Catel.Core" />
</sectionGroup>
</configSections>
...
</configuration>
Configuring a service locator from the default configuration
You can manually specify the namespace of the types to exclude using the method like this: ExcludeAllTypesOfNamespace ExcludeAll
TypesOfNamespace("MyNamespace")
All methods have an version Exclude Include
In the example above we also create a section group named catel to group all Catel related configuration sections.
It's possible add more than one service locator configuration to the configuration file but you must specify an unique name. If a name of a service
locator configuration is not specified then the name is assigned. By default such configuration supports dependency injection. default
<configuration>
<configSections>
<sectionGroup name="catel">
<section name="ioc" type="Catel.IoC.IoCConfigurationSection, Catel.Core" />
</sectionGroup>
</configSections>
<catel>
<ioc>
<serviceLocatorConfigurations>
<serviceLocatorConfiguration [name="default"]
[supportDependencyInjection="true"]>
<register interfaceType="Catel.MVVM.Services.IUIVisualizerService"
implementationType="Catel.MVVM.Services.UIVisualizerService" />
<register interfaceType="Catel.MVVM.Services.IProcessService"
implementationType="Catel.MVVM.Services.ProcessService" />
</serviceLocatorConfiguration>
</serviceLocatorConfigurations>
</ioc>
</catel>
</configuration>

To configure a service locator from the default service locator configuration use the following code:

var serviceLocator = ServiceLocator.Default;


Configuration configuration =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var ioc = configuration.GetSection<IoCConfigurationSection>("ioc", "catel");
ioc.DefaultServiceLocatorConfiguration.Configure(serviceLocator);
Configuring a service locator from a named configuration
The following configuration file is a full example on how write more than one service locator configuration:
<configuration>
<configSections>
<sectionGroup name="catel">
<section name="ioc" type="Catel.IoC.IoCConfigurationSection, Catel.Core" />
</sectionGroup>
</configSections>
<catel>
<ioc>
<serviceLocatorConfigurations>
<serviceLocatorConfiguration>
<register interfaceType="Catel.MVVM.Services.IUIVisualizerService"
implementationType="Catel.MVVM.Services.UIVisualizerService" />
<register interfaceType="Catel.MVVM.Services.IProcessService"
implementationType="Catel.MVVM.Services.ProcessService" />
</serviceLocatorConfiguration>
<serviceLocatorConfiguration name="test"
supportDependencyInjection="false">
<register interfaceType="Catel.MVVM.Services.IUIVisualizerService"
implementationType="Catel.MVVM.Services.Test.UIVisualizerService"
registrationType="Transient"/>
<register interfaceType="Catel.MVVM.Services.IProcessService"
implementationType="Catel.MVVM.Services.Test.ProcessService" tag="test"/>
</serviceLocatorConfiguration>
</serviceLocatorConfigurations>
</ioc>
</catel>
</configuration>
To configure a service locator from a named configuration use the following code:
var serviceLocator = ServiceLocator.Default;
Configuration configuration =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var ioc = configuration.GetSection<IoCConfigurationSection>("ioc", "catel");
ioc.GetServiceLocatorConfiguration("test").Configure(serviceLocator);
You should also note the options setup if the container in order to support dependency injection and the
registration type (a.k.a instantiation style) and the tag for each registration.
Replacing the default components
By default, Catel provides very fast and functional implementations of the component interfaces. It is possible though that one needs to use a
different container than the specified ones.
Replacing default components
Creating IoC components in code
Replacing default components
Starting with Catel 3.9, it is very easy to customize the components. This can be achieved by customizing the factory methods that are available
on the class. IoCConfiguration
Note that when any component is replaced, it must be registered with the other instances that are already running. Catel cannot do this
automatically because it is not aware how other (customized) components interact or require registration.
To replace any component, first create a custom implementation of the specific component, for example the . Then update the IServiceLocator
factory and call : UpdateDefaultComponents
Catel.IoC.IoCFactory.CreateServiceLocatorFunc = () => new MyCustomServiceLocator();
Catel.IoC.IoCFactory.CreateTypeFactoryFunc = () => new MyCustomTypeFactory();

Catel.IoC.IoCConfiguration.UpdateDefaultComponents();
At this moment, Catel will fully replace the components (in this case the and ), but will keep using the default IServiceLocator ITypeFactory
implementation of the . IDependencyResolver
Creating IoC components in code
It is best to respect the customization of the IoC components in the code. Therefore it is wise to always use the to create a IoCFactory ServiceLoc
when a is needed: ator new instance
var serviceLocator = IoCFactory.CreateServiceLocator();
Catel will automatically create the right and and register them in the newly created . IDependencyResolver ITypeFactory IServiceLocator
Logging
Starting with version 2.2, Catel uses a custom internal logging system. This way, the reference to log4net could be removed. The idea behind this
move is not to force the user to use log4net. Also, log4net seems deprecated (no new releases for a long time), and other logging systems such
as NLog seem to grow in popularity.
The new logging system only allows very basic logging. This way, the logging is kept very simple and the real logging can be implemented by the
end-developer if he/she feels the need for it.
Table of contents
Log and ILog
LogManager
Logging in code
Logging to the output window or console
Overriding global log level flags
Other info
Customizing listeners
Batch log listeners
Integration with external loggers
Writing logs to disk
Creating log listeners via configuration
Anotar.Catel.Fody
Log and ILog
All logging is available via the ILog interface. This interface is registered automatically on all objects in Catel as Log field. This way, every object
can log any information by calling methods on the Log field.
In Catel, there is only one implementation of the ILog interface, which is the Log class. This class makes sure that the log messages are formatted
correctly and the LogMessage event is invoked when a message is written to the log.
Catel internally creates a separate log per type. This way, there will be lots of logs and it should be easy to filter the information the end-developer
is really interested in.
LogManager
The LogManager is the class where it all comes together. This class is responsible for creating new logs for types, but also keeps track of all logs
Note that the customization of the IoCConfiguration is the thing that must be done at application start up first
and log listeners. To retrieve the log for a specific class, use the following code:
private static readonly ILog Log = LogManager.GetCurrentClassLogger();
Logging in code
To log in code, the ILog interface implements some basic methods to log information with an option for extra data. There are however lots of
extension methods available to log exceptions, string formats and more. Below is an example of logging in code:
Log.Warning("Customer '{0}' does not exist", customerId);
Or, if an exception is available, this can written to the log as well.
Log.Error(ex, "Failed to delete file '{0}'", fileName);
Logging to the output window or console
By default, Catel does not add any listeners. However, it contains a ready-to-use implementation that writes all logs to the output window or
console, which is the DebugLogListener. To register this listener, call this at any time:
#if DEBUG
LogManager.AddDebugListener();
#endif
Overriding global log level flags
Start with Catel 3.8, it is possible to override the global log level flags for all listeners. To do this, set the corresponding flag on the to LogManager
a value. For example, to force debug logging on all log listeners, use the code below:
LogManager.IsDebugEnabled = true;
To reset the override, set the value back to : null
LogManager.IsDebugEnabled = null;
Customizing listeners
Each listener can be customized to only receive the logs that the listener is interested in. This way, the listener does not receive events it is not
interested in. For example, to only receive errors, create a new listener and use the following customization:
Prior to Catel 3.8, one should use instead LogManager.RegisterDebugListener()
1.
2.
3.
var listener = new MyLogListener();
listener.IsDebugEnabled = false;
listener.IsInfoEnabled = false;
listener.IsWarningEnabled = false;
listener.IsErrorEnabled = true;
By default, all types of logging are enabled on a log listener.
Batch log listeners
Flushing all listeners
Implementing a custom IBatchLogListener
A batch log listener is a class implementing the IBatchLogListener interface (and most probably deriving from BatchLogListenerBase). This
interface adds a Flush method which allows a listener to be flushed. The advantage is that when a log listener writes to a slower persistence
store, it will not have to access this expensive resource for every log event, but by batches.
Flushing all listeners
When using batch log listeners, it is very important to flush the log listeners at important events such as application unhandled exceptions or when
the application exits. The reason is that otherwise important log events that are currently in the batch that hasn't been written to the persistence
store are lost.
To flush all flushable listeners, use the following method:
LogManager.FlushAll();
Implementing a custom IBatchLogListener
When implementing a custom batch log listener, it is very wise to derive from the class. This brings the following BatchLogListenerBase
advantages:
The is thread-safe BatchLogListenerBase
The automatically flushes the listener every 5 seconds BatchLogListenerBase
You only need to implement the which actually writes the entries to the persistence store WriteBatch
Below is an example batch log listener:
public class FileLogListener : BatchLogListenerBase
{
private readonly string _filePath;
private readonly int _maxSizeInKiloBytes;
public FileLogListener(string filePath, int maxSizeInKiloBytes)
{
Argument.IsNotNullOrWhitespace(() => filePath);
_filePath = filePath;
_maxSizeInKiloBytes = maxSizeInKiloBytes;
}
protected override void WriteBatch(System.Collections.Generic.List<LogBatchEntry>
batchEntries)
{
try
{
var fileInfo = new FileInfo(_filePath);
if (fileInfo.Exists && (fileInfo.Length / 1024 >= _maxSizeInKiloBytes))
{
CreateCopyOfCurrentLogFile(_filePath);
}
using (var fileStream = new FileStream(_filePath, FileMode.Append,
FileAccess.Write, FileShare.Read))
{
using (var writer = new StreamWriter(fileStream))
{
foreach (var batchEntry in batchEntries)
{
var message = FormatLogEvent(batchEntry.Log, batchEntry.Message,
batchEntry.LogEvent, batchEntry.ExtraData);
writer.WriteLine(message);
}
}
}
}
catch (Exception)
{
// Swallow
}
}
private void CreateCopyOfCurrentLogFile(string filePath)
{
for (int i = 1; i < 999; i++)
{
var possibleFilePath = string.Format("{0}.{1:000}", filePath, i);
if (!File.Exists(possibleFilePath))
{
File.Move(filePath, possibleFilePath);
}
}
}
}
Integration with external loggers
The logging in Catel does not write any output by default. This gives a developer freedom to use any final logging mechanism in the way he or
she intended. For example, Catel can easily be integrated with log4net or NLog. Basically, the following steps are required to implement an
1.
2.
1.
2.
3.
external log solution:
Create a custom ILogListener by creating your own or using the LogListenerBase implementation
Register it in the LogManager using the LogManager.AddListener
Log4net
NLog
Log4net
The example below provides an ILogListener for NLog, but any external logging library can be used.
Creating the listener
A listener can be created by creating a new class deriving from LogListenerBase.
public class Log4netListener : LogListenerBase
{
protected override void Debug(ILog log, string message, object extraData)
{
var finalLog = log4net.LogManager.GetLogger(log.TargetType);
finalLog.Debug(message);
}
protected override void Info(ILog log, string message, object extraData)
{
var finalLog = log4net.LogManager.GetLogger(log.TargetType);
finalLog.Info(message);
}
protected override void Warning(ILog log, string message, object extraData)
{
var finalLog = log4net.LogManager.GetLogger(log.TargetType);
finalLog.Warn(message);
}
protected override void Error(ILog log, string message, object extraData)
{
var finalLog = log4net.LogManager.GetLogger(log.TargetType);
finalLog.Error(message);
}
}
Registering the listener
Last but not least, it is important to register the listener:
LogManager.AddListener(new Log4netListener());
Configuring log4net
Add reference to log4net
Add [assembly: log4net.Config.XmlConfigurator(Watch = true)] to AssemblyInfo.cs
Configure log4net in your app.config to configure the actual data
NLog
Note that this is just a sample configuration. Please use the log4net documentation for all options
The example below provides an ILogListener for NLog, but any external logging library can be used.
Creating the listener
A listener can be created by creating a new class deriving from LogListenerBase.
public class NLogListener : LogListenerBase
{
protected override void Debug(ILog log, string message, object extraData)
{
var finalLog = NLog.LogManager.GetLogger(log.TargetType.ToString());
finalLog.Debug(message);
}
protected override void Info(ILog log, string message, object extraData)
{
var finalLog = NLog.LogManager.GetLogger(log.TargetType.ToString());
finalLog.Info(message);
}
protected override void Warning(ILog log, string message, object extraData)
{
var finalLog = NLog.LogManager.GetLogger(log.TargetType.ToString());
finalLog.Warn(message);
}
protected override void Error(ILog log, string message, object extraData)
{
var finalLog = NLog.LogManager.GetLogger(log.TargetType.ToString());
finalLog.Error(message);
}
}
Registering the listener
Last but not least, it is important to register the listener:
LogManager.AddListener(new NLogListener());
Writing logs to disk
Catel also supports very lightweight listeners to allow external logging libraries to hook on. To create a listener, first create a new class that
implements the interface. Next, register it in the using the method. ILogListener LogManager LogManager.AddListener
The has a separate method for each , but also has a shared method that is called for each log event. For example, if a ILogListener LogEvent
debug message is written to the log, both the Write and Debug methods are invoked on the . ILogListener
Creating the listener
A listener can be created by creating a new class deriving from . LogListenerBase
For an example which writes to disk in batches, see the batch log event listeners
Note that Catel already contains a FileLogListener and there is no need to reproduce this class. It only acts as an example that is easy
to understand
public class FileLogListener : LogListenerBase
{
private readonly TextWriter _textWriter;
public FileLogListener(string fileName)
{
Argument.IsNotNullOrWhitespace("fileName", fileName);
FileName = fileName;
_textWriter = new StreamWriter(fileName, true);
}
public string FileName { get; private set; }
public override void Write(ILog log, string message, LogEvent logEvent)
{
_textWriter.WriteLine(message);
}
}
Registering the listener
Last but not least, it is important to register the listener:
LogManager.AddListener(new FileLogListener("<log_file_path>"));
Creating log listeners via configuration
Starting with Catel 3.8, it is possible to instantiate classes from the configuration. Below is an example on how to customize the LogListener
listeners:
<configSections>
<sectionGroup name="catel">
<section name="logging" type="Catel.Logging.LoggingConfigurationSection, Catel.Core"
/>
</sectionGroup>
</configSections>
<catel>
<logging>
<listeners>
<listener type="Catel.Logging.FileLogListener" FilePath="CatelLogging.txt"
IgnoreCatelLogging="true"
IsDebugEnabled="false" IsInfoEnabled="true" IsWarningEnabled="true"
IsErrorEnabled="true"/>
</listeners>
</logging>
</catel>
It is important to register the section as shown in the example above. Then the section in the bottom can contain an unlimited logging logging
number of listeners. Each listener has to provide at least the property which contains the type and namespace of the which type ILogListener
must be added:
<listener type="Catel.Logging.FileLogListener" />
The other properties are fully customizable and can be defined on the fly. This means that the configuration is fully customizable for every listener
that needs to be added. Below is an example to register the via configuration: FileLogListener
<listener type="Catel.Logging.FileLogListener" FilePath="CatelLogging.txt"
IgnoreCatelLogging="true"
IsDebugEnabled="false" IsInfoEnabled="true" IsWarningEnabled="true"
IsErrorEnabled="true"/>
The properties ( , , and ) are available to all listeners. All other ILogListener IsDebugEnabled IsInfoEnabled IsWarningEnabled IsErrorEnabled
properties depend on the the actual listener being registered. This allows major flexibility at runtime.
Anotar.Catel.Fody
Logging is a very important part of an application. It provides detailed information about the application workflow, even when an application is
already deployed to several clients. Thats the reason that logging is a first class citizen in the Catel framework.
In general, logging works by defining an instance on a class: ILog
private static readonly ILog Log = LogManager.GetCurrentClassLogger();
Then in any method, logging can be added like this:
Log.Info("This is a logging with a format '{0}'", "test");
Writing the definition can be boring and repetitive. Luckily came up with a solution for that, namely . With the Log Simon Cropp Anotar.Catel.Fody
Anotar implementation, a reference will be added to the solution. Then after compilation the assembly will be removed and all calls to the cl LogTo
ass will be replaced by actual calls to the Catellogging classes.
How to use Anotar
Using Anotar is really easy, just call the static methods on the class as you can see below: LogTo
LogTo.Info("This is a logging with a format '{0}'", "test");
Note that it is no longer required to define the field, it will be added automatically by Anotar. Log
Besides that it is really easy to use, another benefit is a very small performance improvement. The uses reflection to GetCurrentClassLogger
determine the current class. This is a very slight hit on performance the first time a class is used (only once, the field is static). Anotar directly
replaces the call by an implementation like this:
private static readonly ILog Log = LogManager.GetLogger(typeof(MyClass));
Additional options
Disabling method names and line numbers
By default Anotar also logs the method and line number:
03:58:11:858 => [DEBUG] [AnotarDemo.Program] Method: 'Void Main(String[])'. Line: ~19.
this is a test
If you don't want such output, add this attribute on assembly level:
[assembly: LogMinimalMessage]
Then the output will look like this:
03:59:36:344 => [DEBUG] [AnotarDemo1.Program] this is a test
Logging exceptions automatically
It is possible to automatically log exceptions inside a method. To accomplish this, decorate the method with the attri LogTo[LogLevel]OnException
bute:
[LogToDebugOnException]
public static void ExceptionalMethod()
{
throw new Exception("This will be logged automatically");
}
Then the output will be as follows:
04:01:48:331 => [DEBUG] [AnotarDemo.Program] Exception occurred in 'Void
ExceptionalMethod()'. | [Exception] System.Exception: This will be logged
automatically
at AnotarDemo.Program.ExceptionalMethod() in
c:\Source\AnotarDemo\AnotarDemo\Program.cs:line 27
Messaging
MessageBase
Message mediator
Messaging via attributes

MessageBase
The MessageMediator is a very powerful class to send messages to other objects inside an application. However, it can sometimes by
cumbersome to register and create messages. Therefore the MessageBase class is a very nice convenience class to create messages and allow
easier registration.
The MessageBase provides the following additional functionality out of the box:
Send messages with data without instantiating a message
Register message handlers
Unregister message handlers
Creating messages based on the MessageBase
It is very easy to create a new message. The message below is a message that contains a string and this little class provides lots of capabilities.
public class DemoMessage : MessageBase<DemoMessage, string>
{
public DemoMessage() { }
public DemoMessage(string content)
: base(content) { }
}
Sending messages
A user can send a message by using the following code:
DemoMessage.SendWith("hello world");
Registering to messages
A class that is interested in message can register to a message using the Register method:
DemoMessage.Register(this, OnDemoMessage);
Unregistering from messages
DemoMessage.Unregister(this, OnDemoMessage);
Instantiating a message with data
The MessageBase class can also instantiate messages by using the With method:
var message = DemoMessage.With("hello world");
Message mediator
Catel allows sending messages to unknown targets by implementing the mediator pattern. The mediator is assured memory leak free, and can be
used safely in any .NET environment (even ASP.NET). Below are a few usage examples of the MessageMediator class.
Registering to a message
To register a handler for a specific message type, in this case a string, use the following code:
var mediator = ServiceLocator.Instance.ResolveType<IMessageMediator>();
mediator.Register<string>(this, OnMessage);
Sending out a message
Note that the message needs an empty constructor
To send a message to all recipients, use the following code:
var mediator = ServiceLocator.Instance.ResolveType<IMessageMediator>();
mediator.SendMessage<string>("message");
Sending out a message with a tag
Sometimes, you want to send messages only based on a tag. For example, you want to let other view models know that you just added a person.
All recipients that registered to the string message type with the Person tag will receive the message:
var mediator = ServiceLocator.Instance.ResolveType<IMessageMediator>();
mediator.SendMessage<string>("Person added", "Person");
Messaging via attributes
The message mediator is a great way to communicate between instances in an application. It does however require to manually subscribe to and
unsubscribe from classes. This issue can be bypassed using the attribute based approach. This is an alternative for registering a method in the
message mediator and not be obliged to use Register<T> method.
Subscribing and unsubscribing
When attributes are using inside a class, it is required to call the MessageMediatorHelper.SubscripeRecipient. To unsubscribe an object, it is
required to call MessageMediatorHelper.UnsubscribeRecipient.
There are two options to decorate methods with the attribute. Either with or without tag.
Subscribing without a tag
In this case, the mediator will send the message to all the methods that has subscribe using the attribute to receive the message and not one
especially. The code below broadcasts a message without any tag. This is just regular behavior of the message mediator.
/// <summary>
/// Method to invoke when the command is executed.
/// </summary>
private void OnCmdExecute()
{
var dependencyResolver = this.GetDependencyResolver();
var mediator = dependencyResolver.Resolve<IMessageMediator>();
mediator.SendMessage("Test Value");
}
If a class, for example a view model, is interested in these messages, the only thing that needs to be done is to decorate a method with the
MessageRecipient attribute as shown below:
Note that the ViewModelBase class already handles the subscriptions using attributes out of the box
/// <summary>
/// Shows the message.
/// </summary>
/// <param name="value">The value.</param>
[MessageRecipient]
private void ShowMessage(string value)
{
var dependencyResolver = this.GetDependencyResolver();
var messageService = dependencyResolver.Resolve<IMessageService>();
messageService.Show(value);
}
Subscribing with a tag
A tag can be used to specify some sort of grouping for messages. The MessageRecipient attribute also supports this as shown in the code
below. First lets take a look how to send a message and specify a tag.
/// <summary>
/// Method to invoke when the command is executed.
/// </summary>
private void OnCmdExecute()
{
var dependencyResolver = this.GetDependencyResolver();
var mediator = dependencyResolver.Resolve<IMessageMediator>();
mediator.SendMessage("Test Value", "myTag");
}
The message is now sent with the tag. The attribute has to be used as shown below:
/// <summary>
/// Shows the message.
/// </summary>
/// <param name="value">The value.</param>
[MessageRecipient(Tag = "myTag")]
private void ShowMessage(string value)
{
var dependencyResolver = this.GetDependencyResolver();
var messageService = dependencyResolver.Resolve<IMessageService>();
messageService.Show(value);
}
Multilingual
Making an application multilingual is a very common feature request nowadays. Therefore Catel provides the resources in several languages and
provides the to give the developers full control over the translation process in their applications. LanguageService
Setting up the LanguageService
Setting cultures
Registering custom language sources
Using the LanguageService
Using the LanguageService in XAML
Using theLanguageBinding in WPF and Silverlight
Using the LanguageBinding in Windows Phone
Implementing custom LanguageService (from database)
Creating a custom ILanguageSource implementation
Creating a custom DbLanguageService
Enabling the custom DbLanguageService
Setting up the LanguageService
Setting cultures
By default the will use the current UI culture to retrieve the right language values. These can easily be customized: LanguageService
var dependencyResolver = this.GetDependencyResolver();
var languageService = dependencyResolver.Resolve<ILanguageService>();

languageService.PreferredCulture = new CultureInfo("nl-NL");


languageService.FallbackCulture = new CultureInfo("en-US");
Registering custom language sources
In order to customize the language sources, custom language sources can be registered via the method. RegisterLanguageSource
The code below shows how to add a new which represents a resource file in a specific assembly: LanguageResourceSource
var dependencyResolver = this.GetDependencyResolver();
var languageService = dependencyResolver.Resolve<ILanguageService>();

// Create source for assembly MyApplication where the Resources.resx is located in the
Properties folder
var resourcesSource = new LanguageResourceSource("MyApplication",
"MyApplication.Properties", "Resources");
languageService.RegisterLanguageSource(resourcesSource );

// Create source for assembly MyApplication where the Exceptions.resx is located in


the Properties folder
var exceptionsSource = new LanguageResourceSource("MyApplication",
"MyApplication.Properties", "Exceptions");
languageService.RegisterLanguageSource(exceptionsSource );
The will now automatically query these sources for the translations. LanguageService
Using the LanguageService
To use the , retrieve it via the (or let it be injected) and use the provided methods. The example below LanguageService DependencyResolver
retrieves the resource string in the . If theresource cannot be found in the , it will be retrieved for WarningTitle PreferredCulture PreferredCulture
the . If that cannot be found, it will return . FallbackCulture null
var dependencyResolver = this.GetDependencyResolver();
var languageService = dependencyResolver.Resolve<ILanguageService>();
var warningTitle = languageService.GetString("WarningTitle");
Using the LanguageService in XAML
To use the in XAML, Catel provides the markup extensions. LanguageService
Using theLanguageBinding in WPF and Silverlight
To use the markup extension in WPF and Silverlight, use the following code: LanguageBinding
<TextBlock Text="{LanguageBinding WarningTitle}" />
Using the LanguageBinding in Windows Phone
Since Windows Phone does not support markup extensions, a custom implementation is used in Catel. This requires a little MarkupExtension
difference in the usage of the markup extension:
<TextBlock Text="{markup:LanguageBinding ResourceName=WarningTitle}" />
Implementing custom LanguageService (from database)
Implementing a custom consists of several steps which are described below. LanguageService
Creating a custom ILanguageSource implementation
First of all, we need to implement a customized language source to allow the custom service to know what source to read for translations:
public class DbLanguageSource : ILanguageSource
{
public DbLanguageSource(string connectionString)
{
Argument.IsNotNullOrWhitespace(() => connectionString);
ConnectionString = connectionString;
}
public string ConnectionString { get; private set; }
public string GetSource()
{
return ConnectionString;
}
}
Creating a custom DbLanguageService
Below is a custom implementation of the . Note that we only have to derive a single method to fully customize the LanguageService
implementation:
Note that this implementation queries the database for each translation. It is best to read all translations into memory at once to improve
performance
public class DbLanguageService : LanguageService
{
protected override string GetString(ILanguageSource languageSource, string
resourceName, CultureInfo cultureInfo)
{
var connectionString = languageSource.GetSource();
using (var dbConnection = new SqlConnection(connectionString))
{
dbConnection.Open();
var sqlCommand = dbConnection.CreateCommand();
sqlCommand.CommandType = CommandType.Text;
sqlCommand.CommandText = @"SELECT [Name] FROM [Translations] WHERE
[ResourceName] = @ResourceName AND [CultureName] = @CultureName";
sqlCommand.Parameters.Add(new SqlParameter("ResourceName", resourceName));
sqlCommand.Parameters.Add(new SqlParameter("CultureName",
cultureInfo.ThreeLetterISOLanguageName));
var translation = sqlCommand.ExecuteScalar() as string;
if (!string.IsNullOrWhiteSpace(translation))
{
return translation;
}
}
// Resource not found, fall back to base if you like, or simply return null
return base.GetString(languageSource, resourceName, cultureInfo);
}
}
Enabling the custom DbLanguageService
To enable the custom , it must be registered in the : DbLanguageService ServiceLocator
var serviceLocator = ServiceLocator.Default;

var dbLanguageService = new DbLanguageService();

var dbLanguageSource = new DbLanguageSource("myConnectionString");


dbLanguageService.RegisterLanguageSource(dbLanguageSource);

serviceLocator.RegisterInstance<ILanguageService>(dbLanguageService);
Parallel invocation and tasks
This page contains helper classes in Catel to invoke specific actions on very large collections in parallel.
Running batches on large sets in parallel
Running batches on large sets in parallel
When handling a lot of items and invoking a method per item, it might be a viable option to execute the actions in batches. This normally requires
quite some code to split up the large collection into batches and execute the method for each item. To make this process much easier, Catel
introduces the class. ParallelHelper
To invoke an method on all types currently loaded by Catel, in batches of 2500 types per batch, use the following code: Initialize
var allTypes = new List<Type>(TypeCache.GetTypes());
ParallelHelper.ExecuteInParallel(allTypes, type =>
{
SomeInitializeTypeMethod(type);
}, 2500, "Initialize types");
It is really easy to tweak the number of items per batch to find the optimal performance of items per batch.
Preventing memory leaks
Memory leaks are a very stubborn issue inside the .NET world. Every subscription to events can result in a memory leak if not unsubscribed
correctly. Catel provides several helper classes to prevent memory leaks in applications.
Change notification wrapper
Weak events
Change notification wrapper
Subscribing to change notifications of objects mostly results in large statements such as the one below:
var itemAsPropertyChanged = obj as INotifyPropertyChanged;
if (itemAsPropertyChanged != null)
{
itemAsPropertyChanged.PropertyChanged += OnPropertyChanged;
}
However, using this code one must be aware that if not unsubscribed, there might be a potential memory leak here. In Catel, there is a solution for
such cases that can raise change notifications using weak events called the ChangeNotificationWrapper. It allows the subscription of both the
INotifyPropertyChanged and INotifyCollectionChanged interfaces.
Subscribing to events of an observable object
Using the code below, one can subscribe to the PropertyChanged event of an object:
var wrapper = new ChangeNotificationWrapper(obj);
wrapper.PropertyChanged += OnPropertyChanged;
Subscribing to events of an observable collection
Using the code below, one can subscribe to the CollectionChanged event of an object:
var wrapper = new ChangeNotificationWrapper(observableCollection);
wrapper.CollectionChanged += OnCollectionChanged;
Advanced scenario with observable collections
Sometimes it is required to watch both changes inside a collection, but also the items inside a collection. For example, there is a list of customers
and you are also interested in changes of customers inside a collection. This is fully supported by the ChangeNotificationWrapper using the code
Note that it is not required to check whether the object implements INotifyPropertyChanged, the wrapper does it automatically
Note that it is not required to check whether the object implements INotifyCollectionChanged, the wrapper does it automatically
1.
2.
1.
2.
below:
var wrapper = new ChangeNotificationWrapper(observableCustomerCollection);
wrapper.CollectionChanged += OnCollectionChanged;
wrapper.CollectionItemPropertyChanged += OnCollectionItemPropertyChanged;
All subscriptions are automatically managed by the ChangeNotificationWrapper when items are added or removed from the collection.
Unsubscribing from events
When you are no longer interested in events from the source object, there are two options:
Just leave them coming, as soon as the objects are no longer used, they will be garbage collected
Unsubscribe using the following code:
wrapper.UnsubscribeFromAllEvents();
Weak events
You have probably heard about weak events before. This documentation is not about the issue of the cause of weak events, there are lots of
articles about that. This documentation writes about the solution, which is the WeakEventListener. Shortly said, when you do this in every class
(just for the sake of explaining the problem, dont start thinking this code has no business value):
var log = Log.Instance;
log.LogReceived += OnLogReceived;
As you can see, the log is a singleton, so there is only one living instance of the Log class. It will probably live as long as the app itself. Now you
might be thinking: whats wrong with this code? Nothing, until the app starts growing and growing and your users start complaining about memory
issues.
What happens here is that you subscribe to the LogReceived event of the Log class. This subscription contains 2 things:
What class do I need to call (null for static, otherwise the instance of the class)
What method do I need to call
So, in fact now the Log class knows about the instance of the class that just subscribed to it and holds a reference to it (how else can it deliver the
event, if it doesnt know the address). Thus, the classes that subscribe to the Log and that do no unsubscribe will never be collected by the
garbage collection.
I truly hope you understand the issue. If not, I recommend to read , it dives into the issue a bit better. this excellent article
Open instance delegates
The key feature behind this implementation of the weak event pattern is open instance delegates. You are probably wondering: what the hell are
open instance delegates? Well, good question, and I will try to explain it. An open instance delegate is just as a regular delegate, it points to the
method of a specific class, but the biggest difference is that it does not bind to a specific instance. This means that it can be described as: I know
you live on that street (method), but I have not clue in which city (instance) that is. The instance can be specified later. The delegate for a regular
event handler looks like this:
public delegate void OpenInstanceHandler(TTarget @this, object sender, TEventArgs e);
The @this is nothing special, it allows us to use the this keyword so everyone knows that the target should be passed there. As you can see, it
contains 3 parameters. The first one is the target (the city), the second and third parameters are the parameters of the regular event handler.
Weak references
The weak event listener creates an open instance delegate and stores both the source and target in a WeakReference class. As soon as one of
these references are no longer valid, the class is unbound. The good side of this approach is that this weak event listener does not leak when the
event never fires.
What does it support
The following use cases are supported:
Instance source (event) and instance target (handler)
Static source (event) and instance target (handler)
Instance source (event) and static target (handler)
So, actually it handles everything that can cause a memory leak via event subscriptions!
What does it not support and what are the downsides
This weak event listener follows the rules of the .NET framework. So, it cannot subscribe to private events. If you want private events, do your
own hacking (the source is available, you only have to change the DefaultEventBindingFlags at the top of the class).
There are a few downsides about using a weak event listeners in general:
Its notation is ugly, the original .NET way looks way better
You have to name the event by string, that sucks (if you know a better way, contact me!)
It can only handle events with a handler of EventHandler<TEventArgs>
You become a lazy developer not caring about subscriptions
How to use
There are 4 categories of event subscriptions, all described below.
Instance to instance
This is the situation where an instance target subscribes to an instance event. The events are unbound as soon as either the target or source are
collected.
var source = new EventSource();
var listener = new EventListener();
var weakEventListener = WeakEventListener<EventListener, EventSource,
EventArgs>.SubscribeToWeakEvent(listener, source, "PublicEvent",
listener.OnPublicEvent);
Instance to static
This is the situation where a static target subscribes to an instance event. The events are unbound as soon as the source is collected.
var source = new EventSource();
var weakEventListener = WeakEventListener<EventListener, EventSource,
EventArgs>.SubscribeToWeakEvent(null, source, "PublicEvent",
EventListener.OnEventStaticHandler);
Static to instance
This is the situation where an instance target subscribes to a static event. The events are unbound as soon as the target is collected.
var listener = new EventListener();
var weakEventListener = WeakEventListener<EventListener, EventSource,
EventArgs>.SubscribeToWeakEvent(listener, null, "StaticEvent",
listener.OnPublicEvent);
Static to static
This is not supported because you shouldnt be using a weak event listener here. Static events with static event handlers simply cannot cause
memory leaks because both the source and the target have no instance. However, it might be possible that you subscribe to an event too many
times and the event fires too many times. But again, no memory issues here.
Reflection
Internally, Catel uses lots of reflection to implement some of its behavior. And why not make all these excellent reflection classes public?
Getting loaded assemblies
In WPF, it is very simple to get all the loaded assemblies. In Silverlight, it already gets a bit harder. Silverlight in combination with modules that
are separately loaded are horrible to use via reflection. In Catel, it is possible to register xap files to the AssemblyHelper class:
AssemblyHelper.RegisterAssembliesFromXap(xapStream);
Catel unpacks the xap (which is basically just a zip file) and adds all the assemblies to an internal list of assemblies. This way, the
AssemblyHelper.GetLoadedAssemblies method actually returns all the loaded assemblies, also the ones in dynamically loaded xaps that are not
available by default.
Getting types in Silverlight
Sometimes you know what type to get and what assembly it is living in. However, you don't want to be version-dependent by specifying the fully
qualified assembly name. Using the TypeHelper.GetType method, it is possible to get a type by only the assembly name (say Catel.Silverlight)
and the type name (say Catel.Data.ObservableObject).
var type = PropertyHelper.GetType("Catel.Data.ObservableObject", "Catel.Silverlight");
Setting or getting properties of objects
In lots of cases, you need to possibility to set or get properties of an object via reflection. This behavior is implemented in the PropertyHelper
class. Below are a few examples.
Check if a property is available on an object
PropertyHelper.IsPropertyAvailable(person, "FirstName");
Getting a property value
PropertyHelper.GetValue(person, "FirstName");
or
string firstName;
PropertyHelper.TryGetValue(person, "FirstName", out firstName);
Setting a property value
PropertyHelper.SetValue(person, "FirstName", "Geert");
or
PropertyHelper.TrySetValue(person, "FirstName", "Geert");
Scoping
Sometimes scoping is important to share an object inside a specific scope which cannot be determined upfront. A great example is the
serialization inside Catel which requires a serialization scope which can be shared over a lot of objects. Scoping in Catel is really. To create a
scope of an object with a specific tag, use the code below:
using (var scopeManager = ScopeManager<object>.GetScopeManager("object"))
{
var scopeObject = scopeManager.ScopeObject;

// scope can be used here


}
When the scope does not yet exist, it will be created and the object will be created by theTypeFactory.
Serialization
Introduction to serialization
Specifying what gets serialized
Customizing serialization
Introduction to serialization
Serialization modes
Serializing a model
Warming up serialization
Warming up specific types
Warming up automatically
Warming up using multiple threads
Backwards compatibility for binary serialization
Serialization modes
Depending on the target framework, several options are available as serialization modes:
Serialization mode WPF Silverlight Windows Phone WinRT
Binary
XML
Serializing a model
The code below shows how to save an object (which can, of course, be a complex graph of nested objects):
The serialization engine has been completely renewed for Catel 3.7. Make sure that you read about these new features.
Note that it is possible ti implement custom serialization techniques or customize the serialization
var myObject = new MyObject();
myObject.Save(@"C:\myobject.dob");
Looks too easy, but this really is the only thing you need to do. You can specify the serialization mode in the several available overloads of theSa
method. ve
Loading is as easy as saving, as you can see in the following code:
var myObject = MyObject.Load(@"C:\myobject.dob");
Warming up serialization
The first time a serializerneeds to serialize an object, it needs to perform some reflection to gather all the required information. This can have a
negative impact on performance for the end-user during serialization. This load cannot be prevented, but it is possible to warmup the serializer at
any time when it is convenient (for example, during startup of the application).
Warming up specific types
This code will warm up all the specified types:
var typesToWarmup = new type[] { typeof(Settings) };

var xmlSerializer = SerializationFactory.GetXmlSerializer();


xmlSerializer.Warmup(typesToWarmup);

var binarySerializer = SerializationFactory.GetBinarySerializer();


binarySerializer.Warmup(typesToWarmup);
Warming up automatically
This code will warm up all types implementing the class: ModelBase
var xmlSerializer = SerializationFactory.GetXmlSerializer();
xmlSerializer.Warmup();

var binarySerializer = SerializationFactory.GetBinarySerializer();


binarySerialzier.Warmup();
Warming up using multiple threads
By default, Catel will optimize the initialization and dispatch them to different threads. Using extensive testing, the Catel team discovered that
approximately 1000 types / thread is the ideal load balancing (otherwise the spawning of the threads is more expensive than it handling it on the
same thread). If this behavior needs to be customized, simply provide the number of types per thread. If is specified, all types will be warmed -1
up in a single thread.
The code example below shows how to initialize all types deriving from on a single thread: ModelBase
Note that for a model to support the and methods, it must derive from Save Load SavableModelBase
Note that warming up for all types take a serious amount of time and increase the memory footprint of your application might might
depending on the number of models
var xmlSerializer = SerializationFactory.GetXmlSerializer();
xmlSerialzier.Warmup(null, -1);
Backwards compatibility for binary serialization
This example shows how an old (standard .NET) data class that uses custom binary serialization can easily be converted to a to use ModelBase
the even for all your existing classes. ModelBase
Declare a new class (remember the code snippet). If the new class is in a new assembly, or has a new name or ModelBase dataobject
namespace, use the attribute to let the know that when it finds the old type, it should RedirectType ModelBase deserialize that type into the new
type.
Then, by default, the class will try to deserialize the old object. If it fails to do so, it will fall back on the default values provided by the ModelBase
property declarations. However, it is also possible to override the method: GetDataFromSerializationInfo
/// <summary>
/// Retrieves the actual data from the serialization info.
/// </summary>
/// <remarks>
/// This method should only be implemented if backwards compatibility should be
implemented for
/// a class that did not previously implement the ModelBase class.
/// </remarks>
protected override void GetDataFromSerializationInfo(SerializationInfo info)
{
// Check if deserialization succeeded
if (DeserializationSucceeded)
{
return;
}
// Deserialization did not succeed for any reason, so retrieve the values manually
// Luckily there is a helper class (SerializationHelper)
// that eases the deserialization of "old" style objects
FirstName = SerializationHelper.GetString(info, "FirstName",
FirstNameProperty.GetDefaultValue());
LastName = SerializationHelper.GetString(info, "LastName",
LastNameProperty.GetDefaultValue());
}
Specifying what gets serialized
Including fields and properties using IncludeInSerialization attribute
Excluding fields and properties using ExcludeFromSerialization attribute
Implementing a custom ISerializationManager
By default, Catel only serializes the defined Catel properties on the or any deriving classes. It is possible to customize this behavior. ModelBase
Below is a class which will be used in all examples:
public class MyModel : ModelBase
{
private string _fieldValue;

public string RegularProperty { get; set; }

public string CatelProperty
{
get { return GetValue<string>(CatelPropertyProperty); }
set { SetValue(CatelPropertyProperty, value); }
}
public static readonly PropertyData CatelPropertyProperty =
RegisterProperty("CatelProperty", typeof(string), null);
}
Member name Gets serialized
_fieldValue
RegularProperty
CatelProperty
Including fields and properties using IncludeInSerialization attribute
To include fields or regular properties on an object, use the following code:
public class MyModel : ModelBase
{
[IncludeInSerialization]
private string _fieldValue;

[IncludeInSerialization]
public string RegularProperty { get; set; }

public string CatelProperty
{
get { return GetValue<string>(CatelPropertyProperty); }
set { SetValue(CatelPropertyProperty, value); }
}
public static readonly PropertyData CatelPropertyProperty =
RegisterProperty("CatelProperty", typeof(string), null);
}
Member name Gets serialized
_fieldValue
RegularProperty
CatelProperty
Note that private members can only be serialized in .NET and not in Silverlight, Windows Phone or the Windows Runtime
Excluding fields and properties using ExcludeFromSerialization attribute
To exclude Catel properties on an object, use the following code:
public class MyModel : ModelBase
{
private string _fieldValue;

public string RegularProperty { get; set; }

[ExcludeFromSerialization]
public string CatelProperty
{
get { return GetValue<string>(CatelPropertyProperty); }
set { SetValue(CatelPropertyProperty, value); }
}
public static readonly PropertyData CatelPropertyProperty =
RegisterProperty("CatelProperty", typeof(string), null);
}
Member name Gets serialized
_fieldValue
RegularProperty
CatelProperty
Implementing a custom ISerializationManager
Internally Catel uses a default implementation of the to determine what members of a type should be serialized. It is ISerializationManager
possible to customize this behavior by overriding a single method or by creating a brand new type. Below is an example which always excludesP
properties and fields from serialization. assword
public class SafeSerializationManager : SerializationManager
{
public override HashSet<string> GetFieldsToSerialize(Type type)
{
var fieldsList = new List<string>(base.GetFieldsToSerialize(type));

for (int i = 0; i < fieldsList.Count; i++)
{
if (string.Equals(fieldsList[i], "_password"))
{
fieldsList.RemoveAt(i--);
}
}

return new HashSet<string>(fieldsList);
}

public override HashSet<string> GetPropertiesToSerialize(Type type)
{
var propertiesList = new List<string>(base.GetPropertiesToSerialize(type));

for (int i = 0; i < propertiesList.Count; i++)
{
if (string.Equals(propertiesList[i], "Password"))
{
propertiesList.RemoveAt(i--);
}
}

return new HashSet<string>(propertiesList);
}
}
Don't forget to register it in the as well: ServiceLocator
var serviceLocator = ServiceLocator.Default;
serviceLocator.RegisterType<ISerializationManager, SafeSerializationManager>();

Customizing serialization
The serialization engine explained
Customizing serialization
Customizing the serialization for specific models
Creating the modifier
Registering the modifier
Customizing the serialization engines
The serialization engine explained
All classes deriving from use the serialization engine of Catel to serialize itself in a whole or as a subset of properties. Below is a ModelBase
schema which sheds some light on the architecture.
The documentation engine has been completely rewritten for Catel 3.7. This documentation only applies to Catel 3.7 and higher.
The now contains all the serialization and deserialization logic. The advantage is that this logic is no longer contained by the SerializerBase Model
itself which makes the class much simpler to understand and maintain. Now the contains all the heavy lifting, the deriving Base SerializerBase
classes ( andBinarySerializer) only have to implement a few methods. XmlSerializer
The serialization process works as shown in the diagram below:
Customizing serialization
Customizing the serialization for specific models
Catel has a default behavior for what gets serialized. It can be tweaked by including / excluding fields and properties by using the IncludeInSeriali
and attributes. But sometimes one needs more specific customization of the serialization for a specific type. This zation ExcludeFromSerialization
customization is possible via the . ISerializerModifier
Creating the modifier
To customize the serialization of a specific model type, one needs to implement the interface. The example belows shows how ISerializerModifier
to encrypt the property on the model class. Password Person
Workflow 1 represents the serialization. Workflow 2 represents the deserialization.
public class PersonSerializerModifier : SerializerModifierBase<Person>
{
public override void SerializeMember(ISerializationContext context, MemberValue
memberValue)
{
if (string.Equals(property.Name, "Password"))
{
memberValue.Value = EncryptionHelper.Encrypt(memberValue.Value);
}
}

public override void DeserializeMember(ISerializationContext context, MemberValue


memberValue)
{
if (string.Equals(property.Name, "Password"))
{
memberValue.Value = EncryptionHelper.Decrypt(memberValue.Value);
}
}
}
Registering the modifier
To register a modifier for a specific class, define the attribute: SerializerModifier
[SerializerModifier(typeof(PersonSerializerModifier))]
public class Person : ModelBase
{
// .. class contents
}
Customizing the serialization engines
Since the does all the heavy lifting, it is very easy to customize the behavior of an existing serializer or create a completely new SerializerBase
one.Each serializer implements its own interface and are registered in the using the following interfaces: ServiceLocator
XmlSerializer => IXmlSerializer
BinarySerializer => IBinarySerializer
To customize a serializer, derive from an existing class and customize a method. The serializer below makes sure that specific members are
never serialized. It keeps all other serialization logic intact.
Note that modifiers are inherited from base classes. When serializing, the modifiers defined on the most derived classes will be called
last. When deserializing, the modifies defined on the most derived classes will be called first.
public class SafeXmlSerializer : XmlSerializer
{
protected override bool ShouldIgnoreMember(ModelBase model, PropertyData property)
{
if (model is SecurityModel)
{
if (string.Equals(property.Name, "Password"))
{
return true;
}
}
return base.ShouldIgnoreProperty(model, property);
}
}
The only thing to do now is to register this custom instance in the : ServiceLocator
ServiceLocator.Default.RegisterType<IXmlSerializer, SafeXmlSerializer>();
The following methods on theserializer classes might be of interest when customizing the serialization:
ShouldIgnoreProperty
BeforeSerialization
BeforeSerializeProperty
AfterSerializeProperty
AfterSerialization
BeforeDeserialization
BeforeDeserializeProperty
AfterDeserializeProperty
AfterDeserialization

Thread safe code


Writing a multiple threading application is always a challenge. Eventually you need use objects or statements with the ability to synchronize
access to the critical sections of the code by taking and releasing a lock.
Background information
The common solution to access the thread-sensitive resources is use the lock statement just as follow:
private readonly object _syncObj = new object();
public void DoTheWork()
{
lock (_syncObj)
{
// Access to the thread-sensitive resources here.
}
}

But some times the scenario is not quite simple, then you need to use the Monitor class in order to synchronize cross method operations. Here is
an example:
private readonly object _syncObj = new object();
public void DoTheWork()
{
StartTheWork();
object result = EndTheWork();
}
private void StartTheWork()
{
Monitor.Enter(_syncObj);
try
{
// Access to the thread-sensitive resources here.
}
catch(Exception)
{
Monitor.Exit(_syncObj);
throw;
}
}
private object EndTheWork()
{
try
{
// Access to the thread-sensitive resources here.
return new object();
}
finally
{
Monitor.Exit(_syncObj);
}
}
To combine the power of the simplicity of the lock statement syntax and the flexibility of the Monitor class, Catel introduces the
SynchronizationContext class, allowing you to write the code like this.
private readonly List<IValidator> _validators = new List<IValidator>();
private readonly SynchronizationContext _synchronizationContext = new
SynchronizationContext();
public bool Contains(IValidator validator)
{
Argument.IsNotNull("validator", validator);
return _synchronizationContext.Execute(() => _validators.Contains(validator));
}
public void Remove(IValidator validator)
{
Argument.IsNotNull("validator", validator);
_synchronizationContext.Execute(() => _validators.Remove(validator));
}
public void BeforeValidation(object instance, List<IFieldValidationResult>
previousFieldValidationResults, List<IBusinessRuleValidationResult>
previousBusinessRuleValidationResults)
{
_synchronizationContext.Acquire();
try
{
foreach (IValidator validator in _validators)
{
validator.BeforeValidation(instance, previousFieldValidationResults,
previousBusinessRuleValidationResults);
}
}
catch (Exception)
{
_synchronizationContext.Release();
throw;
}
}
public void AfterValidateBusinessRules(object instance,
List<IBusinessRuleValidationResult> validationResults)
{
try
{
foreach (IValidator validator in _validators)
{
validator.AfterValidateBusinessRules(instance, validationResults);
}
}
catch (Exception)
{
_synchronizationContext.Release();
throw;
}
}
1.
2.
3.
4.
Acquiring a lock
To acquire a lock, only a call to Acquire is required:
_synchronizationContext.Acquire();
Releasing a lock
To release a lock, only a call to Release is required:
_synchronizationContext.Release();
Automatic locking of a method
It is also possible to automatically lock and release a method call. This can be accomplished using the Execute method.
_synchronizationContext.Execute(() => ThreadSafeCodeExecution());
Validation
Validation is very important for data objects. Therefore, the ModelBase supports all kinds of different validation:
Internal validation via the ValidateFields and ValidateBusinessRules methods
Validation via data annotations (attributes)
External validators using the IValidatorProvider and IValidator interfaces
The validation results are cached and only executed when a property changes (the object becomes dirty) or when the validation is forced.
Validation via validate methods
Validation via data annotations
Validation via special model validators
Validation via IValidator
Using the validation context
Getting a summary of validation results
Deferring validation
Different types of validation
There are two different types of validation in Catel, namely warnings and errors. There are also two flavors of validations, namely field validation
and business rule validation.
Order of execution of events
The order of execution is very important if you want to perform very advanced validation (such as translating validations at the end of each
validation sequence).
IValidator.BeforeValidation
OnValidation (raises Validating event)
if not already validated
IValidator.BeforeValidateFields
SynchronizationContext also allow you create asynchronous locking request, that could be useful in Silverlight Application where the
action of lock the main thread is not allowed.
The ViewModelBase derives from ModelBase, thus all information here also applies to the ViewModelBase
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
OnValidatingFields (raises the ValidatingFields event)
IValidator.ValidateFields
ValidateFields
OnValidatedFields (raises the ValidatedFields event)
IValidator.AfterValidateFields
IValidator.BeforeValidateBusinessRules
OnValidatingBusinessRules (raises the ValidatingBusinessRules event)
IValidator.ValidateBusinessRules
ValidateBusinessRules
OnValidatedBusinessRules (raises the ValidatedBusinessRules event)
IValidator.AfterValidateBusinessRules
end if not already validated
OnValidated (raises the Validated event)
IValidator.AfterValidation
There are lots of events, and it may seem complex and confusing at first sight. However, all these events give developers the opportunity to hook
into the validation sequence at any time.
Validation via validate methods
The easiest way to implement validation is to override the ValidateFields and ValidateBusinessRules methods. Below is an example of an
implementation of the ValidateFields method:
protected override void ValidateFields(List<IFieldValidationResult> validationResults)
{
if (string.IsNullOrEmpty(FirstName))
{
validationResults.Add(FieldValidationResult.CreateError(FirstNameProperty,
"First name is required"));
}
if (string.IsNullOrEmpty(LastName))
{
validationResults.Add(FieldValidationResult.CreateError(LastNameProperty,
"Last name is required"));
}
if (Gender == Gender.Unknown)
{
validationResults.Add(FieldValidationResult.CreateError(GenderProperty,
"Gender cannot be unknown"));
}
}
Validation via data annotations
Data annotations are validation when the specific property is set. For example, when a property FirstName is set, all the data annotations on the
FirstName property are validated.
Decorating properties with data annotations
Decorating properties is very simple. For example, to make a property mandatory, use the following definition (note the Required attribute):
The ViewModelBase derives from ModelBase, thus all information here also applies to the ViewModelBase
The ViewModelBase derives from ModelBase, thus all information here also applies to the ViewModelBase
/// <summary>
/// Gets or sets the middle name.
/// </summary>
[Required]
public string MiddleName
{
get { return GetValue<string>(MiddleNameProperty); }
set { SetValue(MiddleNameProperty, value); }
}
/// <summary>
/// Register the property so it is known in the class.
/// </summary>
public readonly PropertyData MiddleNameProperty = RegisterProperty("MiddleName",
typeof(string), string.Empty);
For more information about data annotations, read the official MSDN documentation.
Validation via special model validators
By default, Catel registers the as the . This way the and all the classes that derive from it AttributeValidatorProvider IValidatorProvider ModelBase
can easily add a custom validator by using the . ValidateModelAttribute
Implementing the validator
Implementing the validator
The first thing that needs to be done is to write a custom implementation of the interface. You can either implement all the members IValidator
yourself or derive from as is shown below: ValidatorBase
Note that it is still possible to register a custom IValidatorProvider to customize this behavior. It is even possible to set the Validator prop
erty of the ModelBase on a specific instance of a model
public class PersonValidator : ValidatorBase<PersonModel>
{
public override void ValidateFields(PersonModel instance,
List<IFieldValidationResult> validationResults)
{
if (string.IsNullOrWhiteSpace(instance.FirstName))
{

validationResults.Add(FieldValidationResult.CreateError(PersonModel.FirstNameProperty,
"First name is required"));
}

if (string.IsNullOrWhiteSpace(instance.LastName))
{

validationResults.Add(FieldValidationResult.CreateError(PersonModel.FirstNameProperty,
"First name is required"));
}
}

public override void ValidateBusinessRules(PersonModel instance,


List<IBusinessRuleValidationResult> validationResults)
{
// No business rules validations yet
}
}
Decorating a model with the attribute
Once a validator is available, the only thing that needs to be done is to decorate the model with the : ValidateModelAttribute
[ValidateModel(typeof(PersonValidator))]
public class PersonModel : ModelBase
{
public string FirstName
{
get { return GetValue<string>(FirstNameProperty); }
set { SetValue(FirstNameProperty, value); }
}
public static readonly PropertyData FirstNameProperty = RegisterProperty("FirstName",
typeof(string), string.Empty);
public string LastName
{
get { return GetValue<string>(LastNameProperty); }
set { SetValue(LastNameProperty, value); }
}
public static readonly PropertyData LastNameProperty = RegisterProperty("LastName",
typeof(string), string.Empty);
}
The custom validator will now automatically be called.
Validation via IValidator
The validation in Catel is extremely flexible, but sometimes it is just not enough or you are forced to use external validators. For such cases, Catel
provides the IValidatorProvider and IValidator interfaces. These allow very flexible injection or external validators into data objects and view
models of Catel.
Implementing the IValidatorProvider
The IValidatorProvider is responsible to return the right IValidator for a specific type. There is a convenience implementation named
ValidatorProviderBase which only requires the implementation of one single method. Below is an example of an implementation of the
IValidatorProvider.
public class ValidatorProvider : ValidatorProviderBase
{
/// <summary>
/// Gets a validator for the specified target type.
/// </summary>
/// <param name="targetType">The target type.</param>
/// <returns>
/// The <see cref="T:Catel.Data.IValidator"/> for the specified type or
<c>null</c> if no validator is available for the specified type.
/// </returns>
/// <exception cref="T:System.ArgumentNullException">The <paramref
name="targetType"/> is <c>null</c>.</exception>
public override IValidator GetValidator(Type targetType)
{
if (targetType == typeof(ValidationInIValidatorViewModel))
{
return new Validator();
}
// No validator available for other types
return null;
}
}
Implementing the IValidator
The IValidator exposes lots of methods to gain the as much freedom as possible. However, most of the methods that are exposed by the interface
are hardly used. Therefore there is a convenience base class named ValidatorBase. To create a basic validator, derive from the class and
override the methods required for validation.
The ViewModelBase derives from ModelBase, thus all information here also applies to the ViewModelBase
public class Validator : ValidatorBase<TargetClass>
{
/// <summary>
/// Validates the fields of the specified instance. The results must be added to
the list of validation
/// results.
/// </summary>
/// <param name="instance">The instance to validate.</param>
/// <param name="validationResults">The validation results.</param>
/// <exception cref="T:System.ArgumentNullException">The <paramref
name="instance"/> is <c>null</c>.</exception>
/// <exception cref="T:System.ArgumentNullException">The <paramref
name="validationResults"/> is <c>null</c>.</exception>
public override void ValidateFields(TargetClass instance,
List<IFieldValidationResult> validationResults)
{
if (string.IsNullOrEmpty(instance.FirstName))
{

validationResults.Add(FieldValidationResult.CreateError(TargetClass.FirstNameProperty,
"First name cannot be empty"));
}
if (string.IsNullOrEmpty(instance.LastName))
{

validationResults.Add(FieldValidationResult.CreateError(TargetClass.LastNameProperty,
"Last name cannot be empty"));
}
}
/// <summary>
/// Validates the business rules of the specified instance. The results must be
added to the list of validation
/// results.
/// </summary>
/// <param name="instance">The instance to validate.</param>
/// <param name="validationResults">The validation results.</param>
/// <exception cref="T:System.ArgumentNullException">The <paramref
name="instance"/> is <c>null</c>.</exception>
/// <exception cref="T:System.ArgumentNullException">The <paramref
name="validationResults"/> is <c>null</c>.</exception>
public override void ValidateBusinessRules(TargetClass instance,
List<IBusinessRuleValidationResult> validationResults)
{
// No business rules (yet)
}
}
Setting the validator in ModelBase
To register an IValidator instance on a ModelBase, use the following code:
myObject.Validator = new MyValidator();
If an IValidatorProvider instance is available, the following code can be used to allow a more generic approach. This code assumes that the
IValidatorProvider is registered in the ServiceLocator.
var validatorProvider = ServiceLocator.Instance.ResolveType<IValidatorProvider>();
myObject.Validator = validatorProvider.GetValidator(myObject.GetType());
If the IValidatorProvider returns null (which is allowed), no custom validator will be used.
Setting the validator in ViewModelBase
The ViewModelBase has it's own ServiceLocator. The easiest way to support a validator is to register an IValidatorProvider instance in the
ServiceLocator:
ServiceLocator.Instance.RegisterType<IValidatorProvider, MyValidatorProvider>();
The ViewModelBase will automatically retrieve the right IValidator for the view model. If no IValidatorProvider is registered in the ServiceLocator,
no validator will be set automatically. It is also possible to set the Validator property manually, but it is recommended to use an IValidatorProvider
and register it.
Using the validation context
Sometimes detailed information about validation is required. This is possible in Catel thanks to the ValidationContext class. The ValidationContext
serves as the container for all validation results that are gathered via the available validation methods. The ValidationContext has lots of methods
that all return lists of either IFieldValidationResult or IBusinessRuleValidationResult.
The examples below are shown a starter examples, but you can gather every type of validation result by using the ValidationContext. To retrieve
the validation context of an object, use the following code:
var viewModel = new MyViewModel();
var validationContext = viewModel.ValidationContext;
Getting the number of or warnings and errors
To retrieve the total number of warnings and errors, use the following code:
int count = validationContext.GetValidationCount();
Getting all the field errors
To retrieve all the field errors, use the following code:
var fieldErrors = validationContext.GetFieldErrors();
Getting all the field errors of a specific property
To retrieve all the field errors of a specific property, use the following code:
var fieldErrors = validationContext.GetFieldErrors("MyProperty");
The ViewModelBase derives from ModelBase, thus all information here also applies to the ViewModelBase
Getting all the business rule warnings
To retrieve all the business rule warnings:
var businessRuleWarnings = validationContext.GetBusinessRuleWarnings();
Getting all the business rule errors with a specific tag
To retrieve all the business rule errors with a specific tag, use the following code:
var businessRuleErrors = validationContext.GetBusinessRuleErrors("myTag");
Getting a summary of validation results
Sometimes you just need to get a summary of all warnings and errors of an object. All validation is gathered in the IValidationContext and
available on that class. However, there are some convenience classes that allow a developer to create a summary based on a specific tag. This
convenience class is IValidationSummary, which gathers the right information from an instance of IValidationContext.
Creating a summary of all validations
To retrieve a summary of all validations from a IValidationContext, use the following code:
var validationSummary = validationContext.GetValidationSummary();
Creating a summary of all validations with a specific tag
To retrieve a summary of all validations with a specific tag from a IValidationContext, use the following code:
var validationSummary = validationContext.GetValidationSummary("tag");
Using the ValidationToViewModel attribute
The ValidationToViewModel attribute allows a developer to gather a summary of an object easily. For example, to get all the person related
validation into the property, use the property definition below: PersonValidationSummary
[ValidationToViewModel(Tag = "PersonValidation")]
public IValidationSummary PersonValidationSummary { get; set; }
All validation results that have the tag will automatically be gathered into the property after each PersonValidation PersonValidationSummary
validation sequence.
Deferring validation
The opinions about validation differ from person to person. Some people think it is best practice to immediately show the errors to the users.
Others want to defer it to the moment where the user clicks the Save or OK button. Catel supports both "best practices".
Suspending validation for a batch of changes
Deferring validation in view models
Suspending validation for a batch of changes
Sometimes you need to change a batch of properties and don't want validation to be called after every property change. This can be
accomplished by using the following code inside a class: ModelBase
SuspendValidation = true;

// change several properties here

SuspendValidation = false;

// Now force validation


Validate(true);
Deferring validation in view models
Below is a table of properties that can be used to affect the validation deferring.
Property Validate immediately Defer to a later moment
DeferValidationUntilFirstSaveCall false true
ValidateModelsOnInitialization true false
Catel.MVVM
The last few years, MVVM has become the number one pattern to write applications using WPF, Silverlight, and Windows Phone 7. The actual
pattern is very simple, but there are some flaws and questions lots of MVVM users have, such as:
How to show modal dialogs or message boxes inside a View-Model?
How to run processes inside a View-Model?
How to let the user select a file inside a View-Model?
In my opinion, this is where the good frameworks separate themselves from the bad ones. For example, people actually calling
MessageBox.Show inside a View-Model are using the pattern wrong. If you are one of the developers that directly call a MessageBox inside a
View-Model, ask yourself this: who is going to click the button during a unit test?
Before we actually started developing Catel, we did lots of investigations to make sure that the MVVM pattern was really useful in Line of
Business (LoB) applications and does not miss the finishing touch. Thanks to this investigation and research, we created a solid MVVM
framework which solves all the known problems of the MVVM pattern.
This part of the documentation explains all about the MVVM framework included with Catel. The MVVM framework that ships with Catel has the
following characteristics and features:
Very easy to use, a view model is created within 10 minutes
Direct pass-through of view model properties to Models
Validation mapping from model to view model and back
Solves the nested user controls problem
If you are not yet familiar with MVVM, it is advised to read a small introduction on . Wikipedia
Auditing
Behaviors & triggers
Commands & events
Converters
Designers
Handling application initialization parameters
Locators and naming conventions
Services
View models
Views
Auditing
There are lots of lightweight MVVM frameworks out there, which work great for the basics. However, if you are writing larger enterprise
applications, notifying the UI of changed properties isn't enough. For example, did you think about Command Authentication? Or what about
sensor emulation for Windows Phone 7 (that Microsoft dont provide)?
If the DeferValidationUntilFirstSaveCall property, is used, it must be set as first property in the view model because the validation kicks
in immediately when properties change.
Why auditing
Creating an auditor
Registering an auditor
Why auditing
There are many reasons why auditing should be added to an application. Most developers only add auditing to the database, but below are
several reasons to add auditing to the client as well:
Logging (what user did what on specific moments)
Gather statistics (which views (view models) are used most)
See what features of your software are being used by checking if anyone is actually invoking specific commands
Measure performance (how long does it take to update specific properties or why is a specific view-model so slow?)
With the auditing capabilities of Catel, you can create and register custom auditors that can handled changes and events of view models. This
way, you can gather a lot of statistics or any information that you want to gather about the user experience. Below is a list of events that can be
handled:
OnViewModelCreating
OnViewModelCreated
OnPropertyChanging
OnPropertyChanged
OnCommandExecuting
OnViewModelSaving
OnViewModelSaved
OnViewModelCanceling
OnViewModelCanceled
OnViewModelClosing
OnViewModelClosed
The developer has all the freedom to handle one or more methods in an auditor. Of course multiple auditors are possible as well.
Creating an auditor
Creating a new auditor is very simple. Create a new class, derive from and override the methods you are interested in. The class AuditorBase
example tracks the event to a fake analytics framework.
/// <summary>
/// Logs all commands to a custom analytics service.
/// </summary>
public class CommandAuditor : AuditorBase
{
private Analytics _analytics = new Analytics();
/// <summary>
/// Called when a command of a view model has just been executed.
/// </summary>
/// <param name="viewModel">The view model.</param>
/// <param name="commandName">Name of the command, which is the name of the command
property.</param>
/// <param name="command">The command that has been executed.</param>
/// <param name="commandParameter">The command parameter.</param>
public override void OnCommandExecuted(IViewModel viewModel, string commandName,
ICatelCommand command, object commandParameter)
{
_analytics.TrackEvent(viewModel.GetType(), "commandName");
}
}
Registering an auditor
Registering a new auditor is extremely easy as you can see in the code below:
AuditingManager.RegisterAuditor(new CommandAuditor());
Behaviors & triggers
Behaviors and triggers are very important to correctly separate the view from the view model. For example, to respond to and event in a view
model, you cannot simply subscribe to the events in the view. The EventToCommand behavior is a great example to solve this problem.
Catel offers lots of behaviors out of the box, so it is definitely worth taking a look at the behaviors.
Authentication
DelayBindingUpdate
DoubleClickToCommand
EventToCommand
Focus
FocusFirstControl
KeyPressToCommand
MouseInfo
Navigate
NumericTextBox
SelectTextOnFocus
UpdateBindingOnPasswordChanged
UpdateBindingOnTextChanged
Authentication
The Authentication behavior is able to hide, collapse or disable UI elements based on the current user state. The behavior uses the registered
IAuthenticationProvider instances to determine whether the user has access to the specified UI element.
1) Creating an authentication provider:
Note that Windows 8.0 does not support any behaviors or triggers. Windows 8.1 does support behaviors, but no triggers.
/// <summary>
/// Example implementation of the <see cref="AuthenticationProvider"/>. This class is
not really implemented
/// like it should, because it shouldn't be this easy to set the current role.
However, for the sake of simplicity,
/// this class has a simple property with the role of the user.
/// </summary>
public class AuthenticationProvider : IAuthenticationProvider
{
/// <summary>
/// Gets or sets the role the user is currently in.
/// </summary>
/// <value>The role.</value>
public string Role { get; set; }

public bool CanCommandBeExecuted(ICatelCommand command, object commandParameter)
{
return true;
}

public bool HasAccessToUIElement(FrameworkElement element, object tag, object
authenticationTag)
{
var authenticationTagAsString = authenticationTag as string;
if (authenticationTagAsString != null)
{
if (string.Compare(authenticationTagAsString, Role, true) == 0)
{
return true;
}
}

return false;
}
}
2) Register the authentication provider in the ServiceLocator:
Catel.IoC.ServiceLocator.Instance.RegisterType<IAuthenticationProvider,
AuthenticationProvider>();
3)Add the following XML namespaces to your view:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactiv
ity"
xmlns:catel="http://catel.codeplex.com"
4) Add the behavior. As you can see, it is possible to provide a custom , which is passed to the : AuthenticationTag IAuthenticationProvider
<TextBox>
<i:Interaction.Behaviors>
<catel:Authentication AuthenticationTag="Administrator" Action="Disable" />
</i:Interaction.Behaviors>
</TextBox>
5) Below are screenshots of the example applications (which can be found at http://catelexamples.codeplex.com):
Logged in as administrator:
Logged in as read-only user:
DelayBindingUpdate
Sometimes, a binding update should be delayed for performance reasons. This is possible using the DelayBindingUpdate behavior. This behavior
modifies the binding mode to explicit and internally watches for property changes. If the bound dependency property changes, the behavior will
wait for the time to pass and then update. If the value changes again within the timeframe, the timer is reset (so you won't get "double" updates).
1) Add the following XML namespaces:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactiv
ity"
xmlns:catel="http://catel.codeplex.com"
2) Use the following definition. This example will delay the update of the SelectedItem binding with 100 milliseconds:
<ListBox x:Name="listBox" ItemsSource="{Binding PersonCollection}"
SelectedItem="{Binding SelectedPerson}">
<i:Interaction.Behaviors>
<catel:DelayBindingUpdate PropertyName="SelectedItem" UpdateDelay="100" />
</i:Interaction.Behaviors>
</ListBox>
DoubleClickToCommand
Lots of times, a developer needs to handle a double click event. However, somehow the Silverlight team thought that double click had no priority
at all. Luckily, Catel offers the solution by providing the DoubleClickToCommand trigger. This trigger allows a developer to track a double click on
any FrameworkElement and respond to that using a command.
1) Add the following XML namespaces:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactiv
ity"
xmlns:catel="http://catel.codeplex.com"
2) Use the following definition. This example will invoke the Edit command of the view model when the item is double clicked):
<ListBox x:Name="listBox" ItemsSource="{Binding PersonCollection}"
SelectedItem="{Binding SelectedPerson}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<i:Interaction.Behaviors>
<catel:DoubleClickToCommand Command="{Binding ElementName=listBox,
Path=DataContext.Edit}" />
</i:Interaction.Behaviors>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding FirstName}" />
<Label Content="{Binding MiddleName}" />
<Label Content="{Binding LastName}" />
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The trigger contains an additional property AutoFixListBoxItemTemplate which is set to true by default to easily allow the addition of a double click
event to a ListBox. The item template must contain a grid as a base like shown above.
EventToCommand
Almost every respectable MVVM framework supports the EventToCommand trigger. It is a trigger that allows a an event to be turned into a
command. This way, you never have to manually add event handlers, search for the view model in the code-behind and then call the right
command.
The usage is really simple, but requires the reference (ships with Catel). The example below shows how to add a System.Windows.Interactivity.dll
This behavior also supports a constructor that accepts an Action. This way, an anonymous delegate can be executed when the
behavior is created in code
trigger for the double click of a ListBox.
1) Add the following XML namespaces:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactiv
ity"
xmlns:catel="http://catel.codeplex.com"
2) Use the following definition. This example will invoke the Edit command of the view model):
<ListBox ItemsSource="{Binding PersonCollection}" SelectedItem="{Binding
SelectedPerson}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<catel:EventToCommand Command="{Binding Edit}"
DisableAssociatedObjectOnCannotExecute="False" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding FirstName}" />
<Label Content="{Binding MiddleName}" />
<Label Content="{Binding LastName}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
If you want to use parameters (in the case of this example, get the MouseDoubleClick event args, set PassEventArgsToCommand to true:
<Commands:EventToCommand Command="{Binding Edit}"
DisableAssociatedObjectOnCannotExecute="False" PassEventArgsToCommand="True" />
Then, in the view model, you can even make the command "type-safe":
/// <summary>
/// Gets the Edit command.
/// </summary>
public Command<MouseEventArgs> Edit { get; private set; }
// TODO: Move code below to constructor
Edit = new Command(OnEditExecute, OnEditCanExecute);
// TODO: Move code above to constructor
/// <summary>
/// Method to check whether the Edit command can be executed.
/// </summary>
private bool OnEditCanExecute(MouseEventArgs e)
{
return true;
}
/// <summary>
/// Method to invoke when the Edit command is executed.
/// </summary>
private void OnEditExecute(MouseEventArgs e)
{
// TODO: Handle command logic here
}
Focus
To set the focus on a UI element, one must write code in the code-behind. With the Focus behavior, this is no longer necessary. This behavior
sets the focus only once on the first time the associated object is loaded.
Add the following XML namespaces:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactiv
ity"
xmlns:catel="http://catel.codeplex.com"
Focus when the control is loaded
The easiest and default method is to set the focus when the associated control is loaded. In WPF, this is immediately when the control is focused.
In Silverlight, there is a delay of 400 milliseconds by default, otherwise the focus is not set correctly.
<ListBox ItemsSource="{Binding PersonCollection}" SelectedItem="{Binding
SelectedPerson}">
<i:Interaction.Behaviors>
<catel:Focus />
</i:Interaction.Behaviors>
</ListBox>
Focus when an event occurs
In Silverlight, simply calling Focus() on the associated object is not enough. Therefore, the focus is set with a timer with a default delay
of 500 milliseconds. This is customizable via the FocusDelay property
It is possible to set the focus when a specific event occurs. For example, when the layout root gets a MouseEnter event, the focus must be set on
a specific control. This can be done via the following code:
<ListBox ItemsSource="{Binding PersonCollection}" SelectedItem="{Binding
SelectedPerson}">
<i:Interaction.Behaviors>
<catel:Focus FocusMoment="Event" Source="{Binding ElementName=layoutRoot}"
EventName="MouseEnter" />
</i:Interaction.Behaviors>
</ListBox>
Focus when a property changes
It is possible to set the focus when a specific property changes. For example, when a value is set, the focus must move on to a new control. This
can be done via the following code:
<ListBox ItemsSource="{Binding PersonCollection}" SelectedItem="{Binding
SelectedPerson}">
<i:Interaction.Behaviors>
<catel:Focus FocusMoment="PropertyChanged" Source="{Binding }"
PropertyName="MyProperty" />
</i:Interaction.Behaviors>
</ListBox>
FocusFirstControl
The Focus behavior is very powerful, but sometimes you just need to focus the first control on a window or control. This can be done by using the
FocusFirstControl behavior instead. This behavior will focus the first control on a window or control and has only one property: . FocusParentFirst
Add the following XML namespaces:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactiv
ity"
xmlns:catel="http://catel.codeplex.com"
Focus when the control is loaded
The easiest and default method is to focus the first control. The parent is also focused by default (just in case if it doesn't have any focus):
<Window ...>
<i:Interaction.Behaviors>
<catel:FocusFirstcontrol />
</i:Interaction.Behaviors>
</Window>
KeyPressToCommand
Sometimes you need to handle a key press and convert it to a command. An excellent example is a ListBox that should respond to an Ctrl + Enter
If you are using Silverlight, and you don't want the default delay of 500 milliseconds, make sure to explicitly set it to 0
If you are using Silverlight, and you don't want the default delay of 500 milliseconds, make sure to explicitly set it to 0
key press.
1) Add the following XML namespaces:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactiv
ity"
xmlns:catel="http://catel.codeplex.com"
2) Use the following definition:
<ListBox x:Name="listBox" ItemsSource="{Binding PersonCollection}"
SelectedItem="{Binding SelectedPerson}">
<i:Interaction.Behaviors>
<catel:KeyPressToCommand Command="{Binding MyCommand}" Key="Enter"
Modifiers="Ctrl" />
</i:Interaction.Behaviors>
</ListBox>
MouseInfo
Silverlight is missing a lot. One of the things that is missing are decent mouse events such as IsMouseOver. To implement such behavior, the
MouseInfo behavior is created. It supports several mouse events (even in Silverlight!).
OnMouseOver
1) Add the following XML namespaces:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactiv
ity"
xmlns:catel="http://catel.codeplex.com"
2) Use the following definition:
<ListBox ItemsSource="{Binding PersonCollection}" SelectedItem="{Binding
SelectedPerson}">
<i:Interaction.Behaviors>
<catel:MouseInfo x:Name="personCollectionMouseInfo" />
</i:Interaction.Behaviors>
</ListBox>
3) Now, it is easy to bind to the mouse information like this (textblock will become visible when the listbox is hovered):
<TextBlock Visibility="{Binding ElementName=personCollectionMouseInfo,
Path=IsMouseOver, Converter={StaticResource BooleanToCollapsingVisibilityConverter},
ConverterParameter=false}" Text="Hovering listbox" />
Navigate
In WPF, the e.Handled is set to true for the RoutedEvent
Note that this behavior is only available for WPF
The Hyperlink control in WPF is very powerful, but it is hard to make them work outside pages.
Add the following XML namespaces:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactiv
ity"
xmlns:catel="http://catel.codeplex.com"
To execute the NavigateUrl, simply use the behavior as shown below:
<TextBlock>
<Hyperlink NavigateUri="http://catel.codeplex.com">
<i:Interaction.Behaviors>
<catel:Navigate />
</i:Interaction.Behaviors>
<TextBlock Text="The best MVVM Framework" />
</Hyperlink>
</TextBlock>
NumericTextBox
The NumericTextBox behavior makes it easy to allow specific numeric input on a TextBox.
1) Add the following XML namespaces:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactiv
ity"
xmlns:catel="http://catel.codeplex.com"
2) Use the following definition:
<TextBox Text={Binding Amount}">
<i:Interaction.Behaviors>
<catel:NumericTextBox />
</i:Interaction.Behaviors>
</TextBox>
SelectTextOnFocus
The SelectTextOnFocus behavior makes it easy to select all text when a TextBox receives the focus.
1) Add the following XML namespaces:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactiv
ity"
xmlns:catel="http://catel.codeplex.com"
Another alternative is to use the LinkLabel control
Use the properties on the behavior to customize the behavior to your needs
2) Use the following definition:
<TextBox Text={Binding Amount}">
<i:Interaction.Behaviors>
<catel:SelectTextOnFocus />
</i:Interaction.Behaviors>
</TextBox>
UpdateBindingOnPasswordChanged
The UpdateBindingOnPasswordChanged is a very useful behavior which allows to bind the Password property of the PasswordBox Control. Use
it, it's really simple.
Usage in WPF
1) Add the following XML namespaces:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactiv
ity"
xmlns:catel="http://catel.codeplex.com"
2) Use the following definition:
<PasswordBox>
<i:Interaction.Behaviors>
<catel:UpdateBindingOnPasswordChanged Password="{Binding Password,
Mode=TwoWay}" />
</i:Interaction.Behaviors>
</PasswordBox>
Usage in Silverlight
1) Add the following XML namespaces:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactiv
ity"
xmlns:catel="http://catel.codeplex.com"
2) Use the following definition:
<PasswordBox Password="{Binding Password, Mode=TwoWay}">
<i:Interaction.Behaviors>
<catel:UpdateBindingOnPasswordChanged />
</i:Interaction.Behaviors>
</PasswordBox>
UpdateBindingOnTextChanged
The UpdateBindingOnTextChange is a very useful behavior which allows to delay a binding update on the TextChanged event of a TextBox. This
way, it is possible to implement search boxes that only start a search after a specific time when no new key presses have occurred. For example,
when a user types a new search string, and the user doesn't enter a new key for 500 ms, the binding is updated.
1) Add the following XML namespaces:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactiv
ity"
xmlns:catel="http://catel.codeplex.com"
2) Use the following definition. This example will update the binding after 500 ms where normally it would only occur when the user tabs out of the
TextBox:
<TextBox Text="{Binding SearchParam, Mode=TwoWay}">
<i:Interaction.Behaviors>
<catel:UpdateBindingOnTextChanged UpdateDelay="500" />
</i:Interaction.Behaviors>
</TextBox>
Commands & events
Commanding is supported by Catel. Catel supports Command classes, which is also known as or in other RelayCommand DelegateCommand
frameworks. Defining a command on a view model is very easy, as you can see in the code below:
// TODO: Move code below to constructor
Edit = new Command(OnEditExecute, OnEditCanExecute);
// TODO: Move code above to constructor
/// <summary>
/// Gets the Edit command.
/// </summary>
public Command Edit { get; private set; }
/// <summary>
/// Method to check whether the Edit command can be executed.
/// </summary>
private bool OnEditCanExecute()
{
return true;
}
/// <summary>
/// Method to invoke when the Edit command is executed.
/// </summary>
private void OnEditExecute()
{
// TODO: Handle command logic here
}
There are some people who dont like the implementations. For example, Caliburn (Micro) uses convention and does not require the ICommand
creation of a command. There are a few downsides for that:
It requires you to make sure the name of the control is the same as the method;
It is not clear that it is actually a command if you are not fully familiar with the conventions;
The methods need to be public (otherwise, how are you going to invoke the commands during unit tests?), which make them freely
available (and thats not something we like);
You will always have to invoke CanExecute yourself again in Execute, because you have no guarantee that the source of Execute is
actually the convention mapping;
There is no way to manually refresh the CanExecute state on the bound controls.
For more information, see:
Commands
Application-wide commands
Asynchronous commands
Commands authentication
Hooking a command to validation automatically
Commands
Commands are supported in Catel. The base class for commands is . Command
Code snippets
vmcommand - declare a command on a view model
vmcommandwithcanexecute - declare a command with support for CanExecute on a view model
Explanation
To implement commands, and still be able to unit test the view models, a separate command is introduced. This command allows a developer to
implement a command that can be invoked both via code (unit testing) and UI.
There is one real class: Command Command<TCanExecuteParameter, TExecuteParameter>
The is the parameter that is passed to the of the command, ands saves the developer from casting the TCanExecuteParameter CanExecute
object (as in the interface to a typed object). The same goes for which makes the of the command typed. ICommand TExecuteParameter Execute
There are also several wrappers available in case object is used as type parameter:
Command<TExecuteParameter> (wraps with object for Command<TCanExecuteParameter, TExecuteParameter> TCanExecuteParamet
) er
Command (wraps with object for ) Command<TExecuteParameter> TExecuteParameter
Examples
Code:
private readonly IMessageService _messageService;

public void MyViewModel(IMessageService messageService)


{
Argument.IsNotNull(() => messageService);

_messageService = messageService;
// Add commands
MyAction = new Command(MyAction_Execute);
}
/// <summary>
/// Gets the MyAction command.
/// </summary>
public Command MyAction { get; private set; }
/// <summary>
/// Method to invoke when the MyAction command is executed.
/// </summary>
/// <param name="parameter">The parameter of the command.</param>
private void MyAction_Execute(object parameter)
{
// Show message box
_messageService.ShowInfo("My action in MVVM");
}
Xaml (assuming that the view model is set as datacontext):
<Button Content="Click me" Command="{Binding MyCommand}" />
Application-wide commands
Most commands are registered per view and available per view model. Some commands (such as commands on a or ) are Ribbon Toolbar
application-wide. Catel supports both types, and this part of the documentation explains how to use the to work with ICommandManager
application-wide commands such as with a key bound to . Refresh F5
Introduction to CommandManager
Creating application-wide commands
Registering a custom command
Using application-wide commands in xaml
Introduction to CommandManager
There is no generic way to specify application-wide commands in WPF and Silverlight. To overcome this issue, Catel introduces the CommandMa
. This manager allows to create commands which are hosted by the . The commands on the command manager can be nager CommandManager
created with input gestures (on both WPF and Silverlight). Once a view model wants to hook into a specific command, it only has to register the
view model command with the application-wide command.
Creating application-wide commands
To create application-wide commands, one must resolve the from the and create the command: ICommandManager DependencyResolver
var dependencyResolver = IoCConfiguration.DefaultDependencyResolver;
var commandManager = dependencyResolver.Resolve<ICommandManager>();

commandManager.CreateCommand("Refresh", new InputGesture(Key.F5));


Registering a custom command
When a view model wants to use application-wide specific commands, the only thing it has to do is register the command in the CommandManag
. er
It is recommended to put all the command creation in a single place so they are easily manageable.
public class CommandSubscribingViewModel : ViewModelBase
{
private readonly IMessageService _messageService;
public CommandSubscribingViewModel(ICommandManager commandManager, IMessageService
messageService)
{
Argument.IsNotNull(() => commandManager);
Argument.IsNotNull(() => messageService);

_messageService = messageService;

ExampleCommand = new Command(OnExampleCommandExecute);
commandManager.RegisterCommand("Refresh", ExampleCommand, this);
}
public Command ExampleCommand { get; private set; }
private void OnExampleCommandExecute()
{
_messageService.Show("Application-wide command executed");
}
}
Using application-wide commands in xaml
To make it easy to bind to application-wide commands, Catel provides the markup extension for WPF and Silverlight. CommandManagerBinding
To bind to commands in xaml, use the following code:
<Ribbon catel:StackGrid.ColumnSpan="4">
<RibbonTab Header="Home" KeyTip="H" >
<RibbonGroup Header="Example commands">
<RibbonButton Command="{catel:CommandManagerBinding Refresh}"
LargeImageSource="..\Resources\Images\Refresh.png"
Label="Refresh" KeyTip="F5" />
</RibbonGroup>
</RibbonTab>
</Ribbon>
As the code shows, the extension automatically resolves the command from the . CommandManagerBinding Refresh CommandManager

Asynchronous commands
Commands in MVVM are a very precious good. Actually, MVVM can't exist without them because they allow a developer to bind to a method
(that's actually all an implementation is). However, sometimes it is required to create asynchronous commands. Starting with Catel ICommand
3.1, the is introduced. AsynchronousCommand
With the , it is possible to create a command that executes a method in the background without blocking the UI thread. It AsynchronousCommand
is possible to report progress to the UI thread.
Creating the command
The can be used the same as the the regular class. The command must be constructed like this: AsynchronousCommand Command
CancelableAsyncCommand = new AsynchronousCommand(OnCancelableAsyncCommand, () =>
!CancelableAsyncCommand.IsExecuting);
The second parameter is the delegate, and this example does not allow multiple executions of the same command at the same time. CanExecute
Running the command
Running the command is the same as the regular class. The view can simply bind to the command like the code below: Command
<Button Command="{Binding CancelableAsyncCommand}" Content="Execute Command" />
Canceling the command
Last but not least, the cool thing about the is that it can complete in two ways. It either completes the method by itself, or AsynchronousCommand
it is canceled from the outside. To cancel a running command, two steps must be accomplished:
1.Bind to the property of the : CancelCommand AsynchronousCommand
<Button Command="{Binding CancelableAsyncCommand.CancelCommand}" Content="Cancel
Command" />
2.Make sure the execute action checks the property like in the example below: ShouldCancel
private void OnCancelableAsyncCommand()
{
for (var i = 1; i <= 100; i++)
{
if (CancelableAsyncCommand.ShouldCancel)
{
// If we should cancel, break out of the loop
break;
}
Thread.Sleep(100);
}
}
Reporting progress
During the execution of a command, it is possible to report progress back to the main thread. This can done by using the method. ReportProgress
All code inside the will be executed in the UI thread: ReportProgress
Note that this example looks stupid and you should not use Thread.Sleep, but this is just for the sake of simplicity and the example
private void OnCancelableAsyncCommand()
{
for (var i = 1; i <= 100; i++)
{
if (CancelableAsyncCommand.ShouldCancel)
{
// If we should cancel, break out of the loop
break;
}
var i1 = i;
CancelableAsyncCommand.ReportProgress(() =>
Messages.Add(i1.ToString(CultureInfo.InvariantCulture)));
Thread.Sleep(100);
}
}
Commands authentication
One of the questions an MVVM developer faces is how to control the executation state of a command by role or user authentication method. Catel
offers an out-of-the-box solution for this problem to check the state of the commands in the UI. CanExecute
Tagging your commands
To know whether a specific user can execute a command, you need to be able to distinguish one command from another. The in ICatelCommand
terface (which derives from ) providers a property that allows you to tag the command with any object that fits your needs. In one ICommand Tag
application, commands might be distinguished using strings, other applications use integer ID's.
A tag must be set in the constructor of a command and cannot be changed:
Edit = new Command(OnEditExecute, OnEditCanExecute, "editCommand");
IAuthenticationProvider
The is a provider that needs to be implemented per application and must be registered in the IoC container. Below is the IAuthenticationProvider
interface definition:
It is very important that this way of disabling commands is only used to easy the development of consistent user interfaces. It cannot
replace the actual check whether a user can or cannot modify data. The actual and final responsibility still lays at the business layer.
/// <summary>
/// Interface to allow an authentication mechanism to control the CanExecute state of
a command.
/// </summary>
public interface IAuthenticationProvider
{
/// <summary>
/// Determines whether the specified <paramref name="command"/> can be executed.
The class implementing this interface
/// can use any required method to check the command.
/// <para />
/// It is recommended to use the <see cref="ICatelCommand.Tag"/> property to
identify a command.
/// </summary>
/// <param name="command">The command that is requested.</param>
/// <param name="commandParameter">The command parameter.</param>
/// <returns>
/// <c>true</c> if this instance [can command be executed] the specified
command; otherwise, <c>false</c>.
/// </returns>
/// <remarks>
/// The <c>CanExecute</c> state of a command is queried a lot. The command itself
does not cache any results because
/// it is not aware of role or identity changes. If caching is required, this must
be implemented in the class implementing
/// the <see cref="ICommandAuthenticationProvider"/> interface.
/// </remarks>
bool CanCommandBeExecuted(ICatelCommand command, object commandParameter);
}
To register a custom implementation of the command authentication provider, use the code below:
Catel.IoC.ServiceLocator.Instance.RegisterType<IAuthenticationProvider,
RoleAuthenticationProvider>();
The code above registers a custom made command authentication provider that checks whether a specific role can execute the command.
Hooking a command to validation automatically
It is possible to hook the of a to the automatically. This way, there is no need to check for errors CanExecute Command IValidationSummary
manually in the method. The example below first adds a validation summary to a view model to get the validation result. Then, it uses CanExecute
this validation summary to automatically determine whether a command can be executed.
1.Add validation to a person view model (note how the validation adds the tag to a validation): PersonValidation
Catel checks whether an is registered. If not, the way commands are handled is not affected in any way. If there IAuthenticationProvider
is an available, the state is checked, even when there is no custom implemented. IAuthenticationProvider CanExecute CanExecute
/// <summary>
/// Validates the field values of this object. Override this method to enable
/// validation of field values.
/// </summary>
/// <param name="validationResults">The validation results, add additional results to
this list.</param>
protected override void
ValidateFields(System.Collections.Generic.List<IFieldValidationResult>
validationResults)
{
if (string.IsNullOrEmpty(FirstName))
{

validationResults.Add(FieldValidationResult.CreateErrorWithTag(FirstNameProperty,
"First name cannot be empty", "PersonValidation"));
}
if (string.IsNullOrEmpty(LastName))
{

validationResults.Add(FieldValidationResult.CreateErrorWithTag(LastNameProperty, "Last
name cannot be empty", "PersonValidation"));
}
}
2.Add a property to the view model containing the validation summary using the attribute. ValidationToViewModel
[ValidationToViewModel(Tag = "PersonValidation")]
public IValidationSummary PersonValidationSummary { get; set; }
3. Define a command on the view model:
/// <summary>
/// Gets the Save command.
/// </summary>
public Command Save { get; private set; }
/// <summary>
/// Method to invoke when the Save command is executed.
/// </summary>
private void OnSaveExecute()
{
// TODO: Handle command logic here
}
4. Create the command that automatically uses the validation summary using the class: CommandHelper
Save = CommandHelper.CreateCommand(OnSaveExecute, () => PersonValidationSummary);
With this example, the command on the view model can only be executed when there are no errors with the tag. Save PersonValidation
Converters
In MVVM, there will be some point where you will need to use converters. Most of these converters are used in any project, so we have decided
to add them to Catel. Below is a list of converters and a short description what they are used for.
Linking converters
Available converters
Linking converters
It is possible to link converters. To link converters, simply set the property in xaml: Link
<catel:NullableValueConverter x:Key="NullableValueConverter" />

<catel:BooleanToVisibilityConverter>
<catel:BooleanToVisibilityConverter.Link>
<code:NullToBoolConverter Link="{StaticResource NullableValueConverter}" />
</catel:BooleanToVisibilityConverter.Link>
</catel:BooleanToVisibilityConverter>
Available converters
Name Description
AreEqualMultiValueConverter Converts the comparison of 2 values to a boolean
BooleanToCollapsingVisibilityConverter Convert from bool to and back. Visibility
BooleanToHidingVisibilityConverter Convert from bool to and back. Visibility
BooleanToGrayscaleConverter Converts a boolean to a grayscale saturation value. If the input is
false, this converter will return 0, otherwise 1.
BooleanToOppositeBooleanConverter Convert a boolean to it's inverted value.
BooleanToTextConverter Converts a boolean value to text, for example "yes" and "no", or "x"
and " ".
BooleanToCollapsingVisibilityConverter Convert from bool to and back. True returns , Visibility Visibility.Visible
False returns . Visibility.Collapsed
BooleanToHidingVisibilityConverter Convert from bool to and back. True returns , Visibility Visibility.Visible
False returns . Visibility.Hidden
ColorToBrushConverter Converts a color value to a brush and vice versa.
ContainsItemsConverter Convert the count of an ICollection or IEnumerable to true or false,
depending on whether the instance contains items.
For an instance which implements ICollection, check Count > 0
For an instance which implements IEnumerable, if the instance can
be Enumerated.
CountCollapsedConverter Converts the 'count' of ICollection, string, long, int or short to Visibility
or .Visible Visibility.Collapsed
Visible means: ICollection.Count > 0, String.Length > 0 or long, int,
short > 0.
CountHiddenConverter Converts the 'count' of ICollection, string, long, int or short to Visibility
or .Visible Visibility.Hidden
Visible means: ICollection.Count > 0, String.Length > 0 or long, int,
short > 0.
Note that the behavior of most converters can be inverted by using the ConverterParameter
EmptyStringToCollapsingVisibilityConverter Converts a string to . If the string is empty, it will return Visibility Visibili
. ty.Collapsed
EmptyStringToHidingVisibilityConverter Converts a string to Visibility. If the string is empty, it will return Visibili
ty.Hidden.
FormattingConverter Formats the value using the format string provided in the
ConverterParameter
IntToStringConverter Converts integer to string and back.
IsSelectedConverter Converts a selected value to either true of false.
IsSelectedValueConverter Converts a selected value to either true of false.
GetFirstValidationErrorConverter Converts a collection containing ValidationError objects to return the
first error or an empty string in case there are no errors.
IsSelectedConverter Converts a selected value to either true or false. Useful whena
mutually exclusive selection must be made.
IntToStringConverter Converts an inteteger to a string and back.
MethodToValueConverter Converts the result of a method to a value. This makes it possible to
bind to a method. See Source
MultiplyConverter Calculates the product of given value and factor in parameter.
NullableValueConverter Converts a value to a representive value for nullable.
ReferenceToBooleanConverter Converts a reference to a boolean. If the reference is , it will return null
. false
ReferenceToCollapsingVisibilityConverter Converts a reference to . If the reference is , it will return Visibility null
. Visibility.Collapsed
ReferenceToHidingVisibilityConverter Converts a reference to . If the reference is , it will return Visibility null
. Visibility.Hidden
ShortDateFormattingConverter Converts a date to a short date and back.
StringToIntConverter Converts string to an integer and back.
ViewModelToViewConverter Converts a view model to a view. Great way to locate a view based
on a view model inside xaml.
Designers
Lots of developers are using designers such as the built-in designer in Visual Studio 2010 or Expression Blend to design their xaml based
applications. Although you should , we strive to fully support all designers. use designers with lots of care
Since Catel 1.3, it is possible to create design-time versions of a view model. This way, you can preview the or impleme UserControl DataWindow
ntations using example data. Since Silverlight does not support defining types in xaml, the way that the design time works is a bit different.
WPF
Silverlight & Windows Phone
WPF
To create design-time support for a data window, use the following steps:
1.Create a design time view model. Normally, this can easily be achieved by deriving a new class from the actual view-model and inject the
model. Below is an example of a design time version of a person view model:
/// <summary>
/// Design time version of the <see cref="PersonViewModel"/>.
/// </summary>
public class DesignPersonViewModel : PersonViewModel
{
/// <summary>
/// Initializes a new instance of the <see cref="DesignPersonViewModel"/> class.
/// </summary>
public DesignPersonViewModel()
: base(new Person { FirstName = "Geert", MiddleName = "van", LastName =
"Horrik", Gender = Gender.Male })
{
}
}
2.Define the type of the design time view model.
d:DataContext="{d:DesignInstance ViewModels:DesignPersonViewModel}"
If you want it to actually demo data (instead of allowing to configure bindings), use : show IsDesignTimeCreatable
d:DataContext="{d:DesignInstance ViewModels:DesignPersonViewModel,
IsDesignTimeCreatable=True}"
Full DataWindow declaration:
<catel:DataWindow x:Class="Catel.Examples.PersonApplication.UI.Windows.PersonWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:catel="http://catel.codeplex.com"

xmlns:ViewModels="clr-namespace:Catel.Examples.PersonApplication.ViewModels"

xmlns:Converters="clr-namespace:Catel.Examples.PersonApplication.Data.Converters"

xmlns:Models="clr-namespace:Catel.Examples.Models;assembly=Catel.Examples.Models"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance ViewModels:DesignPersonViewModel,
IsDesignTimeCreatable=True}">
3. Example of design time data support:
Silverlight & Windows Phone
To create design-time support for a data window, use the following steps:
1.Create a design time view model. Normally, this can easily be achieved by deriving a new class from the actual view-model and inject the
model. Below is an example of a design time version of a person view model:
/// <summary>
/// Design time version of the <see cref="PersonViewModel"/>.
/// </summary>
public class DesignPersonViewModel : PersonViewModel
{
/// <summary>
/// Initializes a new instance of the <see cref="DesignPersonViewModel"/> class.
/// </summary>
public DesignPersonViewModel()
: base(new Person { FirstName = "Geert", MiddleName = "van", LastName =
"Horrik", Gender = Gender.Male })
{
}
}
2.Define the type of the design time view model.
d:DataContext="{d:DesignInstance ViewModels:DesignPersonViewModel}"
If you want it to actually demo data (instead of allowing to configure bindings), use : show IsDesignTimeCreatable
d:DataContext="{d:DesignInstance ViewModels:DesignPersonViewModel,
IsDesignTimeCreatable=True}"
Full DataWindow declaration:
Although the is not available in Windows Phone, it still shows how to add design time support DataWindow
<catel:DataWindow x:Class="Catel.Examples.Silverlight.UI.Windows.PersonWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:catel="http://catel.codeplex.com"

xmlns:ViewModels="clr-namespace:Catel.Examples.PersonApplication.ViewModels"

xmlns:Converters="clr-namespace:Catel.Examples.Silverlight.Data.Converters"

xmlns:ExampleWindows="clr-namespace:Catel.Examples.Silverlight.Views"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance ViewModels:DesignPersonViewModel,
IsDesignTimeCreatable=True}">
3.Example of design time data support:
Handling application initialization parameters
Sometimes you need enable or disable some application options as the outcome / result of some initialization parameters.Typically this work is
done at the application main entry point or in a notification such as start event receiving this arguments.But its pretty dirt do all this work at the
application start. May that some application modules are actually unloaded and you dont have actually a way to disable such option or the same
argument have a different meaning cross modules.
The fact is that with Catel, you can delay the processing of such initialization parameters using the and make the right StartUpInfoProvider
interpretation of any parameter at any application point.
Using the StartUpInfoProvider
Now Catel comes with . This class provides the access to the initialization parameters of the application. Basically if you are in StartUpInfoProvider
building a NET application you can access to the command line arguments array or if you are building a Silverlight application you can access to
the initialization parameter dictionary.
The interface of this service is defined below:
/// <summary>
/// The IStartUpInfoProvider interface.
/// </summary>
public interface IStartUpInfoProvider
{
#if SILVERLIGHT
/// <summary>
/// Gets the silverlight application initialization parameters.
/// </summary>
IDictionary<string, string> InitParms { get; }
#endif
#if NET
/// <summary>
/// Gets the application command line argument.
/// </summary>
string[] Arguments { get; }
#endif
}
Advantages of the StartUpInfoProvider
Think that you want to test or debug an application that require analyses the initialization parameters to work. Typically you have options to modify
this argument in a configuration windows of the visual studio or in the test page of the Silverlight application.
By default, there no easy way to mock or fake the initialization parameters for an application. Think about it:
Process.GetCurrentProcess().StartInfo.Arguments
or
Application.Current.Host.InitParams
Such thing are actually unmockable.But now, thanks to Catel, you can do it registering fakes or mock instances into the service locator. Just like
this:
var startUpInfoProviderMock = new Moq<IStartUpInfoProvider>();
....
ServiceLocator.Default.RegisterInstance<IStartUpInfoProvider>(startUpInfoProviderMock.
Object);
Locators and naming conventions
Catel contains several "locators". These locators are services that allow a developer to resolve types, such as view models, based on another
type.
ViewModelLocator
ViewLocator
We are evaluating the way to automatically map the command line array into a meaning full strong typed options and switches map or
dictionary to direct access to command line options
UrlLocator
Naming conventions
ViewModelLocator
Starting with Catel 3.0, there are several ways to hook up a view model to the view. When a view is constructed, an MVVM behavior is added to
the view. Thanks to these MVVM behaviors, it is possible to use exactly the same logic on 3rd party controls.
Resolving by GetViewModelType() method
The first thing the view does is call the virtual method. This method returns null by default, but it is possible to override this. GetViewModelType
For example, to let a view know what view model it should use, the following code can be used:
public class MyView : Catel.Windows.Controls.UserControl
{
protected override Type GetViewModelType()
{
return typeof(MyCustomViewModel);
}
}
Using this way, the view will use the as a view model. MyCustomViewModel
Resolving by naming convention
If the method returns (which is the default behavior), the view will resolve the from the GetViewModelType null IViewModelLocator ServiceLocator
. Then it will use the method to resolve the view model based on the type of the view. ResolveViewModel
For example, the following view:
Catel.Examples.Views.MyView
will be resolved as:
Catel.Examples.ViewModels.MyViewModel
Manually resolving a view model using naming convention
To manually resolve a view model using naming convention, use the following code:
var viewModelLocator = ServiceLocator.Instance.ResolveType<IViewModelLocator>();
var viewModelType = viewModelLocator.ResolveViewModel(typeof(MyView));
Customizing naming conventions
By default, the uses the following naming conventions to resolve view models: IViewModelLocator
[UP].ViewModels.[VW]ViewModel
[UP].ViewModels.[VW]ControlViewModel
[UP].ViewModels.[VW]WindowViewModel
[UP].ViewModels.[VW]PageViewModel
[AS].ViewModels.[VW]ViewModel
[AS].ViewModels.[VW]ControlViewModel
[AS].ViewModels.[VW]WindowViewModel
Note that the while using the conventions, magic words such as "View", "Control", "UserControl", "Window" and "Page" will be stripped
from the view name while locating the view model type
[AS].ViewModels.[VW]PageViewModel
However, it is possible to add or remove new naming conventions to support your own naming convention. For example, to add a new naming
convention for a different assembly, use this code:
var viewModelLocator = ServiceLocator.Instance.ResolveType<IViewModelLocator>();
viewModelLocator.NamingConventions.Add("MyCustomAssembly.ViewModels.[VW]ViewModel");
Registering custom view models
Sometimes, a class doesn't follow a naming convention (for whatever reason possible). In such a case, it is possible to register a mapping
manually using the following code:
var viewModelLocator = ServiceLocator.Instance.ResolveType<IViewModelLocator>();
viewModelLocator.Register(typeof(MyViewNotFollowingNamingConvention),
typeof(MyViewModel));
Using a custom ViewModelLocator
If you want to have total freedom to determine which view model is provided per view (maybe there are other services that have an impact on
this), it is possible to create a custom implementation. Then the only thing to do is to register it using the following code: IViewModelLocator
ServiceLocator.Default.Register<IViewModelLocator, MyViewModelLocator>();
Using a generic implementation of the view
Last but not least, it is still possible to use the "old-fashioned" way by using the generic view bases. These classes directly derive from the
non-generic views and return the generic type definition of the view model using the method. GetViewModelType
ViewLocator
The class is responsible for resolving the right views for a view model. Before Catel 3.0, the was responsible for IViewLocator IUIVisualizerService
resolving the view, but this responsibility is now taken over by the . The internally uses the to IViewLocator UIVisualizerService IViewLocator
resolve the views.
Resolving by naming convention
It is possible to resolve views using the . Then you can use the method to resolve the view based on the type of the IViewLocator ResolveView
view model.
For example, the following view model:
Catel.Examples.ViewModels.MyViewModel
will be resolved as:
Catel.Examples.Views.MyView
Manually resolving a view using naming convention
For more information about naming conventions, see Naming conventions
To manually resolve a view using naming convention, use the following code:
var viewLocator = ServiceLocator.Instance.ResolveType<IViewLocator>();
var viewType = viewLocator.ResolveView(typeof(MyViewModel));
Customizing naming conventions
By default, the IViewLocator uses the following naming conventions to resolve views:
[UP].Views.[VM]
[UP].Views.[VM]View
[UP].Views.[VM]Control
[UP].Views.[VM]Window
[UP].Views.[VM]Page
[UP].Controls.[VM]
[UP].Controls.[VM]Control
[UP].Pages.[VM]
[UP].Pages.[VM]Page
[UP].Windows.[VM]
[UP].Windows.[VM]Window
[AS].Views.[VM]
[AS].Views.[VM]View
[AS].Views.[VM]Control
[AS].Views.[VM]Page
[AS].Views.[VM]Window
[AS].Controls.[VM]
[AS].Controls.[VM]Control
[AS].Pages.[VM]
[AS].Pages.[VM]Page
[AS].Windows.[VM]
[AS].Windows.[VM]Window
[AS].UI.Views.[VM]
[AS].UI.Views.[VM]View
[AS].UI.Views.[VM]Control
[AS].UI.Views.[VM]Page
[AS].UI.Views.[VM]Window
[AS].UI.Controls.[VM]
[AS].UI.Controls.[VM]Control
[AS].UI.Pages.[VM]
[AS].UI.Pages.[VM]Page
[AS].UI.Windows.[VM]
[AS].UI.Windows.[VM]Window

However, it is possible to add or remove new naming conventions to support your own naming convention. For example, to add a new naming
convention for a different assembly, use this code:
var viewLocator = ServiceLocator.Instance.ResolveType<IViewLocator>();
viewLocator.NamingConventions.Add("MyCustomAssembly.Views.[VM]View");
Registering custom views
Sometimes, a class doesn't follow a naming convention (for whatever reason possible). In such a case, it is possible to register a mapping
manually using the following code:
var viewLocator = ServiceLocator.Instance.ResolveType<IViewLocator>();
viewLocator.Register(typeof(MyViewModelNotFollowingNamingConvention), typeof(MyView));
For more information about naming conventions, see Naming conventions
Using a custom ViewLocator
If you want to have total freedom to determine which view is provided per view model (maybe there are other services that have an impact on
this), it is possible to create a custom implementation. Then the only thing to do is to register it using the following code: IViewLocator
ServiceLocator.Default.Register<IViewLocator, MyViewLocator>();
UrlLocator
The class is responsible for resolving the right urls for the xaml views for a view model in navigation based applications. Before Catel IUrlLocator
3.0, the was responsible for resolving the url, but this responsibility is now taken over by the . The INavigationService IUrlLocator NavigationServic
internally uses the to resolve the views. e IUrlLocator
Resolving by naming convention
It is possible to resolve views using the . Then you can use the method to resolve the url based on the type of the view IUrlLocator ResolveUrl
model.
For example, the following view model:
Catel.Examples.ViewModels.MyViewModel
will be resolved as:
/Views/MyPage.xaml
Manually resolving a naming convention
To manually resolve a naming convention, use the following code:
var urlLocator = ServiceLocator.Instance.ResolveType<IUrlLocator>();
var url = viewLocator.ResolveUrl(typeof(MyViewModel));
Customizing naming conventions
By default, the uses the following naming conventions to resolve urls: IUrlLocator
/Views/[VM].xaml
/Views/[VM]View.xaml
/Views/[VM]Control.xaml
/Views/[VM]Page.xaml
/Views/[VM]Window.xaml
/Controls/[VM].xaml
/Controls/[VM]Control.xaml
/Pages/[VM].xaml
/Pages/[VM]Page.xaml
/Windows/[VM].xaml
/Windows/[VM]Window.xaml
/UI.Views/[VM].xaml
/UI.Views/[VM]View.xaml
/UI.Views/[VM]Control.xaml
/UI.Views/[VM]Page.xaml
/UI.Views/[VM]Window.xaml
Note that the checks whether the resource actually exists. If the resource does not exists, it will not be able to resolve a view UrlLocator
/UI.Controls/[VM].xaml
/UI.Controls/[VM]Control.xaml
/UI.Pages/[VM].xaml
/UI.Pages/[VM]Page.xaml
/UI.Windows/[VM].xaml
/UI.Windows/[VM]Window.xaml
However, it is possible to add or remove new naming conventions to support your own naming convention. For example, to add a new naming
convention for a different assembly, use this code:
var urlLocator = ServiceLocator.Instance.ResolveType<IUrlLocator>();
urlLocator.NamingConventions.Add("/MyPages/[VM]Page.xaml");
Registering custom urls
Sometimes, a class doesn't follow a naming convention (for whatever reason possible). In such a case, it is possible to register a mapping
manually using the following code:
var urlLocator = ServiceLocator.Instance.ResolveType<IUrlLocator>();
urlLocator.Register(typeof(MyViewModelNotFollowingNamingConvention),
"/MyVerySpecialUrl.xaml");
Using a custom UrlLocator
If you want to have total freedom to determine which url is provided per view model (maybe there are other services that have an impact on this),
it is possible to create a custom implementation. Then the only thing to do is to register it using the following code: IUrlLocator
ServiceLocator.Default.Register<IUrlLocator, MyUrlLocator>();
Naming conventions
Some services in Catel support naming conventions. For example, the and allow naming conventions to prevent IViewLocator IViewModelLocator
a user from having to register all views and view models. Internally, the naming conventions are resolved using the helper NamingConvention
class. This part of the documentation explains the possible constants in naming conventions.
[AS] constant
The [AS] constant will be replaced by the assembly name. For example, the following naming convention:
[AS].Views
in assembly will be resolved as: Catel.Examples
Catel.Examples.Views
[VM] constant
The [VM] constant will be replaced by the name of the view model without the postfix. For example, the following naming convention: ViewModel
For more information about naming conventions, see Naming conventions
[AS].Views.[VM]View
in assembly and for type will be resolved as: Catel.Examples Catel.Examples.ViewModels.MyViewModel
Catel.Examples.Views.MyView
[VW] constant
The [VW] constant will be replaced by the name of the view without the , , or postfixes. For example, the following View Control Page Window
naming convention:
[AS].ViewModels.[VW]ViewModel
in assembly and for type will be resolved as: Catel.Examples Catel.Examples.Views.MyView
Catel.Examples.ViewModels.MyViewModel
[UP] constant
Sometimes it is not possible to use the [AS] constant because the assembly name is not used in the namespace. For example, for an application
called where the client assembly is , the root namespace will still be . Therefore, it is PersonApplication PersonApplication.Client PersonApplication
recommend to use the [UP] constant for this situation.
The [UP] constant will move the namespaces up by one step. It automatically detects the right separator (\ (backslash), / (slash), . (dot) and |
(pipe) are supported).
The following naming convention:
[UP].Views.[VM]View
for type will be resolved as: Catel.Examples.ViewModels.MyViewModel
Catel.Examples.Views.MyView
Services
Catel offers lots of out-of-the-box services and implementations. Services can be used to separate the logic of external functionality in a service.
The advantages of this technique are:
Separation of Concerns
Unit testing (mocking interfaces is easy)
All services provided by Catel have both a unit test version and a real (or production version). For example, the has a test IMessageService
implementation that does not show a message box, but checks the result only.
AccelerometerService
CameraService
CompassService
GyroscopeService
LocationService
MessageService
NavigationService
OpenFileService
PleaseWaitService
ProcessService
SaveFileService
SchedulerService
SelectDirectoryService
SplashScreenService
UIVisualizerService
VibrateService
ViewExportService
AccelerometerService
The allows a developer to access the accelerometer of a Windows Phone device. IAccelerometerService
Platform info
Check if the sensor is supported by the device
Starting the service
Stopping the service
Platform info
Framework Supported
WPF
Silverlight 5
Windows Phone 8.0
Windows Phone 8.1
Windows RT 8.0
Windows RT 8.1
Test/emulation service
Check if the sensor is supported by the device
It is important to check whether the sensor is actually supported by the device. This can be done using the following code:
var dependencyResolver = this.GetDependencyResolver();
var accelerometerService = dependencyResolver.Resolve<IAccelerometerService>();
if (accelerometerService.IsSupported)
{
// Sensor is supported
}
Starting the service
When a service is started, the service will start raising the event as soon as new values come in from the sensor. To start CurrentValueChanged
the service, use the following code:
var dependencyResolver = this.GetDependencyResolver();
var accelerometerService = dependencyResolver.Resolve<IAccelerometerService>();
accelerometerService.CurrentValueChanged += OnAccelerometerValueChanged;
accelerometerService.Start();
Stopping the service
It is important that the service must be started and stopped to retrieve values
It is important to stop the service when it is no longer needed by the application. To stop the service, use the following code:
var dependencyResolver = this.GetDependencyResolver();
var accelerometerService = dependencyResolver.Resolve<IAccelerometerService>();
accelerometerService.CurrentValueChanged -= OnAccelerometerValueChanged;
accelerometerService.Stop();
CameraService
The allows a developer to use the class in an MVVM manner. ICameraService PhotoCamera
Platform info
Starting and stopping the service
Capturing images
Showing a video of camera in a view
Instantiating the test implementation
Customizing camera settings for testing
Platform info
Framework Supported
WPF
Silverlight 5
Windows Phone 8.0
Windows Phone 8.1
Windows RT 8.0
Windows RT 8.1
Test/emulation service
Starting and stopping the service
The documentation continuously states that the camera object must be created and disposed properly. In the service, this is PhotoCamera
encapsulated by the and methods. To start the service, use the code below: Start Stop
var dependencyResolver = this.GetDependencyResolver();
var cameraService = dependencyResolver.Resolve<ICameraService>();
cameraService.CaptureThumbnailAvailable += OnCameraServiceCaptureThumbnailAvailable;
cameraService.CaptureImageAvailable += OnCameraServiceCaptureImageAvailable;
cameraService.Start();
To stop the service, use the code below: (note: the method on a view model is feature of Catel): Close
It is important that the service must be started and stopped to retrieve values
There is also an article available about this service: WP7 Mango and Unit Testing the Camera
protected override void Close()
{
var dependencyResolver = this.GetDependencyResolver();
var cameraService = dependencyResolver.Resolve<ICameraService>();
cameraService.Stop();
cameraService.CaptureThumbnailAvailable -=
OnCameraServiceCaptureThumbnailAvailable;
cameraService.CaptureImageAvailable -= OnCameraServiceCaptureImageAvailable;
}
Capturing images
To capture images, several things must be done. The first action to accomplish is to subscribe to the eve ICameraService.CaptureImageAvailable
nt. The next step is to invoke the method like shown below: CaptureImage
CameraService.CaptureImage();
The last part is very important. You will need to read the image stream from the event: CaptureImageAvailable
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(e.ImageStream);
Showing a video of camera in a view
To show a preview of the camera input on the phone, first subscribe to the event. Next step is ICameraService.CaptureThumbnailImageAvailable
to create a property on the view model:
/// <summary>
/// Gets or sets the current photo.
/// </summary>
public BitmapImage CurrentPhoto
{
get { return GetValue<BitmapImage>(CurrentPhotoProperty); }
set { SetValue(CurrentPhotoProperty, value); }
}
/// <summary>
/// Register the CurrentPhoto property so it is known in the class.
/// </summary>
public static readonly PropertyData CurrentPhotoProperty =
RegisterProperty("CurrentPhoto", typeof(BitmapImage));
This property definition is a Catel property, but if you prefer using a different MVVM framework or your own property definition style, you are free
to do that as well.
In the view, use the Image control to show the current photo:
<Image Grid.Row="0" Source="{Binding CurrentPhoto}" />
Last but not least, we need to update the property when a new thumbnail is available. CurrentPhoto
private void OnCameraServiceCaptureThumbnailAvailable(object sender,
ContentReadyEventArgs e)
{
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(e.ImageStream);
CurrentPhoto = bitmap;
}
Instantiating the test implementation
The test implementation of the needs to be instantiated with an image. The service will use this image to create an animation. ICameraService
The animation that will be applied is the image scrolling to the right pixel by pixel.
To instantiate the test service, add an image to the Windows Phone project and set its build action to Resource. Then instantiate the service like
in the code below:
var testImage = new BitmapImage();
var streamResourceInfo = Application.GetResourceStream(new
Uri("/MyAssembly;component/Resources/Images/MyImage.png",
UriKind.RelativeOrAbsolute));
testImage.CreateOptions = BitmapCreateOptions.None;
testImage.SetSource(streamResourceInfo.Stream);
_testCameraService = new CameraService(testImage);
serviceLocator.RegisterInstance<ICameraService>(_testCameraService);
By default, the will generate a new thumbnail image every 50 milliseconds. It is possible to customize this with a constructor ICameraService
overload.
Customizing camera settings for testing
Sometimes it is required to test different resolutions. One way to do this is to buy all available Windows Phone devices and test the software on all
the cameras. An easier way is to use the and customize the camera options to test how the application responds to the different ICameraService
settings.
The settings are stored in the class. This class allows customizing all the properties normally found on the CameraServiceTestData PhotoCamera
class. For example, to only allow the primary camera (because front facing cameras are not supported by all devices), use the following code:
var cameraTestSettings = new CameraServiceTestData();
cameraTestSettings.SupportedCameraTypes = CameraType.Primary;
cameraService.UpdateTestData(cameraTestSettings);
It is also possible to change the thumbnail and final resolution of the images:
var cameraTestSettings = new CameraServiceTestData();
cameraTestSettings.PreviewResolution = new Size(400, 800);
cameraTestSettings.Resolution = new Size(1200, 2400);
cameraService.UpdateTestData(cameraTestSettings);
CompassService
The allows a developer to access the compass of a Windows Phone device. ICompassService
Platform info
Check if the sensor is supported by the device
Starting the service
Stopping the service
Platform info
Framework Supported
WPF
Silverlight 5
Windows Phone 8.0
Windows Phone 8.1
Windows RT 8.0
Windows RT 8.1
Test/emulation service
Check if the sensor is supported by the device
It is important to check whether the sensor is actually supported by the device. This can be done using the following code:
var dependencyResolver = this.GetDependencyResolver();
var compassService = dependencyResolver.Resolve<ICompassService>();
if (compassService.IsSupported)
{
// Sensor is supported
}
Starting the service
When a service is started, the service will start raising the event as soon as new values come in from the sensor. To start CurrentValueChanged
the service, use the following code:
var dependencyResolver = this.GetDependencyResolver();
var compassService = dependencyResolver.Resolve<ICompassService>();
compassService.CurrentValueChanged += OnCompassValueChanged;
compassService.Start();
Stopping the service
It is important to stop the service when it is no longer needed by the application. To stop the service, use the following code:
var dependencyResolver = this.GetDependencyResolver();
var compassService = dependencyResolver.Resolve<ICompassService>();
compassService.CurrentValueChanged -= OnCompassValueChanged;
compassService.Stop();
Note that the Compass service is available as separate assembly to make sure does also work on older devices without a Catel.MVVM
Compass
It is important that the service must be started and stopped to retrieve values
GyroscopeService
The allows a developer to access the gyroscope of a Windows Phone device. IGyroscopeService
Platform info
Check if the sensor is supported by the device
Starting the service
Stopping the service
Platform info
Framework Supported
WPF
Silverlight 5
Windows Phone 8.0
Windows Phone 8.1
Windows RT 8.0
Windows RT 8.1
Test/emulation service
Check if the sensor is supported by the device
It is important to check whether the sensor is actually supported by the device. This can be done using the following code:
var dependencyResolver = this.GetDependencyResolver();
var gyroscopeService = dependencyResolver.Resolve<IGyroscopeService>();
if (gyroscopeService.IsSupported)
{
// Sensor is supported
}
Starting the service
When a service is started, the service will start raising the event as soon as new values come in from the sensor. To start CurrentValueChanged
the service, use the following code:
var dependencyResolver = this.GetDependencyResolver();
var gyroscopeService = dependencyResolver.Resolve<IGyroscopeService>();
gyroscopeService.CurrentValueChanged += OnGyroscopeValueChanged;
gyroscopeService.Start();
Stopping the service
It is important to stop the service when it is no longer needed by the application. To stop the service, use the following code:
Note that the Gyroscope service is available as separate assembly to make sure does also work on older devices without Catel.MVVM
a Gyroscope
It is important that the service must be started and stopped to retrieve values
var dependencyResolver = this.GetDependencyResolver();
var gyroscopeService = dependencyResolver.Resolve<IGyroscopeService>();
gyroscopeService.CurrentValueChanged -= OnGyroscopeValueChanged;
gyroscopeService.Stop();
LocationService
The allows a developer to use GPS devices inside a view model. ILocationService
Platform info
Starting the service
Stopping the service
Emulating GPS without device
Platform info
Framework Supported
WPF
Silverlight 5
Windows Phone 8.0
Windows Phone 8.1
Windows RT 8.0
Windows RT 8.1
Test/emulation service
Starting the service
The GPS service needs to be started and stopped. To start the GPS service, use the following code:
var dependencyResolver = this.GetDependencyResolver();
var locationService = dependencyResolver.Resolve<ILocationService>();
locationService.LocationChanged += OnCurrentLocationChanged;
locationService.Start();
The service will raise the event when a new location becomes available. LocationChanged
Stopping the service
It is required to stop the service when it is no longer needed. The service can be stopped using the following code:
var dependencyResolver = this.GetDependencyResolver();
var locationService = dependencyResolver.Resolve<ILocationService>();
locationService.LocationChanged -= OnCurrentLocationChanged;
locationService.Stop();
Emulating GPS without device
It is important that the service must be started and stopped to retrieve values
It is possible to emulate GPS without actually owning a Windows Phone 7 or emulate data in the emulator. To accomplish this, it is required to use
the class. This class can be used in the following way: Catel.MVVM.Services.Test.LocationService
var dependencyResolver = this.GetDependencyResolver();
Test.LocationService service =
(Test.LocationService)dependencyResolver.Resolve<ILocationService>();
// Queue the next location (and then wait 5 seconds)
var locationTestData = new LocationTestData(new Location(100d, 100d), new TimeSpan(0,
0, 0, 5)));
service.ExpectedLocations.Add(locationTestData);
// Go to the next location manually
service.ProceedToNextLocation();
It is also possible to enqueue lots of coordinates with a time span and emulate a path.
MessageService
The allows a developer to show message boxes from a view model. IMessageService
Platform info
Screenshot
Showing a message
Showing an error
Requesting confirmation
Asynchronous confirmation
Platform info
Framework Supported
WPF
Silverlight 5
Windows Phone 8.0
Windows Phone 8.1
Windows RT 8.0
Windows RT 8.1
Test/emulation service
Screenshot
Showing a message
To show a message from a view model, use the following code:
var dependencyResolver = this.GetDependencyResolver();
var messageService = dependencyResolver.Resolve<IMessageService>();
messageService.Show("My first message via the service");
Showing an error
Showing a warning or error is very easy. Use the following code:
var dependencyResolver = this.GetDependencyResolver();
var messageService = dependencyResolver.Resolve<IMessageService>();
messageService.ShowError("Whoops, something went wrong");
Requesting confirmation
It is also possible to request confirmation from the user. The number of possibilities depends on WPF, Silverlight or Windows Phone is used (for
example, not all platforms support ). YesNo
The following code must be used to request confirmation:
var dependencyResolver = this.GetDependencyResolver();
var messageService = dependencyResolver.Resolve<IMessageService>();
if (messageService.Show("Are you sure you want to do this?", "Are you sure?",
MessageButton.YesNo) == MessageResult.Yes)
{
// Do it!
}
Asynchronous confirmation
Sometimes you don't want to use regular message boxes, and in Silverlight this means that your call has to be asynchronous. The
implementation is very simple:
var dependencyResolver = this.GetDependencyResolver();
var messageService = dependencyResolver.Resolve<IMessageService>();
messageService.Show("Are you sure you want to do this?", "Are you sure?",
MessageButton.YesNo, OnMessageServiceComplete);
There are two possible callbacks, one with a result of type or one without a result of type Action. Func<MessageResult>
NavigationService
The allows a developer to navigate to other pages inside an application using view models only. INavigationService
All pages will have to be registered manually or following the right naming convention.
Platform info
Closing an application
Preventing an application to be closed
Navigating to a new view
Navigating with parameters
Navigating back and forward
Navigating to a custom Uri
Registering custom views
Using naming conventions to find pages
For WPF and Silverlight, the pages must inherit from . For WP7, the pages must inherit from . In WPF, the Page PhoneApplicationPage
Platform info
Framework Supported
WPF
Silverlight 5
Windows Phone 8.0
Windows Phone 8.1
Windows RT 8.0
Windows RT 8.1
Test/emulation service
Closing an application
It is possible to close an application using the following code:
var dependencyResolver = this.GetDependencyResolver();
var navigationService = dependencyResolver.Resolve<INavigationService>();
navigationService.CloseApplication();
Preventing an application to be closed
To prevent an application to be closed, one can subscribe to the event: ApplicationClosing
var dependencyResolver = this.GetDependencyResolver();
var navigationService = dependencyResolver.Resolve<INavigationService>();
navigationService.ApplicationClosing += (sender, e)
=>
{
e.Cancel = true;
};
Navigating to a new view
To navigate to a new page, use the following code:
var dependencyResolver = this.GetDependencyResolver();
var navigationService = dependencyResolver.Resolve<INavigationService>();
navigationService.Navigate<EmployeeViewModel>();
Navigating with parameters
It is very easy to navigate to a new page with parameters. Use the following code:
parameters are of type , in Silverlight and WP7, the arguments are of type . Dictionary<string, object> Dictionary<string, string>
var parameters = new Dictionary<string, object>();
parameters.Add("id", employee.EmployeeID);

var dependencyResolver = this.GetDependencyResolver();
var navigationService = dependencyResolver.Resolve<INavigationService>();
navigationService.Navigate<EmployeeViewModel>(parameters);
To read the navigation parameters in the receiving view model, use the method. OnNavigationCompleted
Navigating back and forward
The service also supports navigating back and forward:
var dependencyResolver = this.GetDependencyResolver();
var navigationService = dependencyResolver.Resolve<INavigationService>();
navigationService.GoBack(); // navigates to the previous page, obviously
navigationService.GoForward(); // navigates to the next page, obviously
Navigating to a custom Uri
To navigate to a custom uri without a view model type, use the following code. Of course it's also possible to pass parameters using the right
method overload.
var dependencyResolver = this.GetDependencyResolver();
var navigationService = dependencyResolver.Resolve<INavigationService>();
navigationService.Navigate("/UI/Pages/EmployeePage.xaml");
Registering custom views
To register custom views, use the following code:
var dependencyResolver = this.GetDependencyResolver();
var navigationService = dependencyResolver.Resolve<INavigationService>();
navigationService.Register(typeof(EmployeeViewModel), typeof(EmployeeDetailsPage));
Using naming conventions to find pages
If you use a consistent naming convention for views, it is possible to apply this naming convention to the service. This saves a lot of custom
registration. When a page is not registered, the method will try to find the view using the naming convention. Show
To add a naming convention, use the following code:
var dependencyResolver = this.GetDependencyResolver();
var navigationService = dependencyResolver.Resolve<INavigationService>();
navigationService.NamingConventions.Add(string.Format("/Views/My{0}View",
NamingConvention.ViewModelName));
The above naming convention will use the following combination:
Input: MyAssembly.UI.ViewModels.EmployeeViewModel
Output: MyAssembly.UI.Windows.EmployeeWindow
By default, the following naming conventions will be used:
/Views/[VM].xaml
/Views/[VM]View.xaml
/Views/[VM]Control.xaml
/Views/[VM]Page.xaml
/Views/[VM]Window.xaml
/Controls/[VM].xaml
/Controls/[VM]Control.xaml
/Pages/[VM].xaml
/Pages/[VM]Page.xaml
/Windows/[VM].xaml
/Windows/[VM]Window.xaml
/UI/Views/[VM].xaml
/UI/Views/[VM]View.xaml
/UI/Views/[VM]Control.xaml
/UI/Views/[VM]Page.xaml
/UI/Views/[VM]Window.xaml
/UI/Controls/[VM].xaml
/UI/Controls/[VM]Control.xaml
/UI/Pages/[VM].xaml
/UI/Pages/[VM]Page.xaml
/UI/Windows/[VM].xaml
/UI/Windows/[VM]Window.xaml

OpenFileService
The allows a developer to let the user choose a file from inside a view model. IOpenFileService
Platform info
Opening a file
Platform info
Framework Supported
WPF
Silverlight 5
Windows Phone 8.0
Windows Phone 8.1
Windows RT 8.0
Windows RT 8.1
Test/emulation service
Opening a file
To open a file, it is required to set the right properties of the service and then make a call to the method: DetermineFile
var dependencyResolver = this.GetDependencyResolver();
var openFileService = dependencyResolver.Resolve<IOpenFileService>();
openFileService.Filter = "All files|*.*";
if (openFileService.DetermineFile())
{
// User selected a file
}
PleaseWaitService
The allows a developer to show a please wait message (a.k.a. busy indicator) from a view model. IPleaseWaitService
Platform info
Screenshot
Showing
Hiding
Showing and automatically hide
Changing the status
Showing a determinate please wait window
Push/Pop
Platform info
Framework Supported
WPF
Silverlight 5
Windows Phone 8.0
Windows Phone 8.1
Windows RT 8.0
Windows RT 8.1
Test/emulation service
Screenshot
Showing
var dependencyResolver = this.GetDependencyResolver();
var pleaseWaitService = dependencyResolver.Resolve<IPleaseWaitService>();
pleaseWaitService.Show();
Hiding
var dependencyResolver = this.GetDependencyResolver();
var pleaseWaitService = dependencyResolver.Resolve<IPleaseWaitService>();
pleaseWaitService.Hide();
Showing and automatically hide
The can automatically hide itself when an action is completed. To use this feature, simply pass a delegate to the metho IPleaseWaitService Show
This is the WPF service screenshot, the exact look differs per framework
d and the service will hide the window as soon as the delegate has completed.
var dependencyResolver = this.GetDependencyResolver();
var pleaseWaitService = dependencyResolver.Resolve<IPleaseWaitService>();
pleaseWaitService.Show(() => Thread.Sleep(1500));
Changing the status
var dependencyResolver = this.GetDependencyResolver();
var pleaseWaitService = dependencyResolver.Resolve<IPleaseWaitService>();
pleaseWaitService.UpdateStatus("new status");
Showing a determinate please wait window
By default, the shows an indeterminate state (no actual progress is visible). However, both the Silverlight and WPF IPleaseWaitService
implementation of the service also implement the status that shows the progress of a long running action.
The method can be used to show the window. The argument can contain '{0}' (represents the current item) and '{1}' UpdateStatus statusFormat
(represents the total items). However, they can also be left out.
var dependencyResolver = this.GetDependencyResolver();
var pleaseWaitService = dependencyResolver.Resolve<IPleaseWaitService>();
pleaseWaitService.UpdateStatus(1, 5, "Updating item {0} of {1}");
The determinate version can be hidden via a call to or when the currentItem argument is larger than the number of totalItems. Hide
Push/Pop
Sometimes, multiple view models or multiple actions use the service. It's not possible to hide the window when the first action is completed,
because the user will still have to wait for the other actions to complete (without a please wait window). To implement this correctly, it is possible
to use the and methods. Push Pop
The method shows the window if it is not already visible and then increases an internal counter. At the start of each (asynchronous) action, Push
the developer can call the method. When the action is completed, the developer calls which will internally decrease the counter. If the Push Pop
counter hits zero (0), the window is automatically hidden.
It is possible to hide the window, even when the internal counter is not yet zero. A call to will reset the counter to zero and thus hide the Hide
window.
ProcessService
The allows a developer to run processes from inside a view model. IProcessService
Platform info
Starting a process with arguments
Starting a process with arguments and completed callback
Platform info
Framework Supported
WPF
Silverlight 5
Windows Phone 8.0
Windows Phone 8.1
Windows RT 8.0
Windows RT 8.1
Test/emulation service
Starting a process with arguments
To start a process with arguments, use the following code:
var dependencyResolver = this.GetDependencyResolver();
var processService = dependencyResolver.Resolve<IProcessService>();
processService.Start("notepad.exe", @"C:\mytextfile.txt");
Starting a process with arguments and completed callback
To start a process with arguments and receive a callback on completion, use the following code:
var dependencyResolver = this.GetDependencyResolver();
var processService = dependencyResolver.Resolve<IProcessService>();
processService.Start("notepad.exe", @"C:\mytextfile.txt", OnProcessCompleted);
SaveFileService
The allows a developer to let the user choose a file from inside a view model. ISaveFileService
Platform info
Choosing a file
Platform info
Framework Supported
WPF
Silverlight 5
Windows Phone 8.0
Windows Phone 8.1
Windows RT 8.0
Windows RT 8.1
Test/emulation service
Choosing a file
To select a file to save, it is required to set the right properties of the service and then make a call to the method: DetermineFile
var dependencyResolver = this.GetDependencyResolver();
var saveFileService = dependencyResolver.Resolve<ISaveFileService>();
saveFileService.Filter = "C# File|*.cs";
if (saveFileService.DetermineFile())
{
// User selected a file
}
SchedulerService
The allows a developer to schedule an action in the relative or absolute future. The will use the ISchedulerService SchedulerService DispatcherTi
to invoke the action. mer
Platform info
Scheduling an action in the relative future
Scheduling an action in the absolute future
Platform info
Framework Supported
WPF
Silverlight 5
Windows Phone 8.0
Windows Phone 8.1
Windows RT 8.0
Windows RT 8.1
Test/emulation service
Scheduling an action in the relative future
To schedule an action in the relative future, use the method with the overload. The code below starts the action with a delay Schedule TimeSpan
of 50 milliseconds.
var dependencyResolver = this.GetDependencyResolver();
var schedulerService = dependencyResolver.Resolve<ISchedulerService>();
schedulerService.Schedule(() => DoSomething(), new TimeSpan(0, 0, 0, 0, 50));
Scheduling an action in the absolute future
To schedule an action in the absolute future, use the method with the overload. The code below starts the action in 5 Schedule DateTime
minutes.
var dependencyResolver = this.GetDependencyResolver();
var schedulerService = dependencyResolver.Resolve<ISchedulerService>();
schedulerService.Schedule(() => DoSomething(), DateTime.Now.AddMinutes(5));
SelectDirectoryService
The allows a developer to let the user choose a directory from inside a view model. ISelectDirectoryService
Platform info
Selecting a directory
Platform info
Framework Supported
WPF
Note that the does not provide any persistence of actions and schedules. When the application is closed, all SchedulerService
schedules are lost because they are kept in memory.
Silverlight 5
Windows Phone 8.0
Windows Phone 8.1
Windows RT 8.0
Windows RT 8.1
Test/emulation service
Selecting a directory
To select a directory, it is required to set the right properties of the service and then make a call to the method: DetermineDirectory
var dependencyResolver = this.GetDependencyResolver();
var selectDirectoryService = dependencyResolver.Resolve<ISelectDirectoryService>();
if (selectDirectoryService.DetermineFile())
{
// User selected a directory
}
SplashScreenService
The allows a developer execute a batch of tasks en-queued and show the progress through a registered ISplashScreenService IPleaseWaitServi
or type, from the main entry point of the application (typically from the bootstrapper) or a view model. ce IUIVisualizerService
Platform info
Screenshot
Enqueuing tasks into the SplashScreenService batch
Committing the batch
Committing the batch asynchronously with callback
Smooth progress notification of an executing action task
Platform info
Framework Supported
WPF
Silverlight 5
Windows Phone 8.0
Windows Phone 8.1
Windows RT 8.0
Windows RT 8.1
Test/emulation service
Screenshot
Enqueuing tasks into the SplashScreenService batch
First of all is requiered resolve the instance of the registered type from the view model: ISplashScreenService
var dependencyResolver = this.GetDependencyResolver();
var splashScreenService = dependencyResolver.Resolve<ISplashScreenService>();
or from the application bootstrapper, after a previous service registration:
ServiceLocator.Instance.RegisterTypeIfNotYetRegistered<ISplashScreenService,
SplashScreenService>();
/*...*/
var splashScreenService = ServiceLocator.Instance.Resolve<ISplashScreenService>();
To en-queue tasks use the following code:
splashScreenService.Enqueue(new ActionTask("Creating the shell", OnCreateShell));
splashScreenService.Enqueue(new ActionTask("Initializing modules",
OnInitializeModules));
splashScreenService.Enqueue(new ActionTask("Starting application",
OnStartApplication));
Committing the batch
To execute the batch of en-queued tasks, and show the progress through the , use the following code: IPleaseWaitService
splashScreenService.Commit();
To execute the batch of en-queued tasks, and show the progress through the , use the following code: IUIVisualizerService
splashScreenService.Commit<MySplashScreenViewModel>();
or:
splashScreenService.Commit(typeof(MySplashScreenViewModel));
Committing the batch asynchronously with callback
To execute the batch of en-queued tasks asynchronously, and show the progress through the , use the following code: IPleaseWaitService
splashScreenService.CommitAsync(OnBatchCompleted);
To execute the batch of en-queued task asynchronously, and show the progress through the , use the following code: IUIVisualizerService
splashScreenService.CommitAsync<MySplashScreenViewModel>(OnBatchCompleted);
or:
splashScreenService.CommitAsync(OnBatchCompleted, typeof(MySplashScreenViewModel));
Smooth progress notification of an executing action task
To notify the progress of an action task smoothly, use the argument of type just like is used in the following code: ITaskProgressTracker
private void OnInitializeModules(ITaskProgressTracker tracker)
{
int registeredModulesCount = 0;
foreach (var module in ModuleCatalog.Modules)
{
tracker.UpdateStatus((int)(100.0f * (registeredModulesCount /
ModuleCatalog.Modules.Count)), string.Format("Registering module '{0}'",
module.ModuleName));
if (RegisterModule(module))
{
registeredModulesCount++;
}
}
}
UIVisualizerService
The allows a developer to show (modal) windows or dialogs without actually referencing a specific view. Internally, the IUIVisualizerService UIVisu
uses the to resolve views. alizerService ViewLocator
Platform info
Screenshot
Showing a non-modal window
Showing a modal window
Showing a window with callback
Registering a window
Using naming conventions to find windows
After committing the batch is cleared, so to execute it again you should en-queue the tasks again
The SplashScreenService is thread-safe
Platform info
Framework Supported
WPF
Silverlight 5
Windows Phone 8.0
Windows Phone 8.0
Windows RT 8.0
Windows RT 8.1
Test/emulation service
Screenshot
Showing a non-modal window
To show a non-modal window, use the following code:
var viewModel = new EmployeeViewModel();
var dependencyResolver = this.GetDependencyResolver();
var uiVisualizerService = dependencyResolver.Resolve<IUIVisualizerService>();
uiVisualizerService.Show(viewModel);
Showing a modal window
To show a modal window, use the following code:
var viewModel = new EmployeeViewModel();
var dependencyResolver = this.GetDependencyResolver();
var uiVisualizerService = dependencyResolver.Resolve<IUIVisualizerService>();
uiVisualizerService.ShowDialog(viewModel);
Showing a window with callback
To show a (modal or non-modal) window and get a callback as soon as the window is closed, use the following code:
var viewModel = new EmployeeViewModel();
var dependencyResolver = this.GetDependencyResolver();
var uiVisualizerService = dependencyResolver.Resolve<IUIVisualizerService>();
uiVisualizerService.Show(viewModel, OnWindowClosed);
Registering a window
To register a custom window which is not automatically detected via reflection, it is required to use the Register method:
var dependencyResolver = this.GetDependencyResolver();
var uiVisualizerService = dependencyResolver.Resolve<IUIVisualizerService>();
uiVisualizerService.Register(typeof(EmployeeViewModel), typeof(EmployeeView));
Using naming conventions to find windows
Please see the topic. ViewLocator
VibrateService
The allows a developer to start and stop vibration of the device via a service. IVibrateService
Platform info
Starting vibration
Stopping the vibration earlier than initially planned
Platform info
Framework Supported
WPF
Silverlight 5
Windows Phone 8.0
Windows Phone 8.1
Windows RT 8.0
Windows RT 8.1
Test/emulation service
Starting vibration
To start the vibration, use the following code (will vibrate for 250 ms). Note that the time span must be between 0 and 5 seconds.
var dependencyResolver = this.GetDependencyResolver();
var vibrateService = dependencyResolver.Resolve<IVibrateService>();
vibrateService.Start(new TimeSpan(0, 0, 0, 0, 250);
Stopping the vibration earlier than initially planned
By default, the vibration stops automatically after the specified time span has passed. However, it is possible to stop the vibration manually.
var dependencyResolver = this.GetDependencyResolver();
var vibrateService = dependencyResolver.Resolve<IVibrateService>();
vibrateService.Stop();
ViewExportService
The IViewExportServiceallows a developer to export a specific view that belongs to a view model to the clipboard, a file or a printer.
Platform info
Exporting a view
Supported export methods
Platform info
Framework Supported
WPF
Silverlight 5
Windows Phone 8.0
Windows Phone 8.1
Windows RT 8.0
Windows RT 8.1
Test/emulation service
Exporting a view
To export a view, use the following code:
var dependencyResolver = this.GetDependencyResolver();
var viewExportService = dependencyResolver.Resolve<IViewExportService>();
viewExportService.Export(myViewModel, ExportMode.File);
Supported export methods
Export method WPF Silverlight
Clipboard
File
Print
View models
The view model is a very important part in the MVVM pattern. The view model is responsible for the actual logic that ensures separation of
concerns, but also allows unit testing on the view logic (which is implemented in the view model) without actually instantiating the views.
Like almost every other MVVM framework, the base class for all View-Models is . This base class is derived from the ViewModelBase ModelBase
class explained earlier in this article, which gives the following advantages:
Dependency property a-like property registration;
Automatic change notification;
Support for field and business errors.
Because the class derives from , you can simply add field and business errors that are automatically being reflected to the UI. Writing ModelBase
View-Models has never been so easy!
Creating a basic view model
Creating a view model that watches over other view models
Creating a view model with a model
Creating a view model with a model and mappings
Mapping properties from view to view model
Nested view models
Validation in view models
Advanced view models

Creating a basic view model


This example shows how to create a view model without a model. This is useful when a UI item should simply acknowledge a step that doesn't
need to be persisted to a persistence store. The view model does include validation.
Code snippets
vm - declare a view model
vmprop - declare a property on a view model
Explanation
When implementing a simple view model without a model, only one property has to be implemented that represents the checkbox that needs to
be checked. The example view model declares a single property using the code snippet. Then, a field error is set if the user has not vmprop
agreed in the method. ValidateFields
Code
C#
/// <summary>
/// Simple view model.
/// </summary>
public class SimpleViewModel : ViewModelBase
{
/// <summary>
/// Gets the title of the view model.
/// </summary>
/// <value>The title.</value>
public override string Title { get { return "Just acknowledge"; } }

/// <summary>
/// Gets or sets whether the user has agreed to continue.
/// </summary>
public bool UserAgreedToContinue
{
get { return GetValue<bool>(UserAgreedToContinueProperty); }
set { SetValue(UserAgreedToContinueProperty, value); }
}
/// <summary>
/// Register the UserAgreedToContinue property so it is known in the class.
/// </summary>
public static readonly PropertyData UserAgreedToContinueProperty =
RegisterProperty("UserAgreedToContinue", typeof(bool));
/// <summary>
/// Validates the fields.
/// </summary>
protected override void ValidateFields(List<FieldValidationResult>
validationResults)
{
// Check if the user agrees to continue
if (!UserAgreedToContinue)
{

validationResults.Add(FieldValidationResult.CreateError(UserAgreedToContinueProperty,
"User must agree to continue");
}
}
}

XAML (assuming that the view model is set as datacontext)


<CheckBox Content="Check me to continue" IsChecked="{Binding UserAgreedToContinue,
NotifyOnValidationError=True, ValidatesOnDataErrors=True}" />
Creating a view model that watches over other view models
Most frameworks require you to set up complex message systems (messengers) or other techniques to communicate with other view models. The
downside of this approach is that once a view model is written in module X, and you are interested in the view model, the developer of module X
must take care of notifying other view models. We think this is not the responsibility of the originating view model.
If a view model is interested in the changes of another view model, its the responsibility of the view model that is interested to watch the view
model, not the other way around. To be notified of changes on other view models, the only thing you have to do is to decorate a view model with
the , like shown in the code below: InterestedInAttribute
[InterestedIn(typeof(FamilyViewModel))]
public class PersonViewModel : ViewModelBase
Then, inside the (which is interested in the changes of ), you only have to override the PersonViewModel FamilyViewModel OnViewModelProperty
method: Changed
/// <summary>
/// Called when a property has changed for a view model type
/// that the current view model is interested in. This can
/// be accomplished by decorating the view model with the <see
cref="InterestedInAttribute"/>.
/// </summary>
/// <param name="viewModel">The view model.</param>
/// <param name="propertyName">Name of the property.</param>
protected override void OnViewModelPropertyChanged(IViewModel viewModel, string
propertyName)
{
// You can now do something with the changed property
}
It is possible to be interested in multiple view models. Since the view model is passed to the method, it is very OnViewModelPropertyChanged
easy to check the type of the view model.
Code snippets
vm - declare a view model
vmprop - declare a property on a view model
Explanation
The most important thing to know is that there is a in the library. This manager keeps track of all view models that are alive. A ViewModelManager
view model automatically registers itself to the manager, and when it is closed, the view model automatically unsubscribes itself again.
By using the , it is possible to receive notifications of other view models. The defines a specific type of InterestedInAttribute InterestedInAttribute
view model the decorated view model is interested in. Then, the decorated view model will receive all the events of the live view PropertyChanged
models of that specific type. It is possible to define multiple attributes to watch several different types of view models.
Code
Watched view model
/// <summary>
/// Watched view model.
/// </summary>
public class WatchedViewModel : ViewModelBase
{
/// <summary>
/// Gets the title of the view model.
/// </summary>
/// <value>The title.</value>
public override string Title { get { return "View model being watched"; } }
/// <summary>
/// Initializes the object by setting default values.
/// </summary>
protected override void Initialize()
{
// Not required
}
}
Interested view model
/// <summary>
/// Interested view model.
/// </summary>
[InterestedIn(typeof(WatchedViewModel))]
public class InterestedViewModel : ViewModelBase
{
/// <summary>
/// Gets the title of the view model.
/// </summary>
/// <value>The title.</value>
public override string Title { get { return "View model that is interested"; } }
/// <summary>
/// Initializes the object by setting default values.
/// </summary>
protected override void Initialize()
{
// Not required
}
/// <summary>
/// Called when a property has changed for a view model type that the current view
model is interested in. This can
/// be accomplished by decorating the view model with the <see
cref="InterestedInAttribute"/>.
/// </summary>
/// <param name="viewModel">The view model.</param>
/// <param name="propertyName">Name of the property.</param>
protected override void OnViewModelPropertyChanged(IViewModel viewModel, string
propertyName)
{
// TODO: Check what property was changed
}
/// <summary>
/// Called when a command for a view model type that the current view model is
interested in has been executed. This can
/// be accomplished by decorating the view model with the <see
cref="InterestedInAttribute"/>.
/// </summary>
/// <param name="viewModel">The view model.</param>
/// <param name="command">The command that has been executed.</param>
/// <param name="commandParameter">The command parameter used during the
execution.</param>
protected override void OnViewModelCommandExecuted(IViewModel viewModel,
ICatelCommand command, object commandParameter)
{
// TODO: Check what command has been executed
}
}
Creating a view model with a model
This example shows how to create a "classical" view model without any Catel specific MVVM features such as data pass-through. Although it is
recommended to use the pass-through features, some people want to have custom validation on the view model, or want to be fully in control.
Code snippets
vm - declare a view model
vmprop - declare a property on a view model
Explanation
To be in full control, the only thing required is to create a basic view model with the code snippet. Then, the following methods should be vm
implemented:
Constructor - initialize the properties on the view model
ValidateFields - check for field errors in the view model
ValidateBusinessRules - check for business rules in the view model
Save - save the view model data to the model and then save the model
Code
C#
/// <summary>
/// Classical view model.
/// </summary>
public class ClassicalViewModel : ViewModelBase
{
#region Properties
/// <summary>
/// Gets or sets the Person.
/// </summary>
private Person Person
{
get { return GetValue<Person>(PersonProperty); }
set { SetValue(PersonProperty, value); }
}
/// <summary>
/// Register the Person property so it is known in the class.
/// </summary>
public static readonly PropertyData PersonProperty = RegisterProperty("Person",
typeof(Person));
/// <summary>
/// Gets or sets the first name.
/// </summary>
public string FirstName
{
get { return GetValue<string>(FirstNameProperty); }
set { SetValue(FirstNameProperty, value); }
}
/// <summary>
/// Register the FirstName property so it is known in the class.
/// </summary>
public static readonly PropertyData FirstNameProperty =
RegisterProperty("FirstName", typeof(string));
/// <summary>
/// Gets or sets the last name.
/// </summary>
public string LastName
{
get { return GetValue<string>(LastNameProperty); }
set { SetValue(LastNameProperty, value); }
}
/// <summary>
/// Register the LastName property so it is known in the class.
/// </summary>
public static readonly PropertyData LastNameProperty = RegisterProperty("LastName",
typeof(string));
#endregion
#region Methods
/// <summary>
/// Initializes the object by setting default values.
/// </summary>
protected override void Initialize()
{
// Get the person from (in this case) a magical context
Person = Context.CurrentPerson;

// Load the data manually to the view model


FirstName = Person.FirstName;
LastName = Person.LastName;
}
/// <summary>
/// Validates the field values of this object. Override this method to enable
/// validation of field values.
/// </summary>
/// <param name="validationResults">The validation results, add additional results
to this list.</param>
protected override void ValidateFields(List<FieldValidationResult>
validationResults)
{
if (string.IsNullOrWhiteSpace(FirstName))
{
validationResults.Add(FieldValidationResult.CreateError(FirstNameProperty,
"First name is required"));
}

if (string.IsNullOrWhiteSpace(LastName))
{
validationResults.Add(FieldValidationResult.CreateError(LastNameProperty,
"Last name is required"));
}
}
/// <summary>
/// Saves the data.
/// </summary>
/// <returns>
/// <c>true</c> if successful; otherwise <c>false</c>.
/// </returns>
protected override bool Save()
{
// Save the data manually to the model
Person.FirstName = FirstName;
Person.LastName = LastName;

// Save the model


return Person.Save();
}
#endregion
}
Creating a view model with a model and mappings
During of the use of the MVVM pattern, we noticed that lots and lots of developers have a model, and map the values of the model to all
properties of the view model. When the UI closes, the developers map all the properties back to the model. All this redundant code is not
necessary when using the view models of Catel.
In Catel, we have created attributes that allow you to define a property as a model. A model is a property that a part of the view model represents
to the user. A view model might have multiple models if it is a combination of several models.
To use the mapping features, the following attributes are very important:
ModelAttribute - declare a model in a view model
ViewModelToModelAttribute - declare a mapping from a view model property to a model property
Code snippets
vm - declare a view model
vmpropmodel - declare a property as model on a view model
vmpropviewmodeltomodel - declare a property as a pass-through property on a view model"
Explanation
Defining a model is very simple, you only have to decorate your property with the : ModelAttribute
/// <summary>
/// Gets or sets the shop.
/// </summary>
[Model]
public IShop Shop
{
get { return GetValue<IShop>(ShopProperty); }
private set { SetValue(ShopProperty, value); }
}
/// <summary>
/// Register the Shop property so it is known in the class.
/// </summary>
public static readonly PropertyData ShopProperty = RegisterProperty("Shop",
typeof(IShop));
Using the is very powerful. Basically, this is the extended functionality in the view model. If the model supports , ModelAttribute IEditableObject Be
is automatically called in the initialization of the view model. When the view model is canceled, the is called so the changes are ginEdit CancelEdit
undone.
When a model is defined, it is possible to use the , as you can see in the code below: ViewModelToModelAttribute
/// <summary>
/// Gets or sets the name of the shop.
/// </summary>
[ViewModelToModel("Shop")]
public string Name
{
get { return GetValue<string>(NameProperty); }
set { SetValue(NameProperty, value); }
}
/// <summary>
/// Register the Name property so it is known in the class.
/// </summary>
public static readonly PropertyData NameProperty = RegisterProperty("Name",
typeof(string));
The in the code example above automatically maps the view model property to the property. This ViewModelToModelAttribute Name Shop.Name
way, you dont have to manually map the values from and to the model. Another nice effect is that the view model automatically validates all
objects defined using the , and all field and business errors mapped are automatically mapped to the view model. ModelAttribute
Summarized, the model and attributes make sure no duplicate validation and no manual mappings are required. ViewModelToModel

Mapping properties from view to view model


Sometimes a view (for example, a user control) contains additional properties besides the to interact with the view model. By default, DataContext
it is hard to implement this in an MVVM sccenario, but Catel solves this issue using the attribute. ViewToViewModel
This attribute automatically keeps track of changes in both the view and the view model and this way, a control can have several properties and
still implement MVVM.
Example implementation
The example below shows how the is a dependency property on the control. It automatically maps the property to the MapCenter ViewModel.Map
property. Center
public partial class MyControl : UserControl
{
public MyControl()
{
InitializeComponent();
}

[ViewToViewModel(MappingType = ViewToViewModelMappingType.ViewModelToView)]
public GeoCoordinate MapCenter
{
get { return (GeoCoordinate) GetValue(MapCenterProperty); }
set { SetValue(MapCenterProperty, value); }
}

// Using a DependencyProperty as the backing store for MapCenter. This enables


animation, styling, binding, etc...
public static readonly DependencyProperty MapCenterProperty =
DependencyProperty.Register("MapCenter", typeof (GeoCoordinate),
typeof (MyControl), new PropertyMetadata(null, (sender, e) => ((MyControl)
sender).UpdateMapCenter()));

private void UpdateMapCenter()


{
map.SetView(ViewModel.MapCenter, ViewModel.ZoomLevel);
}

public new MainPageViewModel ViewModel


{
get { return base.ViewModel as MainPageViewModel; }
}
}
Mapping types
Catel supports the following mapping types using the enum. ViewToViewModelMappingType
Type Description
TwoWayDoNothing Two way, which means that either the view or the view model will
update the values of the other party as soon as they are updated.
When this value is used, nothing happens when the view model of
the view changes. This way, it might be possible that the values of
the view and the view model are different. The first one to update
next will update the other.
TwoWayViewWins Two way, which means that either the view or the view model will
update the values of the other party as soon as they are updated.
When this value is used, the value of the view is used when the view
model of the view is changed, and is directly transferred to the view
model value
TwoWayViewModelWins Two way, which means that either the view or the view model will
update the values of the other party as soon as they are updated.
When this value is used, the value of the view model is used when
the view model of the view is changed, and is directly transferred to
the view value.
ViewToViewModel The mapping is from the view to the view model only.
ViewModelToView The mapping is from the view model to the view only.
Nested view models
For more information on this topic, see . nested user controls
Validation in view models
Validation is very important to provide both feedback to the user, but also to make sure that no invalid data reaches the model or database. Catel
offers several ways to implement validation. All options are described in this part of the documentation.
Validation in models via mappings
Mapping via ViewModelToModelAttribute
Mapping via ExposeAttribute
Validation in view models
Validating fields
Validating business rules
Translating model validation in the view model
Validating via annotations
To validate required fields or not to validate required fields at startup
Validation in models via mappings
The best way is to put validation into a model. Most model objects nowadays implement and , the most INotifyPropertyChanged IDataErrorInfo
important classes that are required to use mappings from/to a model inside a view model.
The great advantage of mapping properties from/to models automatically using Catel is that you don't have to write lots of plumbing yourself
(getting and setting values in the model and view model). However, if the model implements and , Catel INotifyPropertyChanged IDataErrorInfo
also automatically uses the validation from the model. For example, if there is a model that checks if the and are Person FirstName LastName
entered, why rewrite this validation again in the view model?
There are two ways to use automatic mappings.
Mapping via ViewModelToModelAttribute
Mapping a model property by using the requires the definition of a model property and a separate property per ViewModelToModelAttribute
mapped property. The code below automatically maps the property. FirstName
1.
2.
/// <summary>
/// Gets or sets the person.
/// </summary>
[Model]
public Person Person
{
get { return GetValue<Person>(PersonProperty); }
private set { SetValue(PersonProperty, value); }
}
/// <summary>
/// Register the Person property so it is known in the class.
/// </summary>
public static readonly PropertyData PersonProperty = RegisterProperty("Person",
typeof(Person));
/// <summary>
/// Gets or sets the first name.
/// </summary>
[ViewModelToModel("Person")]
public string FirstName
{
get { return GetValue<string>(FirstNameProperty); }
set { SetValue(FirstNameProperty, value); }
}
/// <summary>
/// Register the FirstName property so it is known in the class.
/// </summary>
public static readonly PropertyData FirstNameProperty = RegisterProperty("FirstName",
typeof(string));
If the provides an error via the interface, it will automatically be exposed by the view model as well. Person.FirstName IDataErrorInfo
Mapping via ExposeAttribute
Mapping a property via the is even more simple, but has some disadvantages. First, let's talk about the disadvantages before ExposeAttribute
showing the code:
Catel uses the interface to implement this behavior, and the interface is only available in WPF. ICustomTypeDescriptor
The properties are not actually created, so you cannot use them inside your view model as real properties.
In other words, the is only very useful if 1) you are using WPF and 2) if the property is not used inside the view model but only ExposeAttribute
declared to protect the model from the outside world. If both of these constraints are true, then the is definitely worth taking a look ExposeAttribute
at. The usage is very simple:
/// <summary>
/// Gets or sets the person.
/// </summary>
[Model]
[Expose("FirstName")]
[Expose("MiddleName")]
[Expose("LastName")]
private Person Person
{
get { return GetValue<Person>(PersonProperty); }
set { SetValue(PersonProperty, value); }
}
/// <summary>
/// Register the Person property so it is known in the class.
/// </summary>
public static readonly PropertyData PersonProperty = RegisterProperty("Person",
typeof(Person));
Simply declare the model property and decorate it with one or multiple instances. Not only are the properties automatically ExposeAttribute
available for binding, the view model also checks for errors and automatically maps these as well.
Validation in view models
Until now, we only spoke about automatic validation for validation that was written in the model. However, sometimes it is required to write
validation inside the view model as well. One reason might be that the model is a POCO object not providing any validation. Or, sometimes there
is a logical error that has nothing to do with the model, but should be shown to the user anyway.
In such a case, Catel offers lots of possibilities to write custom validation inside the view model. Below are the possibilities:
Field warnings
Field errors
Business rule warnings
Business rule errors
The difference between a field and business rule is that a field error or warning is specific for a property. These are returned via IDataErrorInfo["pr
. A business rule is a rule that applies to multiple fields or even a whole entity. Business rule validations are returned via opertyName"] IDataErrorI
. nfo.Error
To implement validation into a view model, only two methods need to be implemented. Catel clearly separates the field validation from the
business rule validation to make it much clearer to the developer what is going on.
Validating fields
To validate fields, one should override the method. Below is an example of field validation on a view model: ValidateFields
/// <summary>
/// Validates the field values of this object. Override this method to enable
/// validation of field values.
/// </summary>
/// <param name="validationResults">The validation results, add additional results to
this list.</param>
protected override void ValidateFields(List<IFieldValidationResult> validationResults)
{
if (!string.IsNullOrEmpty(FirstName))
{
validationResults.Add(FieldValidationResult.CreateError(FirstNameProperty,
"First name cannot be empty"));
}
}
Validating business rules
To validate business rules, one should override the method. Below is an example of business rule validation on a view ValidateBusinessRules
model:
/// <summary>
/// Validates the field values of this object. Override this method to enable
/// validation of field values.
/// </summary>
/// <param name="validationResults">The validation results, add additional results to
this list.</param>
protected override void ValidateBusinessRules(List<IBusinessRuleValidationResult>
validationResults)
{
if (SomeBusinessErrorOccurs)
{
validationResults.Add(BusinessRuleValidationResult.CreateError("A business
error occurred"));
}
}
Translating model validation in the view model
Thanks to the validation system in Catel, it is very easy to implement very advanced validation features in view models. The example below
shows how to translate errors that are added to a model in the Data Access Layer or validation layer. Assume that the following pseudo code is
used to set an error on a model in the DAL:
SetFieldError("FirstName", "FirstNameRequired");
All errors that are mapped from the model to the view model automatically are available in the parameter. This way, the error validationResults
can be easily translated:
/// <summary>
/// Validates the field values of this object. Override this method to enable
/// validation of field values.
/// </summary>
/// <param name="validationResults">The validation results, add additional results to
this list.</param>
protected override void ValidateFields(List<IFieldValidationResult> validationResults)
{
foreach (var validationResult in validationResults)
{
if (validationResult.Message == "FirstNameRequired")
{
validationResult.Message = Properties.Resources.FirstNameRequired;
}
}
}
Of course this is not something you want to actually do in your view model, so youll probably have to write a helper class that translates the
validation for you. You might or might not like delaying the translation of the model errors to as close as the view, but it shows how extremely
powerful the improved validation of Catel is. And if you think a bit about it,wouldn'tit be a good idea to delay the translation from the server to the
actual client to as close as the view?
Validating via annotations
Some people like to add validation to their (view)models using annotations (attributes). Catel also supports this method, but adds additional
functionality. The idea behind it is that in the end, Catel always provides all errors of an object via the interface. This means that IDataErrorInfo
when attribute validation is used, the errors are internally registered and provided in the method. This way, all types of validation ValidateFields
that are provided by the .NET framework are gathered into one single location where they can be used by the view.
/// <summary>
/// Gets or sets the first name.
/// </summary>
[Required("This value is required")]
private string FirstName
{
get { return GetValue<string>(FirstNameProperty); }
set { SetValue(FirstNameProperty, value); }
}
/// <summary>
/// Register the FirstName property so it is known in the class.
/// </summary>
public static readonly PropertyData FirstNameProperty= RegisterProperty("FirstName",
typeof(string));
To validate required fields or not to validate required fields at startup
Catel does not validate the properties with data annotations at startup. It will only validate the data annotations when properties change or when
the view model is about to be saved. This is implemented this way to allow a developer to show required fields with an asterisk (*) instead of
errors. If a developer still wants to initially display errors, only a single call has to be made in the constructor:
Validate(true, false);
Advanced view models
This section contains advanced topics about view models.
Keeping view models alive
Exposing properties of a model automatically
Determine the view model type dynamically at runtime
Controlling the instantiation of view models
Keeping view models alive
In Catel, view models are automatically closed when the is unloaded from the visual tree. This is because there is noguaranteethat UserControl
the control will be loaded again. This works great in most of the cases, but sometimes you need more control about the lifetime of the view model.
One good example is the use of the . When a tab control contains a user control with a view model, every time a new tab is selected, TabControl
the controls on the previously selected tab are unloaded (and thus the view models are closed).
It is possible to have more control about the lifetime of view models. To keep a view model alive, even when the view is unloaded, set the CloseVi
property of the to false in the constructor of the view: ewModelOnUnloaded UserControl
CloseViewModelOnUnloaded = false;
The view model will now be re-used when the view is loaded into the visual tree again.
Exposing properties of a model automatically
Starting with Catel 2.2, a new attribute called is introduced. One of the features that already existed in Catel before is the ExposeAttribute ViewMo
. The goal of these attributes is to easily map properties from a model to the view model so as much of the plumbing delToModelAttribute
(setting/getting properties, rechecking validation, etc) is done automatically for the developer.
Using the ViewModelToModelAttribute, this is the syntax to map properties automatically:
Also see the that is available in Catel TabControl
Keep in mind that the developer is responsible for actually closing the view model
The Catel Examples repository contains an example demonstrating controlling the lifetime of view models
Note that starting with Catel 3.8, this feature is part of Catel.Fody which brings support for this feature on all platforms. More information
can be found . here
This feature is only available in WPF because Silverlight does not provide the or an equivalent feature ICustomTypeDescriptor
/// <summary>
/// Gets or sets the person.
/// </summary>
[Model]
public Person Person
{
get { return GetValue<Person>(PersonProperty); }
private set { SetValue(PersonProperty, value); }
}
/// <summary>
/// Register the Person property so it is known in the class.
/// </summary>
public static readonly PropertyData PersonProperty = RegisterProperty("Person",
typeof(Person));
/// <summary>
/// Gets or sets the first name.
/// </summary>
[ViewModelToModel("Person")]
public string FirstName
{
get { return GetValue<string>(FirstNameProperty); }
set { SetValue(FirstNameProperty, value); }
}
/// <summary>
/// Register the FirstName property so it is known in the class.
/// </summary>
public static readonly PropertyData FirstNameProperty = RegisterProperty("FirstName",
typeof(string));
However, if you only define the property just to protect your model, then why should you define the whole property? This is where the FirstName E
property comes in very handy. This attribute internally registers a new dynamic property on the view model, and then uses the xposeAttribute
same technique as the . ViewModelToModelAttribute
Below is the new way you can easily expose properties of a model and protect other properties of the model from the view:
/// <summary>
/// Gets or sets the person.
/// </summary>
[Model]
[Expose("FirstName")]
[Expose("MiddleName")]
[Expose("LastName")]
private Person Person
{
get { return GetValue<Person>(PersonProperty); }
set { SetValue(PersonProperty, value); }
}
/// <summary>
/// Register the Person property so it is known in the class.
/// </summary>
public static readonly PropertyData PersonProperty = RegisterProperty("Person",
typeof(Person));
So, this is a very cool feature that allows you to protect your model without having to re-define all the properties on the view model. Also, the
validation in the model is automatically synchronized with the view model when you use this attribute.
Determine the view model type dynamically at runtime
Starting with Catel 3.1, it is possible to determine the view model type of a view dynamically at runtime. This sounds complex, but let's bring up a
user scenario which a user came up with:
I have a shape view and a ShapeBaseViewModel. Then, I have models such as Rectangle, Circle, etc, and each model has its own view model
(RectangleViewModel, CircleViewModel, etc). How can I solve this issue using Catel?
This case proves that it should be at least possible to determine the type of the view model of a view, based on the of a view. DataContext
How to dynamically determine the view model type using a UserControl
Determining the view model dynamically when using the is extremely easy. You can override the method UserControl GetViewModelType(object)
like this:
protected override Type GetViewModelType(object dataContext)
{
if (dataContext is Rectangle)
{
return typeof (RectangleViewModel);
}
if (dataContext is Circle)
{
return typeof (CircleViewModel);
}
return null;
}
When the method returns , it will fall back on the earlier determined view model type. null
How to dynamically determine the view model using a behavior
Determining the view model dynamically when using behaviors must be done via the event like this: DetermineViewModelType
mvvmBehavior.DetermineViewModelType += (sender, e) =>
{
if (e.DataContext is Rectangle)
{
e.ViewModelType = typeof (RectangleViewModel);
}
if (e.DataContext is Circle)
{
e.ViewModelType = typeof(CircleViewModel);
}
};
There is no need to set the to because that is the default value. e.ViewModelType null
Controlling the instantiation of view models
Starting with Catel 3.1, it is possible to take control of the view model instantiation of a view dynamically at runtime. This feature can be used
when the construction of a view model is more complex than injecting the datacontext as model, or when the view model instance in a custom
Note that this feature is available on all controls an behaviors, not only for the UserControl
repository should be re-used.
How to control the view model instantiation using the IViewModelFactory
How to control the view model instantiation using a UserControl
How to control the view model instantiation using a behavior
Preventing the logic to create a view model by itself
How to control the view model instantiation using the IViewModelFactory
The is the best way to customize the instantiation of view models in Catel. This allows full control for all view models because IViewModelFactory
the factory will be used to create all view models, except when any other methods described below are used.
If customization of the view model instantiation is required, it is best the derive from the default class to be able to fall back to ViewModelFactory
the default behavior in non-special cases.
public class CustomViewModelFactory : ViewModelFactory
{
public override IViewModel CreateViewModel(Type viewModelType, object dataContext)
{
if (viewModelType == typeof(MySpecialViewModel))
{
// Use custom constructor with dependency injection
return new MySpecialViewModel(dep1, dep2, dep3, dataContext);
}
// Fall back to default behavior
return base.CreateViewModel(viewModelType, dataContext);
}
}
When a custom factory is used, it is important to register it in the ServiceLocator:
ServiceLocator.Default.RegisterType<IViewModelFactory, CustomViewModelFactory>();
How to control the view model instantiation using a UserControl
Controlling the instantiation of the view model dynamically when using the is extremely easy. You can override the UserControl GetViewModelInst
method like this: ance(object)
protected override IViewModel GetViewModelInstance(object dataContext)
{
if (dataContext is Rectangle)
{
return new RectangleViewModel((Rectangle)dataContext);
}
return null;
}
When the method returns , the logic will try to construct the view model by itself. null
How to control the view model instantiation using a behavior
Note that this feature is available on all controls an behaviors, not only for the UserControl
Note that it is best to use the for view model instantation because it is a more generic solution IViewModelFactory
Controlling the instantiation of the view model dynamically when using behaviors must be done via the event like DetermineViewModelInstance
this:
mvvmBehavior.DetermineViewModelInstance += (sender, e) =>
{
var dataContext = e.DataContext;
if (dataContext is Rectangle)
{
e.ViewModel = new RectangleViewModel((Rectangle)dataContext);
}
};
There is no need to set the to because that is the default value. e.ViewModel null
Preventing the logic to create a view model by itself
When using the behavior, it is possible to prevent the logic to instantiate a view model. In this case, it is really possible to have full control over
view model instantiation. To prevent the logic to create a view model, use this code:
mvvmBehavior.DetermineViewModelInstance += (sender, e) =>
{
var dataContext = e.DataContext;
if (dataContext is Rectangle)
{
e.ViewModel = new RectangleViewModel((Rectangle)dataContext);
}
e.DoNotCreateViewModel = true;
};
Views
Views are what the user actually sees on the screen. The views communicate with the view models. The MVVM Framework that ships with Catel
can be used on its own. However, the framework requires some conventions that you, as end-user of Catel, should not be worrying about.
Therefore, Catel ships with both a UserControl and a Window that fully support the MVVM Framework. Those can both be used as base classes
for all controls and windows developed in an application.
DataWindow
UserControl
MVVM behaviors
Validation controls
Finding the view of a view model
Using external controls
Advanced information about views
DataWindow
Introduction to the DataWindow
Using the DataWindow in MVVM
Construction of view models
Automatic validation
Customizing the buttons
Styling the DataWindow
Introduction to the DataWindow
When developing software in WPF or Silverlight, most developers always need the following three types of windows:
OK / Cancel buttons for data windows;
Note that it is best to use the for view model instantation because it is a more generic solution IViewModelFactory
1.
OK / Cancel / Apply buttons for application settings / options;
Close button on windows for action windows.
Creating these windows is just boring and the steps are always the same:
The class makes it much easier to create these basic windows, simply by specifying the mode of the . By using this window, DataWindow Window
you can concentrate on the actual implementation and you dont have to worry about the implementation of the buttons itself, which saves you
time!
Using the DataWindow in MVVM
The easiest object to use with the MVVM Framework is the class. The takes fully care of the construction of the view DataWindow DataWindow
models and the validation of the view models.
The usage of the class is very simple, once you know how to do it. First of all, you will have to specify the base class in the xaml file DataWindow
like shown below:
<catel:DataWindow x:Class="Catel.Articles._03___MVVM.Examples.DataWindow.PersonWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:catel="http://catel.codeplex.com">

<!-- Content left out for the sake of simplicity -->

</catel:DataWindow>
As you can see, one thing has changed in regard to a normal window definition:
The type definition has changed from to ; Window catel:DataWindow
The code-behind is even simpler:
/// <summary>
/// Interaction logic for PersonWindow.xaml
/// </summary>
public partial class PersonWindow : DataWindow
{
/// <summary>
/// Initializes a new instance of the <see cref="PersonWindow"/> class.
/// </summary>
/// <param name="viewModel">The view model.</param>
public PersonWindow(PersonViewModel viewModel)
: base(viewModel)
{
InitializeComponent();
}
}
The code above is everything you will need when using the MVVM Framework of Catel.
Construction of view models
There are multiple ways to construct a window with a view model. There are three options that you have to construct a view model:
Constructor with view model
This is the best option you can use. This way, it is possible to inject view models into the data window.
Constructor with model
It is possible to save a developer from creating a view model manually by accepting a model as input. Then, the data window will have to
construct the view model manually and pass it through to its base constructor.
Empty constructor
If you use an empty constructor, the developer will have to set the data context manually. This something you really should avoid. But
hey, its all up to you.
Automatic validation
The cool thing about the is that is automatically wraps the content that a developer defines into an . This DataWindow InfoBarMessageControl
way, errors and warnings are shown at the top of the window. Another feature of the is that is automatically creates a DataWindow WarningAndEr
control and sets the view model as source. This way, all the warnings of the view model are also shown in the rorValidator InfoBarMessageContro
. In other words: you dont have to do anything to implementation validation, except for actually setting the warnings and errors in your view l
model. And if the validation takes place in the model, you can use the so you dont have to worry about that either. ViewModelToModelAttribute
Customizing the buttons
It is possible to use custom buttons and still be able to use the . DataWindow
1. First, use the base constructor to specify that you want to use custom mode.
/// <summary>
/// Upload window.
/// </summary>
public class UploadWindow : DataWindow
{
public UploadWindow()
: base(DataWindowMode.Custom)
{
InitializeComponent();
}
}
The easiest way to create a new is to use item templates DataWindow
2. Add the custom buttons. This must be done before the call to . InitializeComponent
/// <summary>
/// Upload window.
/// </summary>
public class UploadWindow : DataWindow
{
public UploadWindow()
: base(DataWindowMode.Custom)
{
AddCustomButton(new DataWindowButton("Upload", "Upload"));
InitializeComponent();
}
}
Styling the DataWindow
Starting with Catel 2.4, the has its own styles. These are located in . Below is a table that contains the DataWindow DataWindow.generic.xaml
available styles and a short description.
Style key Description
DataWindowStyle The actual window style which can be used to decorate or customize
the window itself.
DataWindowButtonContainerStyle The container that is used for the buttons. This is a , so WrapPanel
the styles must match that.
DataWindowButtonStyle The style for the buttons. By default, the buttons are right aligned and
have a fixed size.
UserControl
The is a very interesting class of Catel, and fully shows the power of the MVVM Framework that ships with Catel. The user control is UserControl
able to fully integrate MVVM on a user control level and solves the nested user control problem, which is explained in detail a bit further in this
documentation.
Automatic construction without parameter
Automatic construction with parameter
Mapping properties from/to view model
Keeping view models alive
Automatic construction without parameter
It simplest thing to do is to create a view model that has an empty constructor (thus without parameters). If the is added to the visual UserControl
tree, the view model is instantly constructed and available for usage. A view model that is used inside a implementation is exactly the UserControl
same as the implementation. This way, the developers dont have to worry about whether they can currently writing a view model DataWindow
that is meant for a window or a control.
Automatic construction with parameter
A bit harder (its still very easy, dont worry), but much more powerful is the construction with a parameter. This way, a control is forced to use the
data context to create the view model. If there is no valid data context that can be used to construct the view model, no view model will be
constructed. This sounds a little abstract, but lets take a look to a more meaningful example.
Say, you want to write an application to manage company trees. The top-level of the data exists of a collection of objects (models). You Company
want to display the companies inside an , which is a very good way to represent the companies. But how are you going to display the ItemsControl
company details? You can simply create a template, but Iwouldn'trecommend that because the company representation can become very
complex (and dynamic), because it consists of objects that can have children (employees), and the children are person objects as well, Person
that can have children, etc. You might thing that this is a very simple scenario, which it actually is to make sure that all readers understand it
correctly. But, there can be a lot of complex tree scenarios. For example, for a client, I had to write a complete treatment overview of a patient,
which consists of a lot of different objects, which all have a child collection of other object types. Then you can save yourself with writing a simple
and generic data template. Below is a graphical form of the example:
Now comes the real power of in to play. For example, to show the company and its managers, one has to write an items control that UserControl
contains the companies and then a user control containing the details of the company. For the sake of simplicity, I will leave the employees out for
now. The usage might seem a bit complex, but once you get the hang of it, its actually quite simple. First of all, create a view model that has a
constructor of the model that you want to accept, in our case the class of which we will show the details: Company
/// <summary>
/// Initializes a new instance of the <see cref="CompanyViewModel"/> class.
/// </summary>
/// <param name="company">The company.</param>
public CompanyViewModel(Models.Company company)
: base()
{
// Store values
Company = company;
}
As you can see, the view model can only be constructed by passing a company model. This is quite normal, because how can we show details of
a non-existing (null) company? Now we have a view model, we can create our user control:
<catel:UserControl
x:Class="Catel.Articles._03___MVVM.Examples.UserControlWithParameter.Company"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:catel="http://catel.codeplex.com">

<!-- For the sake of simplicity, content is left out -->

</catel:UserControl>
The code behind is even simpler:
Note that the class definition is now instead of catel:UserControl UserControl
/// <summary>
/// Interaction logic for Company.xaml
/// </summary>
public partial class Company : UserControl
{
/// <summary>
/// Initializes a new instance of the <see cref="Company"/> class.
/// </summary>
public Company()
{
InitializeComponent();
}
}
Now the control is created (I dont want to focus on the actual control content here, since its not important), we can use the user control in our
main window that has a collection of companies. The view model also has a property representing the selected company SelectedCompany
inside the listbox. Then, we use the Company control and bind the data context to the property: SelectedCompany
<!-- Items control of companies -->
<ListBox Grid.Column="0" ItemsSource="{Binding CompanyCollection}"
SelectedItem="{Binding SelectedCompany}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Label Content="{Binding Name}" />
<Label Content="{Binding CEO.FullName}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

<!-- Company details -->
<UserControlWithParameter:Company Grid.Column="1" DataContext="{Binding
SelectedCompany}" />
As the code shows, there is a listbox containing all the companies. The data context of the user control is bound to the . The SelectedCompany
cool thing is that as soon as a company is selected, the user control will create an instance of the because it accepts a CompanyViewModel Com
instance in the constructor. The screenshot of the example application will (hopefully) give more insight in what change is causing the exact pany
view model creation:
In the image above, you see 2 controls. The first one is an items control that binds to the because the window represents CompaniesViewModel
list of companies. The second one is the , which dynamically constructs the as soon as a company is CompanyControl CompanyViewModel
selected at the left. This means that for every company selection, and new view model is constructed. This way, you can handle the saving,
canceling and closing of the view model before the next is view model is constructed.
The best thing about this is that you can actually start re-using user controls throughout your whole application. Instead of having the main view
model have to define all the properties of (sub) controls, now each control has its own view model, and you dont have to worry about the
implementation in the parent of a control. Simply set the data context of the user control to the right type instance, and the user control will handle
the rest.
Mapping properties from/to view model
When developing custom user controls, you still want to use the power of MVVM, right? With Catel, all of this is possible. All other frameworks
require a developer to manually set the data context on a user control. Or what about mapping user control properties from/to the view model?
To map a property of a custom user control to a view model and back, the only thing a developer has to do is to decorate the dependency
property of the control with the . Normally, a developer has to build logic that subscribes to property changes of both ViewToViewModelAttribute
the view model and the control, and then synchronize all the differences. Thanks to the , the that ships ViewToViewModelAttribute UserControl
with Catel takes care of this. The usage of the attribute looks as follows:
The easiest way to create a new is to use item templates UserControl
[ViewToViewModel]
public bool MyDependencyProperty
{
get { return (bool)GetValue(MyDependencyPropertyProperty); }
set { SetValue(MyDependencyPropertyProperty, value); }
}
// Using a DependencyProperty as the backing store for MyDependencyProperty. This
enables animation, styling, binding, etc...
public static readonly DependencyProperty MyDependencyPropertyProperty =
DependencyProperty.Register("MyDependencyProperty", typeof(bool),
typeof(MyControl), new UIPropertyMetadata(true));
By default, the attribute assumes that the name of the property on the view model is the same as the property on the user control. To specify a
different name, use the overload of the attribute constructor as shown in the following example:
[ViewToViewModel("MyViewModelProperty")]
public bool MyDependencyProperty
... (remaining code left out for the sake of simplicity)
In the first place, all of this looks fine enough. However, what should happen when the current view model of the control is replaced by another
instance? Or what if the developer only wants to map values from the control to the view model, but not back? By default, the view model will take
the lead when this attribute is used. This means that as soon as the view model is changed, the values of the control will be overwritten by the
values of the view model. If another behavior is required, the property of the attribute should be used: MappingType
[ViewToViewModel("MyViewModelProperty", MappingType =
ViewToViewModelMappingType.TwoWayControlWins)]
public bool MyDependencyProperty
... (remaining code left out for the sake of simplicity)
The table below explains the options in detail:
Enum value Description
TwoWayDoNothing Two way, which means that either the control or the view model will
update the values of the other party as soon as they are updated.
When this value is used, nothing happens when the view model of
the user control changes. This way, it might be possible that the
values of the control and the view model are different. The first one to
update next will update the other.
TwoWayViewWins Two way, which means that either the control or the view model will
update the values of the other party as soon as they are updated.
When this value is used, the value of the control is used when the
view model of the user control is changed, and is directly transferred
to the view model value.
TwoWayViewModelWins Two way, which means that either the control or the view model will
update the values of the other party as soon as they are updated.
When this value is used, the value of the view model is used when
the view model of the user control is changed, and is directly
transferred to the control value.
ViewToViewModel The mapping is from the control to the view model only.
ViewModelToView The mapping is from the view model to the control only.
Keeping view models alive
The automatically closes view models in the event. Reason for this is that there is noguaranteethat the control will be UserControl Unloaded
loaded again. However, this can have some negative side effects. On of this side effects is a user control shown as a tab in a tab control. One of
the behaviors of a tab control is that it unloads all non-active tabs from the visual tree. Therefore, the cancels and closes the view UserControl
model. However, the state of the tab is lost then as well.
To prevent this behavior, it is possible to keep view models alive when a user control is unloaded. This can be done by setting CloseViewModelO
to . This way, the view model is not closed and will be re-used when the control is loaded again. The downside of this is that the nUnloaded false
responsibility of closing and disposing the view model is now in the hands of the developer. A great way to make a difference between unloading
(tab switch) and closing is to create a close button on the tabs that will explicitly call . ViewModel.CloseViewModel

MVVM behaviors
Starting with Catel 2.0, it is possible to use the logic of the following controls as a behavior:
DataWindow => WindowBehavior
UserControl => UserControlBehavior
Page => NavigationPageBehavior
This means that you no longer have to derive user controls from the to use the ability to solve the nested user controls problem. Or, if UserControl
you are not happy with the endless possibilities of the , why not just creating a custom one without having to think about the MVVM DataWindow
integration.
WindowBehavior
UserControlBehavior
NavigationPageBehavior
WindowBehavior
The class takes care of all the MVVM integrations of a window and a view model. So, where you previously had to derive a WindowBehavior
Window implementation from , you can now create a new Window like any application and then add this: DataWindow
The and properties are not obligate, and need the format of . By default, the Click event is used, so if a button Save Cancel [controlname].[event]
(or another control that should respond using the event), the is sufficient. Click [controlname]
<i:Interaction.Behaviors>
<catel:WindowBehavior ViewModelType="viewmodels:DemoWindowViewModel"
Save="okButton.Click" Cancel="cancelButton.Click" />
</i:Interaction.Behaviors>
Seems too easy right? Well, it is really all you have to do.
This looks great, but why is there still a with this terrific solution? DataWindow
First of all, we have to think about all the people that are already using Catel. We don't want to break their code and provide backward
compatibility. Updates to the logic will be applied to both the behavior and the view base because the logic is locatedin a separate class. Also, the
is truly a terrific class, which supports lots of customization and takes care of dumb generation of buttons and the DataWindow InfoBarMessageC
. ontrol
UserControlBehavior
The UserControlBehavior class takes care of all the MVVM integrations of a user control and a view model. So, where you previously had to
derive a UserControl implementation from UserControl, you can now create a new UserControl like any application and then add this:
<i:Interaction.Behaviors>
<catel:UserControlBehavior ViewModelType="viewmodels:DemoWindowViewModel" />
</i:Interaction.Behaviors>
This looks great, but why is there still a with this terrific solution? UserControl
For more information, check out the the which shows the differences Catel.Examples.WPF.AdvancedDemo
First of all, we have to think about all the people that are already using Catel. We don't want to break their code and provide backward
compatibility. Also, the implements the interface which allows chained view models in a hierarchy. If you don't UserControl IViewModelContainer
need this, just go for the behavior. If you need hierarchy chains, either let the custom implement it or use the . UserControl UserControl
To support nested user controls and their validation, it is important to chain views together using the interface. You can IViewModelContainer
choose not to do this, but then it is important to disable for performance reasons (otherwise, the behavior will SupportParentViewModelContainers
keep searching the visual tree for the parent view model).
NavigationPageBehavior
The class takes care of all the MVVM integrations of a page (used in navigation or browser based applications) and a NavigationPageBehavior
view model. So, where you previously had to derive a implementation from , you can now create a new like any application and Page Page Page
then add this:
<i:Interaction.Behaviors>
<catel:NavigationPageBehavior ViewModelType="viewmodels:DemoWindowViewModel" />
</i:Interaction.Behaviors>
This looks great, but why is there still a Page with this terrific solution?
First of all, we have to think about all the people that are already using Catel. We don't want to break their code and provide backward
compatibility. Also, the class comes with more default functionality that you might be interested in. Page
Validation controls
There are some very important controls in Catel which help with visualizing the validation results.
InfoBarMessageControl
WarningAndErrorValidator
InfoBarMessageControl
Ever wanted to show the details of error messages to your end-users? Then, the is the control to use! The control shows InfoBarMessageControl
a summary of all business and field errors provided by bindings on objects that implement the interface. IDataErrorInfo
In combination with the control, the can even show field and business warnings for objects that WarningAndErrorValidator InfoBarMessageControl
implement the interface that ships with Catel. IDataWarningInfo
<catel:InfoBarMessageControl>
<!-- Actual content here -->
</catel:InfoBarMessageControl>
The subscribes to the class. This class is responsible for showing the red border around the controls that WPF InfoBarMessageControl Validation
shows by default. Then, it requests the actual field error property of the data item. This is added to an internal collection of error messages, and
For more information, check out the the which shows the differences Catel.Examples.WPF.AdvancedDemo
For more information, check out the the which shows the differences Catel.Examples.WPF.BrowserApplication
therefore the control is able to show the errors of all bindings.
When the control is found as a child control, the also subscribes to the events exposed by the WarningAndErrorValidator InfoBarMessageControl
. The internal working of that control is explained later in this article. When a data object is subscribed via the WarningAndErrorValidator WarningA
, the will also handle the warnings and business errors of that data object. ndErrorValidator InfoBarMessageControl
WarningAndErrorValidator
The control is not visible to the end user. The only thing this control takes care of is to forward business errors and WarningAndErrorValidator
warnings to controls that are interested in them. The only control that ships with Catel is the . Thanks to the InfoBarMessageControl WarningAndE
, the is able to show business errors and warnings to the end user. rrorValidator InfoBarMessageControl
<catel:WarningAndErrorValidator Source="{Binding MyObject}" />
The needs to be placed inside an . The control then subscribes to all property changed events WarningAndErrorValidator InfoBarMessageControl
to make sure it receives all change notifications. Then, on every property change, the control checks whether the sender either implements the ID
or interfaces. ataErrorInfo IDataWarningInfo
When an error or warning is found on the changed property, the control invokes the corresponding events so the can InfoBarMessageControl
show the right information. When an error or warning no longer exists in a model, a event is invoked so the kno Removed InfoBarMessageControl
ws that the error or warning should be removed from the summary.
Finding the view of a view model
Sometimes it is required to find the view of a view model. For example, this comes in handy when implementing drag and drop where you only
want to support code via view models.
Internally, Catel uses with the for this. As soon as a view is loaded (via the Loaded event), the view is registered to the view IViewManager
manager. The view manager will keep an eye on the events of the view and notice view model changes.
A view is removed from the manager as soon as it is unloaded (via the event). From this moment on, it is no longer possible to retrieve Unloaded
a view via its view model.
Retrieving the view of a view model
To find the view of a view model, use the steps below:
1) Resolve the view from from the : IViewManager ServiceLocator
var viewManager = ServiceLocator.Default.ResolveType<IViewManager>();
2) Resolve the view:
var views = viewManager.GetViewsOfViewModel(myViewModel);
Using external controls
Catel ships with default controls and the . However, some people rather use controls and windows from Telerik, DevExpress or some DataWindow
other 3rd party controls. This is perfectly possible and it is pretty easy to let those external controls support MVVM in the "Catel way".
The logic can be implemented via the MVVM behaviors that ship with Catel. In fact, the and of Catel also use these DataWindow UserControl
behaviors to implement their logic.
Using a custom control
Using a custom window
Using a custom control
Remember that only controls implementing are supported by the IView IViewManager
Note that it is possible that multiple views are linked to the same view model
In this part of the documentation, the of Telerik will be used as an example on how to create a that behaves like the RadTabItem RadTabItem Use
. rControl
Creating the base class with behavior
Using the class
Creating the base class with behavior
The first thing to do is to create a new base class that accepts a view model type argument. In this example, we will call it (to make it as TabItem
"external control company independent" as possible). Below is the code for the control definition. The downside of xaml based applications is that
you cannot derive from controls or windows that have a partial class defined in xaml. Therefore, all controls and code must be initialized via code
as you can see in the code below.
/// <summary>
/// Base class for a control with the Catel mvvm behavior.
/// </summary>
/// <typeparam name="TViewModel">The type of the view model.</typeparam>
public class TabItem : RadTabItem, IUserControl
{
private readonly UserControlLogic _logic;
/// <summary>
/// Initializes a new instance of the <see cref="TabItem{TViewModel}"/> class.
/// </summary>
public TabItem()
{
var viewModelType = GetViewModelType();
if (viewModelType == null)
{
var viewModelLocator =
ServiceLocator.Instance.ResolveType<IViewModelLocator>();
viewModelType = viewModelLocator.ResolveViewModel(GetType());
if (viewModelType == null)
{
const string error = "The view model of the view could not be resolved.
Use either the GetViewModelType() method or IViewModelLocator";
throw new NotSupportedException(error);
}
}
_logic = new UserControlLogic(this, viewModelType);
_logic.ViewModelChanged += (sender, e) => ViewModelChanged.SafeInvoke(this, e);
_logic.ViewModelPropertyChanged += (sender, e) =>
ViewModelPropertyChanged.SafeInvoke(this, e);
_logic.PropertyChanged += (sender, e) => PropertyChanged.SafeInvoke(this, e);
_logic.ViewLoading += (sender, e) => ViewLoading.SafeInvoke(this);
_logic.ViewLoaded += (sender, e) => ViewLoaded.SafeInvoke(this);
_logic.ViewUnloading += (sender, e) => ViewUnloading.SafeInvoke(this);
_logic.ViewUnloaded += (sender, e) => ViewUnloaded.SafeInvoke(this);
SetBinding(RadTabItem.HeaderProperty, new Binding("Title"));
}
/// <summary>
/// Gets the view model that is contained by the container.
/// </summary>
/// <value>The view model.</value>
public IViewModel ViewModel
{
get { return _logic.ViewModel; }
}

public bool CloseViewModelOnUnloaded


{
get { return _logic.GetValue<UserControlLogic, bool>(x =>
x.CloseViewModelOnUnloaded, true); }
set { _logic.SetValue<UserControlLogic>(x => x.CloseViewModelOnUnloaded =
value); }
}

public bool SupportParentViewModelContainers


{
get { return _logic.GetValue<UserControlLogic, bool>(x =>
x.SupportParentViewModelContainers, true); }
set { _logic.SetValue<UserControlLogic>(x => x.SupportParentViewModelContainers
= value); }
}

public bool DisableWhenNoViewModel


{
get { return _logic.GetValue<UserControlLogic, bool>(x =>
x.DisableWhenNoViewModel, false); }
set { _logic.SetValue<UserControlLogic>(x => x.DisableWhenNoViewModel = value);
}
}

/// <summary>
/// Occurs when the <see cref="ViewModel"/> property has changed.
/// </summary>
public event EventHandler<EventArgs> ViewModelChanged;
/// <summary>
/// Occurs when a property on the <see cref="ViewModel"/> has changed.
/// </summary>
public event EventHandler<PropertyChangedEventArgs> ViewModelPropertyChanged;

/// <summary>
/// Occurs when a property on the container has changed.
/// </summary>
/// <remarks>
/// This event makes it possible to externally subscribe to property changes of a
<see cref="DependencyObject"/>
/// (mostly the container of a view model) because the .NET Framework does not
allows us to.
/// </remarks>
public event EventHandler<PropertyChangedEventArgs> PropertyChanged;

/// <summary>
/// Occurs when the view model container is loading.
/// </summary>
public event EventHandler<EventArgs> ViewLoading;
/// <summary>
/// Occurs when the view model container is loaded.
/// </summary>
public event EventHandler<EventArgs> ViewLoaded;
/// <summary>
/// Occurs when the view model container starts unloading.
/// </summary>
public event EventHandler<EventArgs> ViewUnloading;
/// <summary>
/// Occurs when the view model container is unloaded.
/// </summary>
public event EventHandler<EventArgs> ViewUnloaded;
}
If you are using .NET / Silverlight, you must add the property below as well:
public bool SkipSearchingForInfoBarMessageControl
{
get { return _logic.GetValue<UserControlLogic, bool>(x =>
x.SkipSearchingForInfoBarMessageControl, true); }
set { _logic.SetValue<UserControlLogic>(x =>
x.SkipSearchingForInfoBarMessageControl = value); }
}
Using the class
The class can now be used the same as the class. For more information, see . UserControl UserControl explained
Using a custom window
In this part of the documentation, the of Telerik will be used as an example on how to create a that behaves like the RadWindow WindowBase Dat
. aWindow
Creating the base class with behavior
The first thing to do is to create a new base class that accepts a view model type argument. In this example, we will call it (to make it WindowBase
as "external control company independent" as possible). Below is the code for the window definition. The downside of xaml based applications is
that you cannot derive from controls or windows that have a partial class defined in xaml. Therefore, all controls and code must be initialized via
code as you can see in the code below.
/// <summary>
/// Base class for a window with the Catel mvvm behavior.
/// </summary>
/// <typeparam name="TViewModel">The type of the view model.</typeparam>
public class Window : RadWindow, IDataWindow
{
private readonly WindowLogic _logic;
/// <summary>
/// Initializes a new instance of the <see cref="Window{TViewModel}"/> class.
/// </summary>
public Window()
: this(null) { }
/// <summary>
/// Initializes a new instance of the <see cref="Window{TViewModel}"/> class.
/// </summary>
/// <param name="viewModel">The view model.</param>
public Window(IViewModel viewModel)
{
You would expect an abstract class here, but the designers (both Visual Studio and Expression Blend) can't handle abstract base
classes
Because the of Telerik does not close the window when the is set, this window subscribes to the RadWindow DialogResult ViewModelC
event to close the window losed
var viewModelType = (viewModel != null) ? viewModel.GetType() : GetViewModelType();
if (viewModelType == null)
{
var viewModelLocator = ServiceLocator.Instance.ResolveType<IViewModelLocator>();
viewModelType = viewModelLocator.ResolveViewModel(GetType());
if (viewModelType == null)
{
const string error = "The view model of the view could not be resolved. Use either
the GetViewModelType() method or IViewModelLocator";
throw new NotSupportedException(error);
}
}
_logic = new WindowLogic(this, viewModelType, viewModel);
_logic.ViewModelChanged += (sender, e) => ViewModelChanged.SafeInvoke(this, e);
_logic.ViewModelPropertyChanged += (sender, e) =>
ViewModelPropertyChanged.SafeInvoke(this, e);
_logic.PropertyChanged += (sender, e) => PropertyChanged.SafeInvoke(this, e);
_logic.ViewLoading += (sender, e) => ViewLoading.SafeInvoke(this);
_logic.ViewLoaded += (sender, e) => ViewLoaded.SafeInvoke(this);
_logic.ViewUnloading += (sender, e) => ViewUnloading.SafeInvoke(this);
_logic.ViewUnloaded += (sender, e) => ViewUnloaded.SafeInvoke(this);
// Because the RadWindow does not close when DialogResult is set, the following code
is required
ViewModelChanged += (sender, e) => OnViewModelChanged();
// Call manually the first time (for injected view models)
OnViewModelChanged();
WindowStartupLocation = WindowStartupLocation.CenterScreen;
SetBinding(RadWindow.HeaderProperty, new Binding("Title"));
}
/// <summary>
/// Gets the view model that is contained by the container.
/// </summary>
/// <value>The view model.</value>
public IViewModel ViewModel
{
get { return _logic.ViewModel; }
}
/// <summary>
/// Occurs when the <see cref="ViewModel"/> property has changed.
/// </summary>
public event EventHandler<EventArgs> ViewModelChanged;
/// <summary>
/// Occurs when a property on the <see cref="ViewModel"/> has changed.
/// </summary>
public event EventHandler<PropertyChangedEventArgs> ViewModelPropertyChanged;
/// <summary>
/// Occurs when a property on the container has changed.
/// </summary>
/// <remarks>
/// This event makes it possible to externally subscribe to property changes of a
<see cref="DependencyObject"/>
/// (mostly the container of a view model) because the .NET Framework does not allows
us to.
/// </remarks>
public event EventHandler<PropertyChangedEventArgs> PropertyChanged;
/// <summary>
/// Occurs when the view model container is loading.
/// </summary>
public event EventHandler<EventArgs> ViewLoading;
/// <summary>
/// Occurs when the view model container is loaded.
/// </summary>
public event EventHandler<EventArgs> ViewLoaded;
/// <summary>
/// Occurs when the view model container starts unloading.
/// </summary>
public event EventHandler<EventArgs> ViewUnloading;
/// <summary>
/// Occurs when the view model container is unloaded.
/// </summary>
public event EventHandler<EventArgs> ViewUnloaded;

private void OnViewModelChanged()
{
if (ViewModel != null && !ViewModel.IsClosed)
{
ViewModel.Closed += ViewModelClosed;
}
}
private void ViewModelClosed(object sender, ViewModelClosedEventArgs e)
{
Close();
}
}
Using the class
The class can now be used the same as the class. For more information, see . DataWindow DataWindow
Advanced information about views
If you want to know about the background information on how the and work, you've come to the right place. The UserControl DataWindow
information found in this part is pretty heavy material, so enter at your own risk...
DataWindow - under the hood
UserControl - under the hood
DataWindow - under the hood
UserControl - under the hood
The is a pretty sophisticated class. In this part of the documentation, the inner workings of the control are explained. What better way UserControl
is there than to using flowcharts. There are a few events very important for the inner workings of the user control. The flowcharts are created per
event.
Managing the custom DataContext
Main flow
Loaded
Unloaded
DataContextChanged
DetermineDataContext
Managing the custom DataContext
The logic uses an additional layer to customize the DataContext. Below is a graphical representation of how it works. UserControl
You would expect an abstract class here, but the designers (both Visual Studio and Expression Blend) can't handle abstract base
classes
This documentation has to be written in the future
Keep in mind that the actual logic is implemented in the , which is used by the . This way, the logic can be UserControlLogic UserControl
used by any user control via the . UserControlBehavior
Another view can be found in the image below:
Main flow
The following flowchart shows what happens with a user control in the main flow (the startup). First, it checks whether the user control is loaded
(which is not in a normal case). If the control is loaded, it goes directly to determining the datacontext. Otherwise, it will postpone the action until
the event. Loaded
Loaded
When the control is loaded, it starts checking for the first time whether the current datacontext can be used to create a view model. But, before it
does this, it checks whether it should (and can) re-use an existing view model. To control whether view models should be re-used, use the CloseV
property. iewModelOnUnloaded
If a view model can and should be re-used, it sets the view model as data context and that's it. If there is no view model, or the previous view
model should not be re-used, the control continues to determine the datacontext.
Unloaded
Another event that is very important is the event. In this event, the control either cleans up the view model or stores it so it can be Unloaded
re-used later. Then, it also restores the old datacontext so it never breaks existing application bindings. This way, the control won't leave any
traces behind.
DataContextChanged
The event is used to react to changes of the datacontext. You might be thinking: "there is no event in DataContextChanged DataContextChanged
Silverlight". We use the class for that. If the new datacontext is new (thus not a view model that the control just set itself), it it DataContextHelper
continues to determine the datacontext. Otherwise, it will not take any action.
DetermineDataContext
All other flowcharts eventually led to this flowchart, the determination of the datacontext. The determination of the datacontext is very important,
because this is the moment where the user control transforms the datacontext into a new view model if possible. First it tries is to construct the
view model with the datacontext. So, if the datacontext is an object of type Person, and the view model of the user control has a constructor that
accepts a Person object, it injects the datacontext into the constructor of the view model. If that fails, or there is simply no constructor, the control
checks whether the view model has an empty constructor. If so, it constructs the view model and sets it as the new datacontext. If not, it will leave
the datacontext untouched.
Basically, this is all that happens on a higher level to transform a datacontext into a view model. Under the hood, it's a bit more complicated but
again, on a higher level this is what happens.
Catel.Mvc
The MVC library provided by Catel provides code to easily combine the power of Catel with ASP.NET MVC.
Configuring dependency injection
Configuring dependency injection
Dependency injection in ASP.NET MVC controllers
Dependency injection in ASP.NET Web api controllers
Dependency injection in ASP.NET MVC controllers
The ServiceLocator is a very powerful dependency injection class. To allow the ASP.NET MVC to use the ServiceLocator as dependency
resolver, simply call the following in the global.asax class:
Catel.Mvc.DependencyInjectionConfig.RegisterServiceLocatorAsDependencyResolver();
Dependency injection in ASP.NET Web api controllers
If you are using web api as well, a few more things must be done.
1.Create new type implementing theIDependencyResolverof the web api:
public class CatelWebApiDependencyResolver : Catel.IoC.DependencyResolver,
System.Web.Http.Dependencies.IDependencyResolver
{
private readonly IServiceLocator _serviceLocator;
private readonly ITypeFactory _typeFactory;
public CatelWebApiDependencyResolver()
: this(ServiceLocator.Default) { }

public CatelWebApiDependencyResolver(IServiceLocator serviceLocator)
{
Argument.IsNotNull(() => serviceLocator);

_serviceLocator = serviceLocator;
_typeFactory = serviceLocator.ResolveType<ITypeFactory>();
}

public System.Web.Http.Dependencies.IDependencyScope BeginScope()
{
// This resolver does not support child scopes, so we simply return 'this'.
return this;
}

public void Dispose()


{
// nothing to dispose
}
}
2. Register the class manually:
GlobalConfiguration.Configuration.DependencyResolver = new
CatelWebApiDependencyResolver();

Catel.Extensions.Controls
Controls
Pixel shaders
StyleHelper
Themes

Controls
There are several controls available. See the child pages.
StackGrid
TabControl
TraceOutputControl
WatermarkTextBox
StackGrid
Although the example looks crappy (I am not a designer), it shows the power of the StackGrid. You don't have to specify the Grid.Row and
Grid.Column attached properties. Remember the times that you want to insert a grid and you had to increase all the numbers? From now on, use
the StackGrid!
<catel:StackGrid>
<!-- Row definitions -->
<catel:StackGrid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" MinHeight="15" />
<RowDefinition Height="Auto" />
</catel:StackGrid.RowDefinitions>

<!-- Column definitions -->
<catel:StackGrid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</catel:StackGrid.ColumnDefinitions>

<!-- Name, will be set to row 0, column 1 and 2 -->
<Label Content="Name" />
<TextBox Text="Geert van Horrik" />

<!-- Empty row -->
<catel:EmptyRow />

<!-- Wrappanel, will span 2 columns -->
<WrapPanel Grid.ColumnSpan="2">
<Button Command="ApplicationCommands.Close" />
</WrapPanel>
</catel:StackGrid>

The Grid is an excellent control to show several controls in a nice layout on the screen. However, it happens a lot that a grid consists of only 2 or
3 columns, and the first column is for all the labels, and the second one is for controls such as textboxes. You correctly implement all the windows
and controls of your application based on user requirements, and then the user decides that he/she wants a row inserted into a grid containing
about 20 rows. When this happens, you need to re-define all the row attributes of the grid.
With the StackGrid, it is no longer required to define the row and column definitions. The StackGrid can smartly interpret the location of the
controls and therefore fill in the Grid.Row and Grid.Column attached properties for you. You need an empty row? No problem, you can use the
EmptyRow class to fill up a row for you. You want a column span? No problem, just use the existing Grid.Column attached property and the
StackGrid will automatically handle this for you.
The StackGrid internally uses a Grid to measure the layout. However, it dynamically loops through its children, and then assigns the Grid.Row
and Grid.Column attached properties for the user.
TabControl
A custom implementation of the TabControl which allows the customization of the way tab items are loaded.
The following options are available:
Single => loads the current tab
AllOnFirstUse => loads all the tabs when a tab is used for the first time
AllOnStartUp => loads all the tabs when the control is loaded

TraceOutputControl
TraceOutputControl is a debugging convenience control. It shows all the trace and logging output in a filterable control. This way, you can easily
view all the binding errors, etc., in your app instead of the non-colored output window in Visual Studio.
<Controls:TraceOutputControl />
Many times, developers are inside an application viewing the result of what they have created. But, they also want to know what is happening in
the background and view the traces they have written. The output window of Visual Studio is a solution, but it doesnt show errors very well (black,
just as the normal output). Also, it doesnt allow run-time filtering of the results.
The TraceOutputControl allows a developer to embed a control inside a window or control in the actual application and view the information when
the application is actually running. The TraceOutputControl is also available as a separate window in case it cant be embedded into the software
itself (for example, when a plug-in is being developed for a 3rd party application).
The TraceOutputControl subscribes a custom TraceListener to the Trace.Listeners collection. Then, it filters out the messages that the user
actually wants to see and stores these messages into an internal collection so the user can still filter the messages at a later time.
WatermarkTextBox
The WatermarkTextBox allows to set a watermark on textboxes that do not yet have a value.
Setting up a simple watermark
A simple watermark is a watermark with text only. Below is an example:
<catel:WatermarkTextBox Watermark="Enter the first name" />
Setting up a complex watermark
A complex watermark is a watermark that can contain any control, for example an image:
<catel:WatermarkTextBox>
<catel:WatermarkTextBox.Watermark>
<StackPanel Orientation="Horizontal">
<Image Source="/Images/Address.png" />
<TextBlock Text="Enter the e-mail" />
</StackPanel>
</catel:WatermarkTextBox.Watermark>
</catel:WatermarkTextBox>
Pixel shaders
Catel also uses pixel shaders to apply effects to controls via themes and styles. One of the pixel shaders is, for example, the . GrayscaleEffect
This effect automatically converts an image on a button to gray scale when the button is disabled. Below is an example of the shader effect:
This documentation only applies to WPF
If there are a lot of buttons used on the screen, it might be possible that the video card does not support so many shaders, and then WPF will start
throwing exceptions. In that case, first try to set the shader mode of Catel to . If that doesnt work, you can turn the ShaderRenderMode.Software
shaders off by using . ShaderRenderMode.Off
// Force software rendering
StyleHelper.PixelShaderMode = PixelShaderMode.Software;
// Turn off
StyleHelper.PixelShaderMode = PixelShaderMode.Off;
StyleHelper
The StyleHelper class has a few static members that will create style forwarders. Style forwarders are styles that are defined on the application
level, not on the theme level. This allows you to create forwarders with the same key as the control name, but that will forward to the
DefaultxxxStyle. Since the new styles are defined at the application level, you will not get any circular references because the style defined in the
theme cannot access the application level resources.
This is accomplished by simply calling StyleHelper.CreateStyleForwardersForDefaultStyles() in the OnStartup of an application.
Catel currently ships with a several theme files. This example theme file is based on the Aero" theme that is included in the WPF libraries. The
theme of Catel corrects the margins, since the default Aero" theme sets the margin of all controls to 0, which will result in all the user controls
being stuck together, as shown in the figure below:
We see too many developers fixing the margins on the control directly, while this can also be accomplished by using the Catel theme and the
included StyleHelper class. See the image below for the final result:
Themes
Using the themes is pretty simple. First, the right theme has to be added to the application resource dictionary:
<Application x:Class="OverrideStyles.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Views/MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- Set custom theme -->
<ResourceDictionary
Source="/Catel.Extensions.Controls;component/themes/generic.xaml"
/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
The next step is optional. If the margins should automatically be corrected by the stylehelper, it is required to call the following code somewhere in
the application (application startup is recommended):
namespace OverrideStyles
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
// Create style forwarders
Catel.Windows.Helpers.StyleHelper.CreateStyleForwardersForDefaultStyles();
// Call base
base.OnStartup(e);
}
}
}
Catel.Extensions.CSLA
Catel supports CSLA. All MVVM features in Catel (such as nested user controls) can be used with in combination with the CSLA ViewModelBase.
For more information about CSLA, see http://www.lhotka.net/cslanet/
Catel.Extensions.Data
The data extension provides an implementation of the specification pattern.
Specifications
Specifications
Catel provides an implementation of the . specification pattern
A specification pattern outlines a business rule that is combinable with other business rules. In this pattern, a unit of business logic inherits its
functionality from the abstract aggregate Composite Specification class. The Composite Specification class has one method called IsSatisfiedBy
that returns a boolean value.
After instantiation, the specification is "chained" with other specifications, making new specifications easily maintainable, yet highly customizable
business logic. Furthermore upon instantiation the business logic may, through method invocation or inversion of control, have its state altered in
order to become a delegate of other classes such as a persistence repository.
The big advantage is that commonly used queries can be converted to a specification or a combination of specifications. Then if the query should
change (for example, IsDeleted is introduced), only the specification needs to be changed.
The cool thing about the specification implementation in Catel is that it can be used for Entity Framework queries, but also provides implicit
casting to a Func<TEntity, bool>. This way a specification can be passed to any method accepting a method and thus also works with all linq
queries on normal collections.
Using the classes
Creating a specification is very simple. Below is an example of an active products specification:
public class ActiveProductSpecification : Specification<Product>
{
public ActiveProductSpecification()
: base(x => !x.IsDeleted && x.IsActive)
{
}
}
Then the specification can be used like this:
var productRepository = new ProductRepository();
var activeProductSpecification = new ActiveProductSpecification();
var activeProducts = productRepository.GetQuery(activeProductSpecification);
Catel.Extensions.DynamicObjects
In .NET, it is possible to create fully dynamic objects. This makes it possible to create types of which the members are not yet known at compile
time. Starting with Catel 3.7, the is fully dynamic and still provides the features such as serialization. Catel supports dynamic DynamicModelBase
objects by implementing the which is available in WPF, Silverlight and Windows RT. IDynamicMetaObjectProvider
Creating dynamic objects
Using ModelBase functionality
Supporting serialization of dynamic objects
Creating dynamic objects
Creating a dynamic object with full Catel functionality is easy. Just add the reference via NuGet and create a Catel.Extensions.DynamicObjects
class that derives from : DynamicModelBase
public class DynamicModel : DynamicModelBase
{
// TODO: Add custom functionality if required
}
Then the dynamic model can be used like this:
dynamic model = new DynamicModel();
model.NonExistingProperty = "a dynamic value";

Console.WriteLine(model.NonExistingProperty);
Using ModelBase functionality
The class derives from . However it must be preceded by the keyword. To use the functionali DynamicModelBase ModelBase dynamic ModelBase
ty, cast it to the right type:
For more information about dynamic programming, see MSDN
It is important to know that you must use the keyword to instantiate the type. dynamic
dynamic model = new DynamicModel();
model.NonExistingProperty = "a dynamic value";

// Note: the Validate method is available on the ModelBase


var modelBase = (ModelBase)model;
modelBase.Validate();
Supporting serialization of dynamic objects
Dynamic objects in Catel fully support the default serialization that Catel provides. To example below shows how to serialize a dynamic object:
dynamic model = new DynamicModel();
model.NonExistingProperty = "a dynamic value";
var serializer = SerializationFactory.GetXmlSerializer();
using (var memoryStream = new MemoryStream())
{
var dynamicModel = (DynamicModel)model;
serializer.Serialize(dynamicModel, memoryStream);
memoryStream.Position = 0L;
dynamic deserializedModel = serializer.Deserialize(typeof(DynamicModel),
memoryStream);
var deserializedDynamicModel = (DynamicModel) deserializedModel;
// deserializedDynamicModel is now a dynamically deserialized object
}
Catel.Extensions.EntityFramework5
Starting with Catel 3.5, support for Entity Framework 5 was added. For more information about Entity Framework 5, see the official documentation
. by Microsoft
Using the DbContextManager
Using the repositories and unit of work
Using the DbContextManager
The DbContextManager class allows the sharing of DbContext (with underlying ObjectContext) classes in Entity Framework 5. The good thing
about this is that the same context can be used in the same scope without having to recreate the same type of the same context over and over
again.
A very good example of this scoping is an ASP.NET (MVC) application where a context is normally shared throughout the whole thread that
handles a request. A big advantage of reusing the same instance of a context is that already fetched entities don't need to be refetched over and
over again.
Obtaining a DbContext
Obtaining a DbContext is very simple by using the DbContextManager.
using (var dbContextManager = DbContextManager<MyEntities>.GetManager())
{
var dbContext = dbContextManager.DbContext;
// TODO: handle logic with dbContext here
}

Scoping is all done automatically because when a DbContextManager is instantiated, a reference counter is increased. Everytime an instance of
the DbContextManager is disposed, the reference counter is decreased. When the reference count reaches zero (0), it will dispose the DbContext
that it manages.
Sharing a single DbContext per ASP.NET request
When a request is started, a context can be created by calling this code:
DbContextManagerHelper.CreateDbContextForHttpContext<MyEntities>();
When a request is ended, the context can be disposed by using this code:
DbContextManagerHelper.DisposeDbContextForHttpContext<MyEntities>();
Using the repositories and unit of work
The Repository and Unit of Work (UoW) pattern are very useful patterns to create an abstraction level over the DbContext that is provided by
Entity Framework. A much heard excuse not to use repositories is that EF itself already works with repositories (the DbContext) and a UoW (in
the SaveChanges method). Below are a few examples why it is a good thing to create repositories:
Abstract away some of the more complex features of Entity Framework that the end-developer should not be bothered with
Hide the actual DbContext (make it internal) to prevent misuse
Keep security checks and saving and rollback in a single location
Force the use of the Specification pattern on queries

A Unit of Work (UoW) is a a combination of several actions that will be grouped into a transaction. This means that either all actions inside a UoW
are committed or rolled back. The advantage of using a UoW is that multiple save actions to multipleRepositories can be grouped as a unit.
A repository is a class or service responsible for providing objects and allowing end-developers to query data. Instead of querying the DbContext
directly, the DbContext can be abstracted away to provide default queries and force required functionality to all end-developers of the DbContext.
Overview of Unit of Work and repositories
There are different interpretations of how repositories should be used in combination with unit of work. Let's start with an overview how the
DbContext, Repositories and Unit of Work relate to each other. The image below represents an overview of the situation as Catel deals with the
DbContext, Repositories and Unit of Work:
It is very important to wrap the DbContextManager in a using state because it must be disposed
Note that repositories and UoW should not be used to abstract away the ORM tool because that is just another abstraction layer which
is not required. Use it for the advantages mentioned above
The image above shows that the Unit of Work is the top-level component to be used. Each UoW contains its own DbContext instance. The
DbContext can either be injected or will be created on the fly. Then the UoW also contains repositories which always get the DbContext injected.
This way, all repositories inside a UoW share the same DbContext.
Creating a Unit of Work
A UoW can be created by simply instantiating it. The end-developer has the option to either inject the DbContext or let the DbContextManager
take care of it automatically.
using (var uow = new UnitOfWork<MyDbContext>())
{
// get repositories and query away
}
Creating a repository
A repository can be created very easily by deriving from the EntityRepositoryBase class. Below is an example of a customer repository:
public class CustomerRepository : EntityRepositoryBase<Customer, int>,
ICustomerRepository
{
public CustomerRepository(DbContext dbContext)
: base(dbContext)
{
}
}
public interface ICustomerRepository : IEntityRepository<Customer, int>
{
}
1.
2.
Retrieving repositories from a Unit of Work
Once a UoW is created, it can be used to resolve repositories. To retrieve a repository from the UoW, the following conditions must be met:
The container must be registered in the ServiceLocator as Transient type. If the repository is declared as non-transient, it will be
instantiated as new instance anyway.
The repository must have a constructor accepting a DbContext instance
To retrieve a new repository from the UoW, use the following code:
using (var uow = new UnitOfWork<MyDbContext>())
{
var customerRepository = uow.GetRepository<ICustomerRepository>();
// all interaction with the customer repository is applied to the unit of work
}
Saving a Unit of Work
It is very important to save a Unit of Work. Once the Unit of Work gets out of scope (outside the using), all changes will be discarded if not
explicitly saved.
using (var uow = new UnitOfWork<MyDbContext>())
{
var customerRepository = uow.GetRepository<ICustomerRepository>();
// all interaction with the customer repository is applied to the unit of work
uow.SaveChanges();
}

Catel.Extensions.FluentValidation
The validation in Catel is extremely flexible, at this point you must already know it, but sometimes it is just not enough or you are forced to use
external validators.
FluentValidation is a small validation library for .NET that uses a fluent interface and lambda expressions for building validation rules for your
business objects. Catel provides an extension in order to use FluentValidation as a validation library.
The only thing you have to do is install an isolate package named , available via NuGet, then you will be able to Catel.Extensions.FluentValidation
write your view models validations using FluentValidation approach.
Note that the extension can be used in combination with only, so it is not required to combine it with the FluentValidation Catel.Core
MVVM framework
public class PersonViewModelValidator : AbstractValidator<PersonViewModel>
{
public PersonViewModelValidator()
{
RuleFor(person => person.FirstName).NotEmpty();
RuleFor(person => person.LastName).NotEmpty().WithMessage("Please specify the
last name");
}
}
In order to retrieve the right validators, you must register the : FluentValidatorProvider
ServiceLocator.Default.RegisterType<IValidatorProvider, FluentValidatorProvider>();
The will automatically retrieve the right validators associated with the view models. FluentValidatorProvider
How handle all Catel validation concepts with fluent validation classes?
Catel handle concepts like field or business rules errors and warnings . So, it's necessary map the fluent validation class to the specific Catel
validation using . ValidationDescriptionAttribute
[ValidationDescription(Tag = "Person", ValidationResultType =
ValidationResultType.Error, ValidationType = ValidationType.Field)]
public class PersonViewModelValidator : AbstractValidator<PersonViewModel>
{
}
How FluentValidationProvider works?
FluentValidationProvider is an implementation of IValidationProvider (see: Validation via IValidator). It search all validators classes that
implements FluentValidation.IValidator interface, that also can validate the view model type.
A view model can have one or more validators, so FluentValidationProvider aggregates all validators in a single one using CompositeValidator
class. For performance reasons FluentValidationProvider only searches for validators on the assembly which the view model belongs to.
Catel.Extensions.Interception
Interception Extensions enables you to write code that is executed each time a matching method is invoked using a fluent API. It's suited for cross
cutting concerns, such as transactions, security and logging.
Method interception
Property interception
Interception provides the following advantages:
Strongly-typed syntax
Interception semantics are based on strongly-typed method definitions, which permit to develop aspects taking advantage of features like:
auto-completion, refactoring, compile-time errors, etc;
No configuration
FluentValidationProvider do not use NamingConventions
FluentValidation is only available in NET40, NET45, Silverlight 4 and Silverlight 5
We tried to simplify AOP implementation by favoring convention over configuration. As a result, no configuration of any kind is ever
required to build aspects. However, some conventions take place to make this possible;
Minimum learning-curve
In order to get started, no previous experience with this or any other AOP implementation is required. No need to know or understand
AOP terminology, which is not always very intuitive. By looking at some examples developers can figure out how to intercept calls and
modularize their own applications;
Methods as first-class elements
Utilizing dynamic proxies to implement AOP typically results in having to model aspects as interceptors. Such interceptors are commonly
associated with objects no with methods. Therefore, the developer is responsible for providing the logic to break down object interception
into method interception;
Usage in combination with IoC
The interception mechanism in Catel is based on the registration of a type in the ServiceLocator and in addition of the interception
configuration, this way, you can fully use the advantages of IoC.
Initially, Interception extension support Methods and Properties members for the types you register in the (internally, we create an ServiceLocator
class proxy instance which is actually registered in ). ServiceLocator
Method interception

There are many ways to configure method interception.


OnBefore callback
OnAfter callback
OnCatch and OnFinally callbacks
OnInvoke callback
OnReturn callback
Intercepting multiple method calls at once
Intercepting all members calls at once
Differentiating between overloaded methods
Stacking several methods on a single fluent instruction
Utilizing predicates to select multiple methods
OnBefore callback
It always runs before the target method execution.
var serviceLocator = ServiceLocator.Default;
serviceLocator.ConfigureInterceptionForType<ITestService, TestService>()
.InterceptMethod(service => service.Perform())
.OnBefore(() => Console.WriteLine("Called Before"));
var testService = serviceLocator.ResolveType<ITestService>();
testService.Perform();
The output will look like this:
Called Before
The actual call
OnAfter callback
It runs after the target method execution, but only if it does not throw an exception.
This extension is based on FluentAop
var serviceLocator = ServiceLocator.Default;
serviceLocator.ConfigureInterceptionForType<ITestService, TestService>()
.InterceptMethod(service => service.Perform())
.OnAfter(() => Console.WriteLine("Called After"));
var testService = serviceLocator.ResolveType<ITestService>();
testService.Perform();
The output will look like this:
The actual call
Called After
OnCatch and OnFinally callbacks
OnCatchcallback runs after the target method execution, but only if it throws an exception. callback runs after the target method OnFinally
execution. But and callbacks always run first if they exist. OnAfter OnCatch
var serviceLocator = ServiceLocator.Default;
serviceLocator.ConfigureInterceptionForType<ITestService, TestService>()
.InterceptMethod(service => service.Fail())
.OnCatch(exception => Console.WriteLine("An error of
type '{0}' occurs with message : \n'{1}'", exception.GetType().Name,
exception.Message))
.OnFinally(() => Console.Write("You can dispose
resources here"));
var testService = serviceLocator.ResolveType<ITestService>();
testService.Fail();
The output will look like this:
An error of type 'TargetInvocationException' occurs with message:
'Exception has been thrown by the target of an invocation'
You can dispose resources here
OnInvoke callback
It runs instead of the target method execution.
var serviceLocator = ServiceLocator.Default;
serviceLocator.ConfigureInterceptionForType<ITestService, TestService>()
.InterceptMethod(service => service.Perform())
.OnInvoke(invocation => Console.Write("The original call
has been replaced by this"));
var testService = serviceLocator.ResolveType<ITestService>();
testService.Perform();
The output will look like this:
The original call has been replaced by this
OnReturn callback
It runs right before the proxy method execution is over. callback runs first if it exist. OnFinally
var serviceLocator = ServiceLocator.Default;
serviceLocator.ConfigureInterceptionForType<ITestService, TestService>()
.InterceptMethod(service => service.ReturnNull())
.OnReturn((invocation, returnedValue) => returnedValue ??
"This is a replaced value");
var testService = serviceLocator.ResolveType<ITestService>();
var result = testService.ReturnNull();
Console.WriteLine(result);
The output will look like this:
This is the replaced value
Intercepting multiple method calls at once
You can configure interception of multiple methods call at once just like this:
var serviceLocator = ServiceLocator.Default;
serviceLocator.ConfigureInterceptionForType<ITestService, TestService>()
.InterceptMethods
(
service => service.Perform(),
service => service.Perform(It.IsAny<string>()),
service => service.Return()
)
.OnBefore(() => Console.WriteLine("Called On Before"))
.OnAfter(() => Console.WriteLine("Called On After"));
var testService = serviceLocator.ResolveType<ITestService>();
testService.Perform();
testService.Perform("testValue");
testService.Return();
The output will look like this:
Called On Before
The actual call
Called On after
Called On Before
Called On After
Called On Before
Called On After
Intercepting all members calls at once
To intercept all member calls at once, use the following code:
var serviceLocator = ServiceLocator.Default;
serviceLocator.ConfigureInterceptionForType<ITestService, TestService>()
.InterceptAll()
.OnBefore(() => Console.WriteLine("Called On Before"))
.OnAfter(() => Console.WriteLine("Called On After"));
var testService = serviceLocator.ResolveType<ITestService>();
testService.Perform();
testService.Name = "testValue";
var value = testService.Name;
The output will look like this:
Called On Before
The actual call
Called On after
Called On Before
Called On After
Called On Before
Called On After
Differentiating between overloaded methods
To differentiate between overloaded methods, use the following code:
Exclude members
If you want to exclude some members using methods, you can decorate your membre with the InterceptAll* DoNotInterceptAttribute
in the interface type.
var serviceLocator = ServiceLocator.Default;
serviceLocator.ConfigureInterceptionForType<ITestService, TestService>()
.InterceptMethod(service =>
service.Perform(It.IsAny<string>()))
.OnBefore(invocation => invocation.Arguments[0] =
"Intercepted");
var testService = serviceLocator.ResolveType<ITestService>();
testService.Perform("testValue");
testService.Perform(45);
The output will look like this:
Intercepted
45
Stacking several methods on a single fluent instruction
Use the following code:
var serviceLocator = ServiceLocator.Default;
serviceLocator.ConfigureInterceptionForType<ITestService, TestService>()
.InterceptMethod(service => service.Perform())
.OnBefore(() => Console.WriteLine("1,2,3..."))
.OnAfter(() => Console.WriteLine("Excecution Succeeded"))
.And()
.InterceptMethod(service => service.Fail())
.OnCatch(exception => Console.WriteLine("Exception occurs: '{0}'",
exception.Message))
.OnFinally(() => Console.Write("Dispose Resources Here"))
.And()
.InterceptMethod(service => service.ReturnNull())
.OnReturn((invocation, returnedValue) => returnedValue ?? "Replace Any
Null Value Here");
var testService = serviceLocator.ResolveType<ITestService>();
testService.Perform();
testService.Fail();
testService.ReturnNull();
The output will look like this:
1,2,3...
The actual call
Execution Succeeded
Exception occurs: 'Exception has been thrown by the target of an invocation.'
Dispose Resources Here
Utilizing predicates to select multiple methods
Use the following code:
var serviceLocator = ServiceLocator.Default;
serviceLocator.ConfigureInterceptionForType<ITestService, TestService>()
.InterceptWhere(method => method.Name == "Perform")
.OnBefore(() => Console.WriteLine("Called before"))
.OnAfter(() => Console.WriteLine("Called after"));
var testService = serviceLocator.ResolveType<ITestService>();
testService.ReturnNull();
testService.Perform();
The output will look like this:
Called before
The actual call
Called after
Property interception
Intercept setters
Intercept getters
Intercept setters
Use the following code:
var serviceLocator = ServiceLocator.Default;
serviceLocator.ConfigureInterceptionForType<ITestService, TestService>()
.InterceptSetter(service => service.Name)
.OnBefore(() => Console.WriteLine("Setting Property Intercepted"));
var testService = serviceLocator.ResolveType<ITestService>();
testService.Name = "testValue";
var name = testService.Name;
The output will look like this:
Setting Property intercepted
Intercept getters
Use the following code:
var serviceLocator = ServiceLocator.Default;
serviceLocator.ConfigureInterceptionForType<ITestService, TestService>()
.InterceptGetter(service => service.Name)
.OnBefore(() => Console.WriteLine("Getting Property Intercepted"));
var testService = serviceLocator.ResolveType<ITestService>();
testService.Name = "testValue";
var name = testService.Name;
The output will look like this:
Getting Property intercepted
Catel.Extensions.Memento
Lots of real world applications need to implement undo/redo. However, most applications written in MVVM lack this feature because it is very hard
to implement. Luckily, Catel solves this issue by introducing the . The is a service that allows a developer to IMementoService IMementoService
register custom actions that should be undone. A few actions you can think of:
Property change of a model
Item is added or removed to/from a collection
A method is executed
One way to introduce the memento pattern is by creating a copy of the whole memory at each step (yes, some people actually do this), but in
Catel it is done a bit smarter. For each possible action type, there is an implementation of the . This way, each action will know by itself UndoBase
how to undo or redo. Catel offers the following default implementations:
PropertyChangeUndo
CollectionChangeUndo
ActionUndo
If there are more actions supported, it is possible to write a custom implementation and add the specific action to the UndoBase IMementoService
. It will automatically be added to the undo/redo action stack.
Memento and collections
Memento and methods
Memento and properties
Undo and redo support
The supports both undo and redo actions. This means that an action that is undo-ed by a call to the method, it is IMementoService Undo
automatically added to the redo stack when redo is supported.
To undo an action, use the code below:
var mementoService = ServiceLocator.Default.ResolveType<IMementoService>();
mementoService.Undo();
It is possible to check whether it is possible to undo actions by using the property. This check is not required since the method will CanUndo Undo
also check this internally.
To redo an action, use the code below:
var mementoService = ServiceLocator.Default.ResolveType<IMementoService>();
mementoService.Redo();
It is possible to check whether it is possible to redo actions by using the property. This check is not required since the method will CanRedo Redo
also check this internally.
Grouping actions in batches
The automatically wraps all actions in batches. Because each action is treated as a batch, it is easy to begin a batch and add MementoService
several actions to a single batch. Below is the code to create a batch:
1.
2.
var mementoService = ServiceLocator.Default.ResolveType<IMementoService>();
mementoService.BeginBatch("Batch title", "Batch description");
// All actions added to the memento service are added to the specified batch
A batch can be ended in several ways:
A call to EndBatch
A call to BeginBatch
As soon as a batch is ended by one of the ways described below, it will be added to the undo stack.
Ignoring support for memento
Ignoring specific properties or methods for the is very easy. Just decorate them with the as IMementoService IgnoreMementoSupportAttribute
shown below:
[IgnoreMementoSupport]
public string IgnoredProperty { get; set; }
Memento and collections
Adding the ability to undo and redo collection changes on a collection is very simple using the class. This can be done CollectionChangeUndo
either automatically or manually.
Handling collection changes automatically
When a collection implements the interface, it is possible to register the collection. The will fully take INotifyCollectionChanged IMementoService
care of any collection changes by the collection and add these automatically to the undo/redo stack. Internally, the service will create an instance
of the which will register the changes in the . CollectionObserver IMementoService
var mementoService = ServiceLocator.Instance.ResolveType<IMementoService>();
mementoService.RegisterCollection(myCollection);
Handling collection changes manually
When an object does not support the interface or you want more control, it is possible to instantiate the INotifyPropertyChanged CollectionChange
yourself. See the example below: Undo
public void AddPerson(IPerson person)
{
var newIndex = _internalCollection.Add(person);

var mementoService = ServiceLocator.Instance.ResolveType<IMementoService>();
mementoService.Add(new CollectionChangeUndo(_internalCollection,
CollectionChangeType.Add, -1, newIndex, null, item));
}
Note that the and are optional. They are however a great way to represent the batches in the user interface Title Description
Note that all actions should be implemented, such as adding, replacing, removing and resetting to fully support undo/redo
Removing a collection and its actions
When a collection goes out of scope, it is important that the does not keep it in memory and keeps undoing the changes. IMementoService
Therefore, one should also unregister the collection:
var mementoService = ServiceLocator.Instance.ResolveType<IMementoService>();
mementoService.UnregisterCollection(myCollection);
Memento and methods
Adding the ability to undo and redo methods is the most complex, because this cannot be done automatically. However, it is possible to use the A
class to make it as easy as possible. ctionUndo
Handling methods manually
An action can come in two flavors. One with only undo support, and one with redo support. It is always recommended to implement the one with
support for redo, but the choice is always yours. For this example, let's assume a simple class that will increase a value (for which we are building
undo/redo support):
public class SpecialNumberContainer()
{
private int _number = 5;

public int Number { get { return _number; } }

public int IncreaseNumber()
{
_number++;
}
}
As you can see in the example, it is not possible to use the because the property has no setter and no change notification. PropertyChangeUndo
So, we will create custom actions for undo/redo.
First, the class with only undo support:
public class SpecialNumberContainer()
{
private int _number = 5;
public int Number { get { return _number; } }

public int IncreaseNumber()
{
_number++;

var mementoService = ServiceLocator.Instance.ResolveType<IMementoService>();
mementoService.Add(new ActionUndo(this, () => _number--));
}
}
The code above will add a new action to the undo stack every time the method is called. Then, it will not add it to the redo stack IncreaseNumber
Note that unregistering a collection will both cancel change notifications and remove the actions that belong to this collection from the
undo/redo stack
because redo is not possible (we haven't provided a redo action).
Below is the same class, but now with redo support:
public class SpecialNumberContainer()
{
private int _number = 5;
public int Number { get { return _number; } }

public int IncreaseNumber()
{
_number++;

var mementoService = ServiceLocator.Instance.ResolveType<IMementoService>();
mementoService.Add(new ActionUndo(this, () => _number--, () => _number++));
}
}
The code above will add a new action to the undo stack every time the method is called. Then, when an action is undo-ed, the IncreaseNumber
action is added to the redo stack and it is possible to redo the action because the redo action was provided as well.
Removing the actions from the undo/redo stack
When an action no longer has to be in the undo/redo stack of the one should call the method with the instance of the IMementoService, Clear
method as shown in the sample below:
var mementoService = ServiceLocator.Instance.ResolveType<IMementoService>();
mementoService.Clear(myInstanceContainingTheMethod);
Memento and properties
Adding the ability to undo and redo property changes on an object is very simple using the class. This can be done either PropertyChangeUndo
automatically or manually.
Handling property changes automatically
When an object implements the interface, it is possible to register the object. The will fully take care of INotifyPropertyChanged IMementoService
any property changes by the object and add these automatically to the undo/redo stack. Internally, the service will create an instance of the Objec
which will register the changes in the . tObserver IMementoService
var mementoService = ServiceLocator.Instance.ResolveType<IMementoService>();
mementoService.RegisterObject(myObject);
Handling property changes manually
When an object does not support the interface or you want more control, it is possible to instantiate the INotifyPropertyChanged PropertyChange
yourself. See the example below: Undo
public string Name
{
get { return _name; }
set
{
object oldValue = _name;
object newValue = value;
_name = value;
RaisePropertyChanged("Name");
var mementoService = ServiceLocator.Instance.ResolveType<IMementoService>();
mementoService.Add(new PropertyChangeUndo(this, "Name", oldValue, newValue));
}
}
Removing an object and its actions
When a model goes out of scope, it is important that the does not keep it in memory and keeps undoing the changes. IMementoService
Therefore, one should also unregister the object:
var mementoService = ServiceLocator.Instance.ResolveType<IMementoService>();
mementoService.UnregisterObject(myObject);
Catel.Extensions.Prism
Starting with Catel 3.1 the Prism extension is available.
Table of contents:
Making the region manager available
Activating a view into a specific region
Dealing with more than one and only one shell
Deactivating a view
Deactivating a view automatically
More information:
Declaring modules
Translating or customizing the initialization task messages
Using the bootstrapper
The latest version of the guidance, Prism, includes a feature named "User Interface Composition". Basically it allows build a mosaic like
application by loading multiple views that comes from different modules into an active regions exposed by a control, also know as the shell.
Note that unregistering an object will both cancel change notifications and remove the actions that belong to this object from the
undo/redo stack
But all this is about view models. Therefore, the Catel team decide to introduce an extension that implements a good starting point in order create
a composite user interface without actually referencing any view. At this point, you must have heared about of the UIVisualizerService, and the
way it can resolve a view from an instance of a view model.
Making the region manager available
First of all, you must make available the region manager on the instance of . A Prism based application uses MEF or Unity as ServiceLocator
primary IoC contanier. Therefore, you must synchronize this container with the Catel one, overriding the method of the ConfigureContainer
application class, using the following code: Bootstrapper
protected override void ConfigureContainer()
{
base.ConfigureContainer();
if (ServiceLocator.Instance.IsExternalContainerSupported(this.Container))
{
ServiceLocator.Instance.RegisterExternalContainer(this.Container);
}
}
but if you use primary IoC contanier, and your class inherits from the region manager is actually ServiceLocator Bootstrapper BootstrapperBase
available and you don't have to write the synchronization container code.
Since Catel 3.2 ServiceLocator support Dependency injection, therefore now you are able write Prism base application without the
usage of a third party container.
Activating a view into a specific region
To activate a view into a specific region, use the following code:
var viewModel = new EmployeeViewModel();
var dependencyResolver = this.GetDependencyResolver();
var uiVisualizerService = dependencyResolver.Resolve<IUIVisualizerService>();
uiVisualizerService.Activate(viewModel, "MainRegion");
But if the context allows you to know the instance of the view model of the view owner of the region where you will inject a view, is strongly
recommended use the Activate overload that allows you to specify the parent view-model. This call will enforce the view models parent-child
relationship:
uiVisualizerService.Activate(viewModel, this, "MainRegion");
Dealing with more than one and only one shell
Actually you are able to inject views (referencing it's view models) in any window. Just like the previous example but in combination with the
experimental extension method Show:
var dependencyResolver = this.GetDependencyResolver();
var uiVisualizerService = dependencyResolver.Resolve<IUIVisualizerService>();
var windowViewModel = new WindowWithRegionViewModel();
uiVisualizerService.Show(windowViewModel, () => { uiVisualizerService.Activate(new
EmployeeViewModel(), windowViewModel, "WindowMainRegion") });
Deactivating a view
To deactivate a view, use the following code:
uiVisualizerService.Deactivate(viewModel);
If you keep your view model alive (see: Keeping view models alive), you can reactivate a deactivated the view using Activate method without
specify the region name.
Deactivating a view automatically
If you close the view model using or or methods, the view that belongs to SaveAndCloseViewModel CancelAndCloseViewModel CloseViewModel
this view model will be automatically deactivated from the region where it is activated.
In order to start using this feature, the only thing you have to do is install an isolated package named , available via Catel.Extensions.Prism
NuGet.
Assume that references an instance of the view-model of a view with MainRegion region specified, so is used as parent view this this
model reference in the previous call.
User interface composition feature that comes with Prism extension is only available in NET40, NET45 and Silverlight 5
Declaring modules
When developing a module in Prism, most of the time you need a base class for all the models that contain the IoC container, an IRegionManager
d more. To make development with prism and Catel as easy as possible, the is included with Catel.There are two versions of the ModuleBase Mo
available, which are described below. duleBase
Generic ModuleBase
The generic module base allows the end-developer to decide what IoC container is used. For example, the developer has the choice whether the
or any other IoC container such as Unity or MEF is used. ServiceLocator
Defining a module
Defining a module is very simple. Just create a new class with the ModuleBase as base class.
public class MyModule : ModuleBase<IServiceLocator>
{
public MyModule()
: base("My module", ServiceLocator.Instance.ResolveType<IModuleTracker>(),
ServiceLocator.Instance)
{
}
protected override T GetService<T>()
{
return Container.ResolveType<T>();
}
}
Handling code when the module is initialized
The contains convenience methods when the module is initialized. Simple override the or methods. ModuleBase OnInitializing OnInitialized
Non-generic ModuleBase
The non-generic base uses the ServiceLocator as default IoC container. This class derives from the generic module base and specifies the Servic
as IoC container. eLocator
Translating or customizing the initialization task messages
Starting with version 3.7, it is possible to fully customize the bootstrapper tasks. Catel now uses the to create the tasks IBootstrapperTaskFactory
instead of the bootstrapper itself.To customize the logic, one has to implement his/her own version of the . The easiest IBootstrapperTaskFactory
way to do this is to derive from the existing and register it in the service locator the bootstrapper is created. BootstrapperTaskFactory before
Customizing the messages
The example below customizes the messages that are shown during the initialization tasks.
public class TranslatedBootstrapperTaskFactory : BootstrapperTaskFactory
{
public override ITask CreateCreateLoggerTask(Action action)
{
return CreateCreateLoggerTask(action, "We are now creating the logger for
you");
}
}
Using the bootstrapper
Catel offers a basic bootstrapper that uses the ServiceLocator as IoC container. This way, it is really simple to create a prism application using
Catel and prism.
The bootstrapper takes lots of work out of hands, and this way a developer can simply focus on what must be done in the bootstrapper (such as
registering the right module catalog).
Using the bootstrapper
This example shows how the bootstrapper is used to define both the shell and the module catalog that looks for modules in the directory Modules
of the application root.
/// <summary>
/// The bootstrapper that will create and run the shell.
/// </summary>
public class MyApplicationBootstrapper : BootstrapperBase
{
/// <summary>
/// Initializes a new instance of the <see cref="MyApplicationBootstrapper"/> class.
/// </summary>
public MyApplicationBootstrapper()
{
LogManager.RegisterDebugListener();
}

/// <summary>
/// Creates the <see cref="T:Microsoft.Practices.Prism.Modularity.IModuleCatalog"/>
used by Prism.
/// </summary>
/// <returns></returns>
protected override IModuleCatalog CreateModuleCatalog()
{
var moduleCatalog = new DirectoryModuleCatalog { ModulePath = @".\Modules"};
moduleCatalog.Initialize();
return moduleCatalog;
}

/// <summary>
/// Creates the shell or main window of the application.
/// </summary>
/// <returns>
/// The shell of the application.
/// </returns>
protected override DependencyObject CreateShell()
{
var shell = new MainWindow();
shell.Show();
return shell;
}
}
Remember to register the the bootstrapper is created TranslatedBootstrapperTaskFactory before
Note that this example only customizes a single action. To customize all the actions, override all methods
Using the bootstrapper with generic shell definition
Most of the time, the method simple defines the main window, creates it and returns it. This can be automated using Catel as well by CreateShell
using the generic bootstrapper. This way, the bootstrapper stays really small and can be kept very simple.
/// <summary>
/// The bootstrapper that will create and run the shell.
/// </summary>
public class MyApplicationBootstrapper : BootstrapperBase<MainWindow>
{
/// <summary>
/// Initializes a new instance of the <see cref="MyApplicationBootstrapper"/>
class.
/// </summary>
public MyApplicationBootstrapper()
{
LogManager.RegisterDebugListener();
}e
/// <summary>
/// Creates the <see
cref="T:Microsoft.Practices.Prism.Modularity.IModuleCatalog"/> used by Prism.
/// </summary>
/// <returns></returns>
protected override IModuleCatalog CreateModuleCatalog()
{
var moduleCatalog = new DirectoryModuleCatalog { ModulePath = @".\Modules"};
moduleCatalog.Initialize();
return moduleCatalog;
}
}
Catel.Extensions.Wcf.Server
Catel.Fody
Fody is an extensible tool for weaving .NET assemblies. For more information about Fody, see . its official website
Enabling Catel.Fody
To enable Catel.Fody to weave assemblies, you need to perform the following steps:
Install theCatel.Fody NuGet package
Update and make sure it contains <Catel /> Weavers.xml
Available functionality
Below are the several options available in Catel.Fody:
Weaving properties
Weaving argument checks
Documentation must be written here
Note that the weavers.xml should be updated automatically when you install the package
Exposing properties on view models
XmlSchema generation
Disabling weaving for specific types or properties
To disable the weaving of types or properties of a type, decorate it with the attribute as shown in the example below: NoWeaving
[NoWeaving]
public class MyClass : ModelBase
{
...
}
Weaving properties
Automatically excluded properties
Specifying default values for weaved properties
How to get automatic change notifications
The for Fody already supports Catel out of the box, but only for property change notifications. However, with the PropertyChanged.Fody plugin
Catel.Fody plugin, it is possible to automatically weave a simple property into a Catel property.
The following property definition:
public string Name { get; set; }
will be weaved into:
public string Name
{
get { return GetValue<string>(NameProperty); }
set { SetValue(NameProperty, value); }
}
public static readonly PropertyData NameProperty = RegisterProperty("Name",
typeof(string));
In the background, Catel.Fody will handle the following workflow:
Find all types in the assembly deriving from (thus also ) ModelBase ViewModelBase
Check if the type has an automatic property backing field (only those properties are weaved)
Add the field for the property PropertyData
Instantiate the field in the static constructor of the type PropertyData
Replace the content of the getter and setter with the appropriate calls to and GetValue SetValue
Automatically excluded properties
By default, Catel.Fody ignores the following properties and types by default because they shouldn't be weaved:
All properties of typeICommand
Properties without an automatically generated backing field
Specifying default values for weaved properties
By default, Catel uses as default values for reference types. For value types, it will use default(T). To specify the default value of a weaved null
property, use the attribute as shown in the example below: DefaultValue
public class Person : ModelBase
{
[DefaultValue("Geert")]
public string FirstName { get; set; }

public string LastName { get; set; }


}
This will be weaved into:
public class Person : ModelBase
{
public string FirstName
{
get { return GetValue<string>(FirstNameProperty); }
set { SetValue(FirstNameProperty, value); }
}
public static readonly PropertyData FirstNameProperty = RegisterProperty("FirstName",
typeof(string), "Geert");
public string LastName
{
get { return GetValue<string>(LastNameProperty); }
set { SetValue(LastNameProperty, value); }
}
public static readonly PropertyData LastNameProperty = RegisterProperty("LastName",
typeof(string), null);
}
How to get automatic change notifications
So, the Fody plugin for Catel automatically searches for the methods. If a method is found, it will automatically be On[PropertyName]Changed
called when the property has changed. For example, the is automatically called when the property is changed in the OnNameChanged Name
example below:
public string Name { get; set; }
private void OnNameChanged()
{
// this method is automatically called when the Name property changes
}
Weaving argument checks
With the Catel.Fody plugin, it is possible to automatically weave a method implementation with its own argument check operations declared via
attributes.
Usage example
Available argument check Catel.Fody attributes
Usage example
1.
2.
3.
4.
The following method definition:
public void DoSomething([NotNullOrEmpty] string myString. [NotNull] object myObject)
{
}
Will be weaved into:
public void DoSomething(string myString, object myObject)
{
Argument.IsNotNullOrEmpty("myString", myString);
Argument.IsNotNull("myObject", myObject);
}
In the background, Catel.Fody will handle the following workflow:
Find all types in the assembly
Find all method of each type
Find all annotated method parameter of each method
Insert as first instructions of the method body the calls to check corresponding methods. Argument
Available argument check Catel.Fody attributes
The following table shows the available argument check attributes and its corresponding class checks method: Argument
Fody attribute Argument method
NotNull Argument.IsNotNull
NotNullOrEmptyArray Argument.IsNotNullOrEmptyArray
NotNullOrEmpty Argument.IsNotNullOrEmpty
NotNullOrWhitespace Argument.IsNotNullOrWhitespace
Match Argument.IsMatch
NotMatch Argument.IsNotMatch
NotOutOfRange Argument.IsNotOutOfRange
Maximum Argument.IsMaximum
Minimal Argument.IsMinimal
OfType Argument.IsOfType
ImplementsInterface Argument.ImplementsInterface
InheritsFromAttribute Argument.InheritsFrom
Exposing properties on view models
The Catel version for WPF provides the attribute. Starting with Catel 3.8, this feature has been moved to Fody to support all platforms Expose
instead of just WPF.One of the features that already existed in Catel before is the . The goal of these attributes is to ViewModelToModelAttribute
easily map properties from a model to the view model so as much of the plumbing (setting/getting properties, rechecking validation, etc) is done
automatically for the developer.
Using the , this is the syntax to map properties automatically: ViewModelToModelAttribute
/// <summary>
/// Gets or sets the person.
/// </summary>
[Model]
public Person Person
{
get { return GetValue<Person>(PersonProperty); }
private set { SetValue(PersonProperty, value); }
}

/// <summary>
/// Register the Person property so it is known in the class.
/// </summary>
public static readonly PropertyData PersonProperty = RegisterProperty("Person",
typeof(Person));

/// <summary>
/// Gets or sets the first name.
/// </summary>
[ViewModelToModel("Person")]
public string FirstName
{
get { return GetValue<string>(FirstNameProperty); }
set { SetValue(FirstNameProperty, value); }
}

/// <summary>
/// Register the FirstName property so it is known in the class.
/// </summary>
public static readonly PropertyData FirstNameProperty = RegisterProperty("FirstName",
typeof(string));
However, if you only define the property just to protect your model, then why should you define the whole property? This is where the FirstName E
property comes in very handy. This attribute internally registers a new dynamic property on the view model, and then uses the xposeAttribute
same technique as the . ViewModelToModelAttribute
Below is the new way you can easily expose properties of a model and protect other properties of the model from the view:
/// <summary>
/// Gets or sets the person.
/// </summary>
[Model]
[Expose("FirstName")]
[Expose("MiddleName")]
[Expose("LastName")]
private Person Person
{
get { return GetValue<Person>(PersonProperty); }
set { SetValue(PersonProperty, value); }
}

/// <summary>
/// Register the Person property so it is known in the class.
/// </summary>
public static readonly PropertyData PersonProperty = RegisterProperty("Person",
typeof(Person));
This is a very cool feature that allows you to protect your model without having to re-define all the properties on the view model. Also, the
validation in the model is automatically synchronized with the view model when you use this attribute.
XmlSchema generation
The .NET framework supports attributes to allow static members to define a custom schema method required for WCF serialization. XmlSchema
Unfortunately this cannot be implemented in Catel itself because it would required too much reflection and the method is static. Therefore this
feature included in Catel.Fody.
There is no need to enable this feature because it is automatically enabled when Catel.Fody is added to a project.
When the is available on the target platform where Catel is used, the changes will be made to classes deriving from XmlSchemaProvider ModelB
ase:
1.Decorate the class withXmlSchemaProvider attribute:
[XmlSchemaProvider("GetXmlSchemaForCatelFodyTestAssemblyInheritedClass")]
public class InheritedClass : BaseClass
{
// rest of the class definition
}
2. Implement the class specific method: GetXmlSchema
[CompilerGenerated]
public static XmlQualifiedName
GetXmlSchemaForCatelFodyTestAssemblyInheritedClass(XmlSchemaSet xmlSchemaSet)
{
Type type = typeof(InheritedClass);
return XmlSchemaManager.GetXmlSchema(type, xmlSchemaSet);
}
Catel.ReSharper
The Catel team developed a plugin for Resharper which makes it easier to write code for Catel. The plugin contains several features:
Checking arguments of a method
Converting regular properties into Catel properties
You got more ideas? ! Let us know
You can grab the plugin at . http://catelresharper.codeplex.com
Checking arguments of a method
Converting regular properties into Catel properties
Checking arguments of a method
If you are not using the Argument class, you are definitely missing something! It allows you to check for a method input and make sure it is valid.
So, instead of writing this:
public void DoSomething(string myInput)
{
if (string.IsNullOrWhitespace(myInput)
{
Log.Error("Argument 'myInput' cannot be null or whitespace");
throw new ArgumentException("Argument 'myInput' cannot be null or whitespace",
"myInput");
}
// custom logic
}
You can write this:
public void DoSomething(string myInput)
{
Argument.IsNotNullOrWhitespace(() => myInput);
// custom logic
}
However, when you are writing lots of code, then even this piece of code can be too much. Thanks to the Catel.Resharper plugin, it is possible to
select the argument (in this case myInput), hit ALT + Enter and generate the code, just like the video below:
Below is a table what argument checks are available per type:
.NET Type Available checks Exception type Constraint text
Any reference type IsNotNull ArgumentNullException The <paramref
name="[paramname]"/> is
<c>null</c>
ImplementsInterface ArgumentException The <paramref
name="[paramname]"/> does not
implement the <see
cref=[interface] /> interface
IsOfType ArgumentException The <paramref
name="[paramname]"/> is not of
type <see cref=[type] />
Array IsNotNullOrEmptyArray ArgumentException The <paramref
name="[paramname]"/> is
<c>null</c> or an empty array
Int / decimal / double / float IsNotOutOfRange ArgumentOutOfRangeException The <paramref
name="[paramname]"/> is not
between <c>[min]</c> and
<c>[max]</c>
IsMinimal ArgumentOutOfRangeException The <paramref
name="[paramname]"/> is
smaller than <c>[value]</c>
IsMaximal ArgumentOutOfRangeException The <paramref
name="[paramname]"/> is larger
than <c>[value]</c>
String IsNotNullOrEmpty ArgumentException The <paramref
name="[paramname]"/> is
<c>null</c> or empty
IsNotNullOrWhitespace ArgumentException The <paramref
name="[paramname]"/> is
<c>null</c> or whitespace
IsMatch ArgumentException The <paramref
name="[paramname]"/> doesnt
match with pattern
<c><![CDATA[[pattern]]]></c>.
IsNotMatch ArgumentException The <paramref
name="[paramname]"/> does
match with pattern
<c><![CDATA[[pattern]]]></c>.
Guid IsNotNullOrEmpty ArgumentException The <paramref
name="[paramname]"/> is
<c>null</c> or empty
Type ImplementsInterface ArgumentException The <paramref
name="[paramname]"/> does not
implement the <see
cref=[interface] /> interface
IsOfType ArgumentException The <paramref
name="[paramname]"/> is not of
type <see cref=[type] />
Converting regular properties into Catel properties
Catel is extremly powerful, but sometimes the property definitions are lots of work to write down. The code snippets already make your life much
easier, but with the Catel.Resharper plugin it might be even easier. You can simply write this code:
public class Person : ModelBase<Person>
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
}
Then hit ALT + Enter and turn properties into Catel properties, which will result in this class:
public class Person : ModelBase<Person>
{
/// <summary>
/// Gets or sets the first name.
/// </summary>
public string FirstName
{
get { return GetValue<string>(FirstNameProperty); }
set { SetValue(FirstNameProperty, value); }
}

/// <summary>
/// Register the FirstName property so it is known in the class.
/// </summary>
public static readonly PropertyData FirstNameProperty = RegisterProperty("FirstName",
typeof(string));

/// <summary>
/// Gets or sets the middle name.
/// </summary>
public string MiddleName
{
get { return GetValue<string>(MiddleNameProperty); }
set { SetValue(MiddleNameProperty, value); }
}

/// <summary>
/// Register the MiddleName property so it is known in the class.
/// </summary>
public static readonly PropertyData MiddleNameProperty =
RegisterProperty("MiddleName", typeof(string));

/// <summary>
/// Gets or sets the last name.
/// </summary>
public string LastName
{
get { return GetValue<string>(LastNameProperty); }
set { SetValue(LastNameProperty, value); }
}

/// <summary>
/// Register the LastName property so it is known in the class.
/// </summary>
public static readonly PropertyData LastNameProperty = RegisterProperty("LastName",
typeof(string));
}
Reference documentation
Reference documentation is available via NuDoc:
http://www.nudoq.org/#/Projects/Catel
Note that it is only possible to use this feature on classes deriving from , such as ModelBase ViewModelBase

Anda mungkin juga menyukai