I-Synergy.Framework.UI.WPF
2026.11114.12249
Prefix Reserved
dotnet add package I-Synergy.Framework.UI.WPF --version 2026.11114.12249
NuGet\Install-Package I-Synergy.Framework.UI.WPF -Version 2026.11114.12249
<PackageReference Include="I-Synergy.Framework.UI.WPF" Version="2026.11114.12249" />
<PackageVersion Include="I-Synergy.Framework.UI.WPF" Version="2026.11114.12249" />
<PackageReference Include="I-Synergy.Framework.UI.WPF" />
paket add I-Synergy.Framework.UI.WPF --version 2026.11114.12249
#r "nuget: I-Synergy.Framework.UI.WPF, 2026.11114.12249"
#:package I-Synergy.Framework.UI.WPF@2026.11114.12249
#addin nuget:?package=I-Synergy.Framework.UI.WPF&version=2026.11114.12249
#tool nuget:?package=I-Synergy.Framework.UI.WPF&version=2026.11114.12249
I-Synergy Framework UI WPF
Windows Presentation Foundation (WPF) UI framework for building modern desktop applications on Windows. This package provides a complete WPF implementation of the I-Synergy Framework UI services, controls, and patterns with support for Windows 7, 8, and 10+.
Features
- Full WPF desktop support for Windows 7+, 8+, and 10+
- Dialog service with MessageBox and custom dialog support
- Navigation service with frame-based navigation
- Theme service with dynamic accent colors and styles
- File service with Windows file dialogs
- Clipboard service for Windows clipboard operations
- Update service for application updates
- Custom controls (BladeView, Console, ImageBrowser, Menu, Tiles, ErrorPresenter)
- Behaviors using Microsoft.Xaml.Behaviors.Wpf
- 40+ dynamic theme palettes with XAML resource dictionaries
- Splash screen support with customizable UI
Installation
Install the package via NuGet:
dotnet add package I-Synergy.Framework.UI.WPF
Quick Start
1. Configure Application
Setup your WPF application with I-Synergy Framework:
using ISynergy.Framework.UI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
public partial class App : Application
{
private IHost _host;
protected override async void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
_host = Host.CreateDefaultBuilder()
.ConfigureServices((context, services) =>
{
// Core services
services.AddSingleton<ILanguageService, LanguageService>();
services.AddSingleton<IMessengerService, MessengerService>();
services.AddSingleton<IBusyService, BusyService>();
// WPF services
services.AddSingleton<IDialogService, DialogService>();
services.AddSingleton<INavigationService, NavigationService>();
services.AddSingleton<IThemeService, ThemeService>();
services.AddSingleton<IFileService<FileResult>, FileService>();
services.AddSingleton<IClipboardService, ClipboardService>();
services.AddSingleton<IUpdateService, UpdateService>();
// ViewModels
services.AddTransient<MainViewModel>();
services.AddTransient<ShellViewModel>();
})
.Build();
await _host.StartAsync();
// Apply theme
var themeService = _host.Services.GetRequiredService<IThemeService>();
themeService.ApplyTheme();
// Show main window
var mainWindow = _host.Services.GetRequiredService<MainWindow>();
mainWindow.Show();
}
protected override async void OnExit(ExitEventArgs e)
{
await _host.StopAsync();
_host.Dispose();
base.OnExit(e);
}
}
2. Create XAML Windows with ViewModels
<Window x:Class="MyApp.MainWindow"
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:vm="clr-namespace:MyApp.ViewModels"
d:DataContext="{d:DesignInstance Type=vm:MainViewModel}"
Title="{Binding Title}"
Height="600" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Menu Grid.Row="0">
<MenuItem Header="File">
<MenuItem Header="New" Command="{Binding NewCommand}"/>
<MenuItem Header="Open" Command="{Binding OpenCommand}"/>
<MenuItem Header="Save" Command="{Binding SaveCommand}"/>
<Separator/>
<MenuItem Header="Exit" Command="{Binding ExitCommand}"/>
</MenuItem>
<MenuItem Header="Edit">
<MenuItem Header="Settings" Command="{Binding SettingsCommand}"/>
</MenuItem>
</Menu>
<Frame Grid.Row="1"
x:Name="MainFrame"
NavigationUIVisibility="Hidden"/>
<StatusBar Grid.Row="2">
<StatusBarItem>
<TextBlock Text="{Binding StatusMessage}"/>
</StatusBarItem>
<StatusBarItem HorizontalAlignment="Right">
<ProgressBar Width="100"
Height="16"
IsIndeterminate="{Binding BusyService.IsBusy}"/>
</StatusBarItem>
</StatusBar>
</Grid>
</Window>
using ISynergy.Framework.Mvvm.ViewModels;
public partial class MainWindow : Window
{
public MainWindow(MainViewModel viewModel)
{
InitializeComponent();
DataContext = viewModel;
}
}
3. Use Dialog Service
using ISynergy.Framework.Mvvm.ViewModels;
using ISynergy.Framework.Mvvm.Commands;
public class ProductViewModel : ViewModel
{
private readonly IProductService _productService;
public AsyncRelayCommand SaveCommand { get; }
public AsyncRelayCommand DeleteCommand { get; }
public ProductViewModel(
ICommonServices commonServices,
IProductService productService,
ILogger<ProductViewModel> logger)
: base(commonServices, logger)
{
_productService = productService;
SaveCommand = new AsyncRelayCommand(SaveAsync, CanSave);
DeleteCommand = new AsyncRelayCommand(DeleteAsync);
}
private bool CanSave() => !string.IsNullOrEmpty(Name) && IsValid;
private async Task SaveAsync()
{
try
{
CommonServices.BusyService.StartBusy("Saving product...");
await _productService.SaveAsync(Product);
await CommonServices.DialogService.ShowInformationAsync(
"Product saved successfully",
"Success");
}
catch (Exception ex)
{
await CommonServices.DialogService.ShowErrorAsync(ex, "Error");
}
finally
{
CommonServices.BusyService.StopBusy();
}
}
private async Task DeleteAsync()
{
var result = await CommonServices.DialogService.ShowMessageAsync(
"Are you sure you want to delete this product?",
"Confirm Delete",
MessageBoxButtons.YesNo);
if (result == MessageBoxResult.Yes)
{
try
{
await _productService.DeleteAsync(Product.Id);
await CommonServices.NavigationService.GoBackAsync();
}
catch (Exception ex)
{
await CommonServices.DialogService.ShowErrorAsync(ex, "Error");
}
}
}
// Show custom dialog
private async Task EditSettingsAsync()
{
await CommonServices.DialogService
.ShowDialogAsync<SettingsWindow, SettingsViewModel, Settings>();
}
}
4. Navigation Service
public class ShellViewModel : ViewModel
{
private readonly INavigationService _navigationService;
public AsyncRelayCommand<Type> NavigateCommand { get; }
public ShellViewModel(
ICommonServices commonServices,
INavigationService navigationService,
ILogger<ShellViewModel> logger)
: base(commonServices, logger)
{
_navigationService = navigationService;
NavigateCommand = new AsyncRelayCommand<Type>(NavigateAsync);
}
private async Task NavigateAsync(Type viewModelType)
{
await _navigationService.NavigateAsync(viewModelType);
}
// Navigate with parameters
private async Task NavigateToProductDetailAsync(Product product)
{
await _navigationService.NavigateAsync<ProductDetailViewModel>(product);
}
// Navigate back
private async Task GoBackAsync()
{
if (_navigationService.CanGoBack)
{
await _navigationService.GoBackAsync();
}
}
}
5. File Operations
using ISynergy.Framework.Mvvm.Abstractions.Services;
using ISynergy.Framework.Core.Models.Results;
public class DocumentViewModel : ViewModel
{
private readonly IFileService<FileResult> _fileService;
public AsyncRelayCommand OpenFileCommand { get; }
public AsyncRelayCommand SaveFileCommand { get; }
public DocumentViewModel(
ICommonServices commonServices,
IFileService<FileResult> fileService,
ILogger<DocumentViewModel> logger)
: base(commonServices, logger)
{
_fileService = fileService;
OpenFileCommand = new AsyncRelayCommand(OpenFileAsync);
SaveFileCommand = new AsyncRelayCommand(SaveFileAsync);
}
private async Task OpenFileAsync()
{
var file = await _fileService.BrowseFileAsync(
new[] { ".pdf", ".docx", ".txt" });
if (file is not null)
{
// Read file content
using var stream = await file.OpenReadAsync();
// Process file...
}
}
private async Task SaveFileAsync()
{
var file = await _fileService.SaveFileAsync(
"document.pdf",
"Documents",
new[] { ".pdf" });
if (file is not null)
{
// Write file content
using var stream = await file.OpenWriteAsync();
// Save content...
}
}
}
6. Update Service
using ISynergy.Framework.Mvvm.Abstractions.Services;
public class UpdateViewModel : ViewModel
{
private readonly IUpdateService _updateService;
public AsyncRelayCommand CheckForUpdatesCommand { get; }
public AsyncRelayCommand InstallUpdateCommand { get; }
public bool UpdateAvailable
{
get => GetValue<bool>();
set => SetValue(value);
}
public string UpdateVersion
{
get => GetValue<string>();
set => SetValue(value);
}
public UpdateViewModel(
ICommonServices commonServices,
IUpdateService updateService,
ILogger<UpdateViewModel> logger)
: base(commonServices, logger)
{
_updateService = updateService;
CheckForUpdatesCommand = new AsyncRelayCommand(CheckForUpdatesAsync);
InstallUpdateCommand = new AsyncRelayCommand(InstallUpdateAsync);
}
private async Task CheckForUpdatesAsync()
{
try
{
var update = await _updateService.CheckForUpdateAsync();
if (update.IsAvailable)
{
UpdateAvailable = true;
UpdateVersion = update.Version;
var result = await CommonServices.DialogService.ShowMessageAsync(
$"A new version ({update.Version}) is available. Would you like to install it?",
"Update Available",
MessageBoxButtons.YesNo);
if (result == MessageBoxResult.Yes)
{
await InstallUpdateAsync();
}
}
else
{
await CommonServices.DialogService.ShowInformationAsync(
"You are running the latest version.",
"No Updates");
}
}
catch (Exception ex)
{
await CommonServices.DialogService.ShowErrorAsync(ex, "Error");
}
}
private async Task InstallUpdateAsync()
{
try
{
CommonServices.BusyService.StartBusy("Downloading update...");
await _updateService.DownloadAndInstallUpdateAsync(
progress => CommonServices.BusyService.UpdateMessage($"Downloading... {progress}%"));
await CommonServices.DialogService.ShowInformationAsync(
"Update installed successfully. The application will now restart.",
"Update Complete");
_updateService.RestartApplication();
}
catch (Exception ex)
{
await CommonServices.DialogService.ShowErrorAsync(ex, "Error");
}
finally
{
CommonServices.BusyService.StopBusy();
}
}
}
Custom Controls
BladeView
<controls:BladeView ItemsSource="{Binding Blades}"
Anchor="Auto"
BladeMaxWidth="520" />
See Blades (edge panes) for the blade contract and the right-to-left rule.
ImageBrowser
<controls:ImageBrowser Images="{Binding ProductImages}"
SelectedImage="{Binding SelectedImage}"
AllowAdd="True"
AllowRemove="True" />
Console
<controls:Console Messages="{Binding ConsoleMessages}"
AutoScroll="True" />
ErrorPresenter
<controls:ErrorPresenter Errors="{Binding ValidationErrors}"
Visibility="{Binding HasErrors, Converter={StaticResource BoolToVisibilityConverter}}" />
Tiles
<controls:Tile Title="Dashboard"
Command="{Binding NavigateToDashboardCommand}"
Icon="{StaticResource DashboardIcon}" />
6. Live Localization with IndexerBinding
Bind directly to LocalizedStrings.Default indexer for automatic language switching without page reload:
<Window xmlns:local="clr-namespace:ISynergy.Framework.Globalization.Services;assembly=ISynergy.Framework.Globalization"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TextBlock Text="{Binding [WelcomeMessage], Source={x:Static local:LocalizedStrings.Default}}" />
<Label Content="{Binding [GreetingText], Source={x:Static local:LocalizedStrings.Default}}" />
</Window>
When the application language changes, simply call:
var newCulture = new CultureInfo("fr-FR");
newCulture.ApplyCulture(); // Triggers PropertyChanged("Item[]") on LocalizedStrings.Default
All bound controls automatically update with the new translations — no page refresh needed.
Blades (edge panes)
A blade is a card that slides in from a screen edge and stacks on top of the previous one, matching the WinUI BladeView interaction.
The owning view model implements IViewModelBladeView and exposes the stack through Blades (ObservableCollection<IView>) plus IsPaneVisible.
Blades are opened through IBladeService.OpenBladeAsync<TBladeViewModel, TEntity>(owner, ...), which resolves the view and view model from a DI scope, appends the view to owner.Blades and disables every earlier blade; closing the newest blade removes it and re-enables the previous one.
Derive the owner from ViewModelBladeView<TModel> to get Blades and the blade commands for free.
Host the pane in the owning view:
<controls:BladeView ItemsSource="{Binding Blades}"
Anchor="Start" />
BladeView properties:
ItemsSource— the blade views to host, in opening order. Whennull, theBladesof theIViewModelBladeViewdata context is used.Anchor— the logical edge,Auto(default, resolves toEnd),StartorEnd.DisabledOpacity— opacity of every blade except the newest one (0.75by default).BladeSpacing— gap between two adjacent blades (10by default).BladeMaxWidth— maximum width of a single blade card (520by default).InnerPadding— padding between the blade stack and the host edges (8on every side by default).
The pane collapses itself when there is no blade or when the owner sets IsPaneVisible to false, clicking the scrim closes the newest blade through its CloseCommand, and the newest blade is the only interactive one.
Shell-level pane
Controls/BladeHostView is a self-contained host: it resolves the framework's BladeHostViewModel (ISynergy.Framework.UI/ViewModels, registered as a singleton) from Application.Services, sets it as its own DataContext, and hosts a BladeView bound to Blades.
Because the owner belongs to the shell rather than to a page, the pane survives page navigation and a blade opened from anywhere docks into the same stack.
When the view model cannot be resolved (design time, or a host that does not register it) the control stays collapsed and traces the failure instead of throwing.
<c:BladeHostView Grid.RowSpan="2" Grid.ColumnSpan="3" />
Use BladeHostView when the blades are shell-level, and a page-level BladeView when the blades belong to a page — there ItemsSource="{Binding Blades}" binds to that page's own IViewModelBladeView.
The sample's Settings is opened this way: ShellViewModel.OpenSettingsAsync calls _bladeService.OpenBladeAsync<SettingsViewModel, object>(_bladeHost) and ShellView hosts BladeHostView above the content frame, below the busy overlay.
Right-to-left
Anchor is logical: Start is the left edge in a left-to-right culture and the right edge in a right-to-left one, and Auto follows End.
The edge is resolved once through BladePlacement.IsStartSide/BladePlacement.HorizontalSign, never hardcoded.
The positioning container under the pane is deliberately forced to LeftToRight so Left/Right alignment stay physical, while each blade's Frame receives the ambient FlowDirection so the blade content mirrors; the slide-in direction uses HorizontalSign, because WPF never mirrors render transforms.
The pane re-resolves both on FlowDirectionChanged.
A blade view must derive from c:View — a WPF Page — because BladeView hosts it in a Frame (JournalOwnership = OwnsJournal, navigation UI hidden); any other element is rejected with a trace error instead of being added.
Theme Support
The WPF framework includes 40+ built-in theme palettes:
using ISynergy.Framework.Mvvm.Abstractions.Services;
// Theme is automatically applied on startup
// To change theme programmatically:
public void ChangeTheme(string colorHex, Themes theme)
{
// Update settings
_settingsService.LocalSettings.Color = colorHex;
_settingsService.LocalSettings.Theme = theme;
// Apply theme
_themeService.ApplyTheme();
// Restart application to fully apply theme
System.Windows.Forms.Application.Restart();
System.Windows.Application.Current.Shutdown();
}
// Light/dark switching is built into the shell: ThemeCommand toggles through IThemeService.
// Language, theme and accent color are selected in your own settings page.
Behaviors
Using Microsoft.Xaml.Behaviors.Wpf:
<Window xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
<i:Interaction.Behaviors>
<behaviors:WindowDragBehavior />
</i:Interaction.Behaviors>
<TextBox>
<i:Interaction.Behaviors>
<behaviors:SelectAllOnFocusBehavior />
</i:Interaction.Behaviors>
</TextBox>
</Window>
Best Practices
Use Frame for navigation between pages and Window for dialogs and child windows.
Always configure theme on application startup for consistent UI appearance.
WPF supports Windows 7, 8, and 10+ through different target frameworks.
Application Structure
- Use MVVM pattern with dependency injection
- Configure services in Host builder
- Apply theme on startup
- Use NavigationService for page navigation
- Handle application updates gracefully
Performance
- Use virtualization for large lists
- Implement lazy loading for complex views
- Dispose resources properly
- Use compiled bindings where possible
- Leverage hardware acceleration
Dependencies
- I-Synergy.Framework.UI - Base UI abstractions
- Microsoft.Xaml.Behaviors.Wpf - WPF behaviors
- Microsoft.Extensions.Configuration.Json - Configuration
- Microsoft.Extensions.Hosting - Application hosting
- OpenTelemetry.Instrumentation.Http - HTTP telemetry
- OpenTelemetry.Instrumentation.Runtime - Runtime telemetry
Platform Requirements
- Windows 7.0: .NET 10.0-windows7.0
- Windows 8.0: .NET 10.0-windows8.0
- Windows 10+: .NET 10.0-windows10.0.26100.0
Documentation
Related Packages
- I-Synergy.Framework.UI - Base UI abstractions
- I-Synergy.Framework.Core - Core framework
- I-Synergy.Framework.Mvvm - MVVM framework
- I-Synergy.Framework.UI.WinUI - WinUI implementation
- I-Synergy.Framework.UI.Maui - MAUI implementation
Support
For issues, questions, or contributions, please visit the GitHub repository.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0-windows7.0 is compatible. net10.0-windows8.0 is compatible. net10.0-windows10.0.26100 is compatible. net11.0-windows7.0 is compatible. net11.0-windows8.0 is compatible. net11.0-windows10.0.26100 is compatible. |
-
net10.0-windows10.0.26100
- I-Synergy.Framework.UI (>= 2026.11114.12249)
- Microsoft.Extensions.Hosting (>= 10.0.15)
- Microsoft.Xaml.Behaviors.Wpf (>= 1.1.161)
- OpenTelemetry.Instrumentation.Http (>= 1.21.0)
- OpenTelemetry.Instrumentation.Runtime (>= 1.21.0)
-
net10.0-windows7.0
- I-Synergy.Framework.UI (>= 2026.11114.12249)
- Microsoft.Extensions.Hosting (>= 10.0.15)
- Microsoft.Xaml.Behaviors.Wpf (>= 1.1.161)
- OpenTelemetry.Instrumentation.Http (>= 1.21.0)
- OpenTelemetry.Instrumentation.Runtime (>= 1.21.0)
-
net10.0-windows8.0
- I-Synergy.Framework.UI (>= 2026.11114.12249)
- Microsoft.Extensions.Hosting (>= 10.0.15)
- Microsoft.Xaml.Behaviors.Wpf (>= 1.1.161)
- OpenTelemetry.Instrumentation.Http (>= 1.21.0)
- OpenTelemetry.Instrumentation.Runtime (>= 1.21.0)
-
net11.0-windows10.0.26100
- I-Synergy.Framework.UI (>= 2026.11114.12249)
- Microsoft.Extensions.Hosting (>= 11.0.0)
- Microsoft.Xaml.Behaviors.Wpf (>= 1.1.161)
- OpenTelemetry.Instrumentation.Http (>= 1.21.0)
- OpenTelemetry.Instrumentation.Runtime (>= 1.21.0)
-
net11.0-windows7.0
- I-Synergy.Framework.UI (>= 2026.11114.12249)
- Microsoft.Extensions.Hosting (>= 11.0.0)
- Microsoft.Xaml.Behaviors.Wpf (>= 1.1.161)
- OpenTelemetry.Instrumentation.Http (>= 1.21.0)
- OpenTelemetry.Instrumentation.Runtime (>= 1.21.0)
-
net11.0-windows8.0
- I-Synergy.Framework.UI (>= 2026.11114.12249)
- Microsoft.Extensions.Hosting (>= 11.0.0)
- Microsoft.Xaml.Behaviors.Wpf (>= 1.1.161)
- OpenTelemetry.Instrumentation.Http (>= 1.21.0)
- OpenTelemetry.Instrumentation.Runtime (>= 1.21.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2026.11114.12249 | 53 | 11/14/2026 |
| 2026.11114.11807-preview | 40 | 11/14/2026 |
| 2026.11114.11740-preview | 44 | 11/14/2026 |
| 2026.11114.11330 | 53 | 11/14/2026 |
| 2026.11114.11302-preview | 65 | 11/14/2026 |
| 2026.11112.10146 | 80 | 11/12/2026 |
| 2026.11112.10114-preview | 77 | 11/12/2026 |
| 2026.11111.12233 | 81 | 11/12/2026 |
| 2026.11111.12212-preview | 67 | 11/11/2026 |
| 2026.11111.12142-preview | 72 | 11/11/2026 |
| 2026.11111.11259-preview | 68 | 11/11/2026 |
| 2026.11111.11219-preview | 70 | 11/11/2026 |
| 2026.11111.10206 | 76 | 11/11/2026 |
| 2026.11111.10127-preview | 85 | 11/11/2026 |
| 2026.11110.12025-preview | 46 | 11/10/2026 |
| 2026.11110.12000-preview | 52 | 11/10/2026 |
| 2026.11110.11608-preview | 53 | 11/10/2026 |
| 2026.11110.11539-preview | 51 | 11/10/2026 |
| 2026.11110.11423-preview | 55 | 11/10/2026 |
| 2026.11027.11355 | 62 | 11/11/2026 |