diff --git a/_config.yml b/_config.yml index 599b4cb4..07d6fcd7 100644 --- a/_config.yml +++ b/_config.yml @@ -470,3 +470,7 @@ authors: name: Ilkka Jokela email: d250169ca75ef01273b214cc3767ec3d url: https://www.linkedin.com/in/ilkka-jokela/ + solita-123345: + name: Kimmo Tomminen + email: af60ec62d2bf274c0f5ab042b8eab3a8 + url: https://www.linkedin.com/in/kimmo-tomminen-68327a223/ diff --git a/_posts/2025-11-21-mvvm.md b/_posts/2025-11-21-mvvm.md new file mode 100644 index 00000000..910f6d84 --- /dev/null +++ b/_posts/2025-11-21-mvvm.md @@ -0,0 +1,436 @@ +--- +layout: post +title: Using Model-View-ViewModel pattern for UI development in 2025 +author: solita-123345 +excerpt: > + My experiences and collected information about using MVVM design pattern in UI design and development with practical examples. +tags: + - JavaScript + - TypeScript + - Vue.js + - Knockout.js + - Angular + - Blazor + - WPF + - MVVM + - Model-View-ViewModel + - C# +--- + +In this blog post we will see how Model-View-ViewModel UI design pattern can be used with different JavaScript, TypeScript, and .NET Core UI frameworks that are used today in many projects. + +MVVM design pattern consists of three connected layers, where topmost is View, that has connection with data binding to ViewModel, which handles Model preparation and needed UI tasks for presenting the data in UI. Models can be data bound to UI like ViewModels. Models are data and domain representations of the actual domain or data models like data entities, or just conceptual models that are connected in example to REST API controllers and/or repositories. In theory, model can contain more information than is stored in the single data entity. + +For the current state of the view for MVVM usage, and available up-to-date frameworks, Microsoft 365 Copilot was used. Copilot provided information about currently available MVVM supporting JavaScript and TypeScript frameworks for UI development. M365 Copilot provided a list of available alternatives for JS and TS MVVM usage, which was compared against already outdated not very well supported Knockout.js framework, that is most pure implementation of MVVM supporting frameworks for JS and TS. Currently available and popular MVVM JS and TS frameworks included Vue.js, Angular, and React, of which React does not really support MVVM design pattern. + +For .NET Core based UI projects, there are two examples for MVVM use from original Windows Presentation Foundation (WPF) MVVM Windows application framework to newer Blazor ASP.NET Core framework, which both can use the same ViewModels and Models, and create different View layer implementations for the different environments, web and desktop app. Both .NET Core UI framework implementations support data binding to ViewModels and Models. + + +## Model-View-ViewModel pattern + +Model-View-ViewModel pattern was introduced for Windows Presentation Foundation (WPF) use in .NET and was also designed in 2005 for HTML use. In this design pattern the UI design is differentiated from program code as XAML or HTML layer, where UI design can be changed without changing the ViewModel or Model code. + +From earlier experience, this kind of design is very useful when developer or designer wants to create different views of the same ViewModel and Models, like product list view, product overlay view, and product details view. All these views can use same ViewModel and Model implementations, and view can be totally different and contain all or part of the commands created for domain logic. + +MVVM pattern uses commands to execute domain commands that are not directly attached to UI. Commands can have parameters, that are used to filter data from ViewModel state and make changes to data storage or do other kind of domain logic functionalities. Command pattern also makes it possible to use Command Query Responsibility Segregation (CQRS) design pattern that differentiates command execution and queries by using concepts like Write model and Read model, which both can reside in different service interfaces. Also, Read model can be seperated data store from write store when using Event-driven architecture like Azure Event Hub event data streaming service. + +MVVM also uses data-binding that can be done with one way, one way to source, or two-way data-binding modes, where all changes in example to product name field, are updated to other places and views that have data-binding to the same Model. Different frameworks support different modes of data-binding. + + + +## JavaScript and TypeScript MVVM support in detail + +When asking guidance from M365 Copilot, Copilot provided following diagram about MVVM usage for different JS and TS UI frameworks. + + + +Knockout.js and Vue.js provide possibility to create ViewModels, Views, and Models for MVVM style based application. Angular has components model, which is replacing ViewModel, but works similarly. + +Below is a table that was provided by GitHub Copilot, that describes the MVVM support for different UI frameworks. + + +| Framework | MVVM Support | Data Binding | Notes | +|--------------|--------------|--------------|------------------------------| +| Knockout.js | Yes | Two-way | Pure MVVM, less maintained | +| Vue.js | Partial | Two-way | Uses ViewModel-like pattern | +| Angular | Partial | One/two-way | Uses components, not pure MVVM | +| React | No | One-way | Follows MV* patterns | + +Table shows that Knockout.js that has been used more in earlier years, and that was included in the project templates in web projects for .NET, is not maintained so well anymore. Second and third options, Vue.js is a framework that can be used to create MVVM applications client side in TypeScript or JavaScript. + +Knockout.js, Vue.js and Angular provide possibility to use Two-way data-binding. Because React is not MVVM supporting framework, this the usage of React is not described more in this blog post. + + +## .NET Core MVVM support in detail + +Below GitHub Copilot has created diagram that describes two .NET Core based case examples with WPF Windows application and Blazor Web application that are using MVVM pattern. + +```mermaid +flowchart LR + subgraph Shared + Shared_VM["ViewModel Assembly (C#)"] + Shared_Model["Model Assembly (C#)"] + end + + subgraph WPF + WPF_Page1["XAML Page 1"] + WPF_Page2["XAML Page 2"] + WPF_View["XAML View"] + WPF_Page1 --> WPF_View + WPF_Page2 --> WPF_View + + %% pages reference shared viewmodels/models + WPF_Page1 ---|references| Shared_VM + WPF_Page2 ---|references| Shared_VM + WPF_Page1 ---|references| Shared_Model + WPF_Page2 ---|references| Shared_Model + + WPF_View -- "Data Binding / Commands" --> Shared_VM + Shared_VM --> Shared_Model + end + + subgraph Blazor + Blazor_Page1["Razor Page 1 (.razor)"] + Blazor_Page2["Razor Page 2 (.razor)"] + Blazor_View["Razor Component (.razor)"] + Blazor_Page1 --> Blazor_View + Blazor_Page2 --> Blazor_View + + %% pages reference shared viewmodels/models + Blazor_Page1 ---|references| Shared_VM + Blazor_Page2 ---|references| Shared_VM + Blazor_Page1 ---|references| Shared_Model + Blazor_Page2 ---|references| Shared_Model + + Blazor_View -- "Data Binding / Commands" --> Shared_VM + Shared_VM --> Shared_Model + end + + WPF_View ---|references| Shared_VM + WPF_View ---|references| Shared_Model + Blazor_View ---|references| Shared_VM + Blazor_View ---|references| Shared_Model +``` + +In past projects, there have been successful experiences about creating two user interface projects with same ViewModel library, like it is shown in the above diagram. This means that same business logic, and same UI logic can be used in Windows application and in Web applications with Blazor and WPF. + +| Framework / UI Type | MVVM Support | Data Binding | Shared ViewModel/Model Support | Notes | +|---------------------|--------------|----------------------|-------------------------------|--------------------------------------------| +| WPF | Yes | One-way, Two-way | Yes | Native MVVM, strong XAML binding | +| Blazor | Yes | One-way, Two-way | Yes | MVVM by convention, supports shared logic | + +Both UI frameworks for .NET Core support MVVM design style project fully. In this example case it is also possible to use both for same business case, if native workstation application and web application both are needed, in example in transition phase. + + +## Experimentation code examples + +For this blog post M365 Copilot provided code examples for JavaScript UI frameworks, for View, ViewModel, and Model layers, and for different pages in the application. + +### Knockout.js (Outdated pure MVVM example) + +Below we can see product UI example code that was created for Knockout.js by M365 Copilot. + +#### View (pages and single overlay view) +```html + + +
+Price:
+Discounted:
+ + +Price:
+Discounted:
+ +Price: ${{ p.price }}
+Discounted: ${{ (p.price * 0.9).toFixed(2) }}
+ + +{{ product.description }}
+Price: ${{ product.price }}
+Discounted: ${{ (product.price * 0.9).toFixed(2) }}
+ +Price: ${p.price}
+Discounted: ${(p.price * 0.9).toFixed(2)}
+ + +{selectedProduct.description}
+Original Price: ${selectedProduct.price}
+Discounted Price: ${(selectedProduct.price * 0.9).toFixed(2)}
+ +{product.description}
+Price: ${product.price}
+Discounted: ${(product.price * 0.9).toFixed(2)}
+ +