Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions blazor/common/migration/wpf-blazor-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ Data binding is a fundamental concept in both WPF and Blazor, but the implementa

In WPF, the `DataContext` property is a powerful mechanism that enables declarative data binding. You set the `DataContext` to a view model instance that typically implements `INotifyPropertyChanged`, and XAML bindings automatically resolve against this object. This allows UI elements to automatically update when the underlying data changes.

When the data source implements `INotifyCollectionChanged` (such as `ObservableCollection<T>`), the `SfDataGrid` control automatically refreshes the UI when items are added, removed, or when the list is cleared. However, when using a standard `List<T>`, the grid will not automatically refresh when the collection is modified.
When the data source implements [INotifyCollectionChanged](https://learn.microsoft.com/en-us/dotnet/api/system.collections.specialized.inotifycollectionchanged?view=net-10.0) (such as [ObservableCollection<T>](https://learn.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.observablecollection-1?view=net-10.0)), the [SfDataGrid](https://www.syncfusion.com/wpf-controls/datagrid) control automatically refreshes the UI when items are added, removed, or when the list is cleared. However, when using a standard `List<T>`, the grid will not automatically refresh when the collection is modified.

{% tabs %}
{% highlight c# tabtitle="MainWindow.xaml.cs" %}
Expand Down Expand Up @@ -230,7 +230,7 @@ public class Order

In Blazor, data flows through component parameters and the `@bind` directive. Instead of a global `DataContext`, each component explicitly defines its data dependencies through parameters. This approach provides more explicit data flow, better component composition, and type-safe binding.

The [Blazor DataGrid](https://www.syncfusion.com/blazor-components/blazor-datagrid) supports binding to any `IEnumerable` collection such as `List<T>`, `ObservableCollection<T>`, collections of `ExpandoObject`, `DynamicObject`, or `DataTable`, directly to the [DataSource](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.SfGrid-1.html#Syncfusion_Blazor_Grids_SfGrid_1_DataSource) property of the Grid. When using `ObservableCollection<T>`, the component automatically reflects changes made externally. For standard `List<T>`, call the [Refresh](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.SfGrid-1.html#Syncfusion_Blazor_Grids_SfGrid_1_Refresh_System_Boolean_) method to reflect externally made changes to avoid tracking changes for performance considerations.
The [Blazor DataGrid](https://www.syncfusion.com/blazor-components/blazor-datagrid) supports binding to any `IEnumerable` collection such as `List<T>`, [ObservableCollection<T>](https://learn.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.observablecollection-1?view=net-10.0), collections of [ExpandoObject](https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=net-10.0), [DynamicObject](https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.dynamicobject?view=net-10.0), or `DataTable`, directly to the [DataSource](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.SfGrid-1.html#Syncfusion_Blazor_Grids_SfGrid_1_DataSource) property of the Grid. When using `ObservableCollection<T>`, the component automatically reflects changes made externally. For standard `List<T>`, call the [Refresh](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.SfGrid-1.html#Syncfusion_Blazor_Grids_SfGrid_1_Refresh_System_Boolean_) method to reflect externally made changes to avoid tracking changes for performance considerations.

{% tabs %}
{% highlight razor tabtitle="Orders.razor" %}
Expand Down Expand Up @@ -272,14 +272,14 @@ The [Blazor DataGrid](https://www.syncfusion.com/blazor-components/blazor-datagr
{% endhighlight %}
{% endtabs %}

**Key differences in data binding:**
**Key differences in data binding**

| Aspect | WPF DataContext | Blazor Parameters |
|---|---|---|
| Scope | Global to window/control hierarchy | Explicit per component |
| Binding declaration | `{Binding PropertyName}` in XAML | `@PropertyName` or `@bind` in Razor |
| Property changes | `INotifyPropertyChanged` triggers UI updates | Component state changes trigger re-renders |
| Collection type | `ObservableCollection<T>` for automatic notifications | `List<T>` or `ObservableCollection<T>` (for `ObservableCollection<T>`, automatic notifications; for `List<T>`, call `Refresh()` method) |
| Collection type | `ObservableCollection<T>` for automatic notifications | `List<T>` or `ObservableCollection<T>` (for `ObservableCollection<T>`, automatic notifications; for `List<T>`, call [Refresh()](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.SfGrid-1.html#Syncfusion_Blazor_Grids_SfGrid_1_Refresh_System_Boolean_) method) |
| Type safety | Resolved at runtime | Type-safe at compile time |
| Two-way binding | `{Binding PropertyName, Mode=TwoWay}` | `@bind-Value="@PropertyName"` |
| Update notification | Automatic via `PropertyChanged` event | Automatic for `ObservableCollection<T>` or manual via `Refresh()` or re-assignment for `List<T>` |
Expand Down Expand Up @@ -462,7 +462,7 @@ Blazor components render as standard HTML and CSS in the browser, requiring a sh
{% endhighlight %}
{% endtabs %}

**Key differences:**
**Key differences**

| Aspect | WPF | Blazor |
|---|---|---|
Expand All @@ -473,7 +473,7 @@ Blazor components render as standard HTML and CSS in the browser, requiring a sh
| Overflow handling | Controlled by layout panels (StackPanel, Grid, DockPanel) | CSS overflow properties |
| Rendering | GPU rendering via native engine | Browser rendering engine (hardware-accelerated) |

**Migration strategy:**
**Migration strategy**

* Replace fixed pixel dimensions with flexible CSS units (percentages, em, rem) where appropriate
* Use CSS Flexbox or CSS Grid in place of WPF layout panels (StackPanel, Grid, DockPanel)
Expand All @@ -485,7 +485,7 @@ Blazor components render as standard HTML and CSS in the browser, requiring a sh

**WPF lifecycle**

WPF controls follow a predictable, synchronous lifecycle: `Loaded`, property change notifications via `DependencyProperty`, `DataContextChanged`, and `Unloaded`. Event handling is direct through routed events and delegates, executing synchronously on the UI thread. This ensures tight control over component state but can block the UI if long-running operations aren't handled properly.
WPF controls usually follow a synchronous lifecycle. Events like `Loaded` and `Unloaded` are used to start work, clean up resources, and respond to user actions directly on the UI thread. This approach is straightforward, but long-running tasks can block the interface if they are not handled carefully.

{% tabs %}
{% highlight c# tabtitle="MainWindow.xaml.cs" %}
Expand Down Expand Up @@ -523,7 +523,7 @@ public class MainWindow : Window

**Blazor lifecycle**

Blazor components use an asynchronous lifecycle model designed for server-client communication: `OnInitialized` / `OnInitializedAsync`, `OnParametersSet` / `OnParametersSetAsync`, and `OnAfterRender` / `OnAfterRenderAsync`. Event handling is through `EventCallback` delegates, supporting both synchronous and asynchronous operations. This asynchronous model prevents blocking the server-side interactive connection but requires a shift in thinking about component initialization and updates.
Blazor uses an asynchronous lifecycle that fits browser rendering and server communication. Common lifecycle methods include `OnInitializedAsync`, `OnParametersSetAsync`, and `OnAfterRenderAsync`. Event handling is also flexible, so component logic can run synchronously or asynchronously depending on the task.

{% tabs %}
{% highlight razor tabtitle="Sample.razor" %}
Expand Down Expand Up @@ -612,26 +612,26 @@ Blazor components use an asynchronous lifecycle model designed for server-client
{% endhighlight %}
{% endtabs %}

**Key differences:**
**Key differences**

| Aspect | WPF | Blazor |
|---|---|---|
| Initialization | Synchronous `Loaded` event | Asynchronous `OnInitializedAsync` |
| Parameter changes | `DependencyProperty` change notifications | `OnParametersSetAsync` |
| Post-render operations | Direct event handler execution | `OnAfterRenderAsync` |
| Event handling | Synchronous routed events and delegates | Direct EventCallback properties (e.g., `OnActionBegin`, `OnActionComplete`) |
| Event handling | Synchronous routed events and delegates | Direct `EventCallback` properties such as `OnActionBegin` and `OnActionComplete` |
| Cleanup | `Unloaded` event | `IAsyncDisposable` interface |
| Rendering model | Immediate, blocking in UI thread | Server-side with SignalR client updates |
| Performance implications | Blocking operations freeze the UI | Async/await prevents server blocking |

**Migration strategy:**
**Migration strategy**

* Convert synchronous event handlers to asynchronous `EventCallback` methods
* Move initialization logic from `Loaded` to `OnInitializedAsync`
* Use `OnParametersSetAsync` for responding to parameter changes instead of `DependencyProperty` handlers
* Leverage `OnAfterRenderAsync` for DOM-dependent logic and JavaScript interop
* Implement `IAsyncDisposable` and use the `@implements` directive for proper resource cleanup
* **Always use `async`/`await`** in event handlers and lifecycle methods to prevent blocking the interactive server connection
* Always use `async`/`await` in event handlers and lifecycle methods to prevent blocking the interactive server connection
* Test thoroughly for race conditions that may occur due to asynchronous re-rendering

## Run the application
Expand Down