> For the complete documentation index, see [llms.txt](https://docs.radicalframework.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.radicalframework.com/upgrade-guides/3.x-to-4.0.0.md).

# Radical.Windows 3.x to 4.0.0

Radical.Windows 4.0.0 is a major release: it moves to .NET 10 and Radical 3.0, adopts the async-only message broker, removes APIs that have been obsolete since 2.x, and enables validation by default.

## .NET 10

Radical.Windows 4.0.0 targets `net10.0-windows`. .NET 8 support ends on November 10, 2026, and applications using Radical.Windows 4.0.0 must target .NET 10:

```xml
<TargetFramework>net10.0-windows</TargetFramework>
```

## Radical 3.0 and the async-only message broker

Radical.Windows 4.0.0 requires Radical 3.0, whose message broker is async-only: subscribers return a `Task`, standalone handlers implement `HandleAsync`, and publishers use `DispatchAsync` and `BroadcastAsync`. Follow the [async-only message broker upgrade guide](/upgrade-guides/async-message-broker.md), and the [changes for WPF and Avalonia applications](/upgrade-guides/async-message-broker/async-message-broker-ui.md):

* `RadicalApplication.Shutdown()` is obsolete with an error, and will be removed in 5.0.0: use `await RadicalApplication.ShutdownAsync()`, which awaits the `ApplicationShutdownRequested` subscribers before checking whether they canceled the shutdown.
* The infrastructure's built-in messages, such as `ViewLoaded`, are still broadcast fire-and-forget. Their subscribers and handlers follow the new signatures.

Radical 3.0 also removes members that were obsolete in 2.x, such as `IRequireValidationCallback<T>` and the `As<T>` extension methods. The [Radical 3.0.0 release notes](https://github.com/RadicalFx/Radical/releases/tag/3.0.0) list them.

## Async commands

[`DelegateCommand`](/presentation/delegate-command.md#asynchronous-execution) has an `OnExecute(Func<object, Task>)` overload and an `ExecuteAsync` method, and [`AutoCommandBinding`](/markup-extensions/auto-command-binding.md) binds view model methods returning a `Task`. The command awaits the execution: while it runs, the command can't execute again, so bound controls are disabled, and exceptions go to the application's unhandled exception handler. Synchronous commands and `void` methods are unchanged.

## ViewModelClosing

`ViewModelClosing` is obsolete with an error, and will be removed in 5.0.0. The infrastructure never published it. To cancel closing a view, implement `IExpectViewClosingCallback`, as described in [callback expectations](/presentation/iview-resolver/view-life-cycle-events/callback-expectations.md).

## ApplicationBootstrapper

`ApplicationBootstrapper` and `ApplicationBootstrapper<TMainView>`, obsolete since 2.0.0, are now obsolete with an error: code using them no longer compiles. They will be removed in 5.0.0. Use the `AddRadicalApplication` extension method instead, as described in the [1.x to 2.0.0 upgrade guide](/upgrade-guides/1.x-to-2.0.0.md) and in [application configuration](/presentation/boot-process/application-configuration.md):

```csharp
public partial class App : Application
{
    public App()
    {
        this.AddRadicalApplication<MainView>(configuration =>
        {
            //configuration options previously set on the ApplicationBootstrapper
        });
    }
}
```

## Validation is always enabled

`AbstractViewModel` and `AbstractMementoViewModel` now implement `IRequireValidation`. Setting a validation service is enough to enable validation, and view models no longer need to implement `IRequireValidation` explicitly. Existing view models that do keep working.

View models without a validation service use the default `NullValidationService`, which never reports errors.

## Removed APIs

| Removed                                                                             | Replacement                                                                                 |
| ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| `Repeat`                                                                            | A `DispatcherTimer`.                                                                        |
| `Wait`                                                                              | A `DispatcherTimer`, stopped in its first `Tick`.                                           |
| `AbstractViewModel.MoveFocusTo<T>(Expression<Func<T>>)`                             | `MoveFocusTo(nameof(Property))`                                                             |
| `AbstractMementoViewModel.MoveFocusTo<T>(Expression<Func<T>>)`                      | `MoveFocusTo(nameof(Property))`                                                             |
| `ObservableEntityCollection<T>.OnPropertyChanged<TValue>(Expression<Func<TValue>>)` | `OnPropertyChanged(nameof(Property))`                                                       |
| `DelegateValidationService`                                                         | A class inheriting from `AbstractValidationService` that overrides `OnValidate`, see below. |
| The `IConventionsHandler.DefaultViewDataContextSearchBehavior` setter               | None: the value is always `ViewDataContextSearchBehavior.LocalOnly`.                        |

`DelegateValidationService` can be replaced by:

```csharp
class CallbackValidationService(Func<IEnumerable<ValidationError>> callback) : AbstractValidationService
{
    protected override IEnumerable<ValidationError> OnValidate() => callback();
}
```

## XML namespaces

The legacy `http://schemas.topics.it/wpf/radical/windows/*` XML namespaces, deprecated in 2.0.0, have been removed. Use the `http://schemas.radicalframework.com/windows/*` ones:

| Removed                                                   | Replacement                                              |
| --------------------------------------------------------- | -------------------------------------------------------- |
| `http://schemas.topics.it/wpf/radical/windows`            | `http://schemas.radicalframework.com/windows`            |
| `http://schemas.topics.it/wpf/radical/windows/behaviors`  | `http://schemas.radicalframework.com/windows/behaviors`  |
| `http://schemas.topics.it/wpf/radical/windows/controls`   | `http://schemas.radicalframework.com/windows/controls`   |
| `http://schemas.topics.it/wpf/radical/windows/converters` | `http://schemas.radicalframework.com/windows/converters` |
| `http://schemas.topics.it/wpf/radical/windows/effects`    | `http://schemas.radicalframework.com/windows/effects`    |
| `http://schemas.topics.it/wpf/radical/windows/input`      | `http://schemas.radicalframework.com/windows/input`      |
| `http://schemas.topics.it/wpf/radical/windows/markup`     | `http://schemas.radicalframework.com/windows/markup`     |
| `http://schemas.topics.it/wpf/radical/windows/regions`    | `http://schemas.radicalframework.com/windows/regions`    |
