A navigation framework and set of UI components for ReactiveUI-based applications across WPF, Avalonia, MAUI, and WinForms.
CrissCross provides ViewModel-first navigation, hostable navigation surfaces, and a comprehensive WPF UI control set with a strong ReactiveUI focus. It promotes:
- ViewModel-first navigation using ReactiveUI’s IViewFor and WhenActivated
- Host-based navigation via named ViewModelRoutedViewHost containers
- Consistent navigation lifecycle notifications (WhenNavigating/WhenNavigatedTo/From)
- Easy DI/IoC integration via Splat and Microsoft.Extensions.Hosting
- A large library of fluent WPF UI controls and services (dialogs, snackbars, themes)
Supported platforms and packages:
- Core: CrissCross (ReactiveUI helpers and navigation abstractions)
- WPF navigation host: CrissCross.WPF
- WPF UI control library: CrissCross.WPF.UI
- Avalonia host: CrissCross.Avalonia
- .NET MAUI helpers: CrissCross.MAUI
- WinForms host: CrissCross.WinForms
- WPF WebView2 overlay host: CrissCross.WPF.WebView2
- WPF Plot control suite: CrissCross.WPF.Plot
NuGet packages:
Note: Xamarin.Forms support exists in separate projects but for new apps prefer .NET MAUI.
CrissCross builds on ReactiveUI to provide ViewModel-first navigation:
- IRxObject: Base ViewModel type used throughout CrissCross
- IViewFor: ReactiveUI contract mapping VMs to Views
- WhenActivated: ReactiveUI activation lifecycle for Views
- ViewModelRoutedViewHost: Navigation host control that manages a navigation stack and view transitions
- HostName: A host identifier (string) that allows targeting navigation to a specific host
- Navigation lifecycle: WhenNavigating, WhenNavigatedTo, WhenNavigatedFrom via mixins/events
Register your ViewModels and Views with Splat’s Locator or Microsoft.Extensions.DependencyInjection. CrissCross uses the locator to resolve Views for navigation targets.
- Install packages
- CrissCross
- CrissCross.WPF
- CrissCross.WPF.UI (for controls/themes)
- Register ViewModels and Views
public class AppBootstrapper : RxObject
{
public AppBootstrapper()
{
this.BuildComplete(() =>
{
// Example VM/View registrations using Splat
Locator.CurrentMutable.RegisterConstant(new MainViewModel());
Locator.CurrentMutable.Register<IViewFor<MainViewModel>>(() => new MainView());
Locator.CurrentMutable.RegisterConstant(new FirstViewModel());
Locator.CurrentMutable.Register<IViewFor<FirstViewModel>>(() => new FirstView());
Locator.CurrentMutable.SetupComplete();
});
}
}- Create a navigation host (NavigationWindow)
public partial class MainWindow : NavigationWindow<MainWindowViewModel>
{
public MainWindow()
{
InitializeComponent(); // Ensure x:Name is set on the Window (e.g., "mainWindow")
this.WhenActivated(d =>
{
// Bind back command, etc
NavBack.Command = ReactiveCommand.Create(() => this.NavigateBack(), CanNavigateBack).DisposeWith(d);
// Navigate to a start VM
this.NavigateToView<MainViewModel>();
});
}
}- Navigate from a ViewModel
public class MainViewModel : RxObject
{
public MainViewModel()
{
this.BuildComplete(() =>
{
// Target a specific host by name (Window x:Name)
this.NavigateToView<FirstViewModel>("mainWindow");
});
}
}- Create a View
public partial class MainView : ReactiveUserControl<MainViewModel>
{
public MainView()
{
InitializeComponent();
this.WhenActivated(_ => { /* bindings, commands */ });
}
}-
NavigationWindow (WPF): A Window that exposes a ViewModelRoutedViewHost and transition support
- Properties: Transition, NavigateBackIsEnabled
- Exposes CanNavigateBack observable and NavigateBack() helper
-
FluentNavigationWindow (WPF UI): A fluent-styled NavigationWindow with additional title content areas and Transition
-
NavigationUserControl (WPF UI, Avalonia): A hostable control version of the navigation container (for regions/panels)
-
ViewModelRoutedViewHost (WPF): Core host implementation
- Navigate(contract, parameter)
- Navigate(IRxObject vm, contract, parameter)
- NavigateAndReset variants
- NavigateBack(parameter)
- CanNavigateBackObservable, NavigationStack
- Lifecycle events routed via ViewModelRoutedViewHostMixins:
- WhenNavigating: preview/cancel navigation
- WhenNavigatedTo/From: after navigation completes
-
HostName: Set on NavigationWindow/NavigationUserControl (typically from x:Name) to route cross-host navigation
- From code-behind: this.NavigateToView(hostName?, parameter?)
- From ViewModel: this.NavigateToView(hostName, parameter?)
- NavigateBack(hostName?, parameter?) and CanNavigateBack(hostName?) helpers
A comprehensive set of fluent controls and services designed for ReactiveUI apps. Highlights include:
- NavigationView, BreadcrumbBar and navigation controls/models
- Dialogs: ContentDialog, MessageBox, async variants
- Notifications: Snackbar, InfoBar, InfoBadge
- Input: AutoSuggestBox, NumberBox, PasswordBox, ToggleSwitch, TimePicker, DatePicker
- Lists and virtualization: ListView, VirtualizingGridView, VirtualizingWrapPanel
- Layout/containers: Card, CardExpander, GroupBox, Grid, StackPanel
- Media: GifImage (animation), Image
- PersonPicture, RatingControl, ProgressRing, AppBar, TitleBar, Window enhancements
- Color controls: ColorSelector suite (sliders, dual pickers), HexColorTextBox, and ColorPicker
- Typography and iconography: FontIcon, SymbolIcon, IconSource
- Themes and appearance utilities
Include the control resources by merging the ControlsDictionary:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ui:ControlsDictionary />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>- ApplicationThemeManager and SystemThemeWatcher for light/dark and system theme integration
- Resource dictionaries for typography, colors, focus, default styles
- ThemeService and IThemeService for programmatic control
- ContentDialogService: Show dialogs and await results
- SnackbarService: Host snackbars with extension helpers
- PageService (WPF UI): Resolve pages by type for embedded/hosted scenarios
For page-based apps using WPF UI, use the host builder extensions:
private static readonly IHost _host = Host.CreateDefaultBuilder()
.ConfigureCrissCrossForPageNavigation<MainWindow, DashboardPage>()
.ConfigureServices((context, services) =>
{
services.AddSingleton<MainWindowViewModel>();
services.AddSingleton<DashboardPage>().AddSingleton<DashboardViewModel>();
services.AddSingleton<DataPage>().AddSingleton<DataViewModel>();
services.AddSingleton<SettingsPage>().AddSingleton<SettingsViewModel>();
services.AddSingleton<LoginPage>().AddSingleton<LoginViewModel>();
})
.Build();Wire up and start in App.xaml.cs, then navigate using IPageService or NavigationView.
A powerful navigation control that manages a journal and hierarchical navigation stack:
- Navigate(Type pageType, object? dataContext)
- Navigate(string pageIdOrTargetTag, object? dataContext)
- NavigateWithHierarchy(Type pageType, object? dataContext)
- ReplaceContent(Type pageType) / ReplaceContent(UIElement)
- GoBack(), GoForward() (where implemented), ClearJournal()
- Events: Navigating (cancelable), Navigated, BackRequested, SelectionChanged, PaneOpened/Closed
The control maintains a NavigationStack and history so you can build rich shell navigation experiences.
- NavigationUserControl (host)
- ViewModelRoutedViewHost equivalent with CanNavigateBack observable and HostName
- Use ReactiveUI’s WhenActivated and Splat for registration as in WPF
public partial class MainUserControl : NavigationUserControl<MainWindowViewModel>
{
public MainUserControl()
{
InitializeComponent();
this.WhenActivated(d =>
{
this.NavigateToView<MainViewModel>();
_NavBack!.Command = ReactiveCommand.Create(() => this.NavigateBack(), this.CanNavigateBack()).DisposeWith(d);
});
}
}MAUI helpers integrate with ReactiveUI.Maui. Register your VMs/Views with DI and navigate using the same NavigateToView/Back helpers where applicable. Prefer this approach over Xamarin.Forms for new apps.
Packages:
- CrissCross.MAUI
- ReactiveUI.Maui
- ViewModelRoutedViewHost for WinForms
- ReactiveUserControl usage with WhenActivated
- Navigate using the same helper mixins
CrissCross.WPF.WebView2 provides a NavigationWebView that hosts WebView2 while allowing WPF content overlays:
xmlns:webv="https://github.com/reactivemarbles/CrissCross"
<webv:WebView2Wpf x:Name="WebView2Wpf" AutoDispose="True">
<!-- overlay WPF content here -->
</webv:WebView2Wpf>WebView2Wpf.Source = new Uri("https://www.reactiveui.net/");CrissCross.WPF.Plot adds Reactive plotting components:
- Bind reactive sequences
- Multiple series, Y-axes, crosshairs
- Zoom/pan, drag zoom selection
- Visibility toggles, auto/manual scale
Install: Install-Package CrissCross.WPF.Plot
Persist and track control/window state:
- Tracker service with attributes (Trackable, PersistOn, StopTrackingOn)
- Example usage in App.xaml.cs wiring window size/position persistence
_tracker?.Configure<MainWindow>()
.Id(w => w.Name, $"[Width={SystemParameters.VirtualScreenWidth},Height{SystemParameters.VirtualScreenHeight}]")
.Properties(w => new { w.Height, w.Width, w.Left, w.Top, w.WindowState })
.PersistOn(w => nameof(w.Closing))
.StopTrackingOn(w => nameof(w.Closing));- ColorSelector suite (HSV/HSL/RGB sliders, square pickers, hex entry, dual color with hints)
- ColorPicker control: A simple RGBA + Hex picker with a live preview
- GifImage with animation control and performance-oriented decoding/animation components
- CrissCross.WPF.UI.Test: WPF UI test app with page navigation
- CrissCross.WPF.Test: WPF navigation sample
- CrissCross.Avalonia.Test.*: Avalonia samples (desktop, mobile)
- CrissCross.MAUI.Test: MAUI sample
- CrissCross.WPF.Plot.Test: Plot samples
- CrissCross.WPF.WebView2.Test: WebView2 overlay usage
- CrissCross.WPF.UI.Gallery: Control gallery showcasing WPF UI controls
Browse these projects to see real-world usage patterns, navigation setup, and control bindings.
Prevent multiple instances using Make.SingleInstance in App:
protected override void OnStartup(StartupEventArgs e)
{
Make.SingleInstance("MyUniqueAppName ddd81fc8-9107-4e33-b848-cac4c3ec3d2a");
base.OnStartup(e);
}Issues and PRs are welcome. Please include platform, .NET version, and a minimal repro where applicable.
MIT © ReactiveUI Association Incorporated