WPF-UI.Violeta
4.0.3.6
dotnet add package WPF-UI.Violeta --version 4.0.3.6
NuGet\Install-Package WPF-UI.Violeta -Version 4.0.3.6
<PackageReference Include="WPF-UI.Violeta" Version="4.0.3.6" />
<PackageVersion Include="WPF-UI.Violeta" Version="4.0.3.6" />
<PackageReference Include="WPF-UI.Violeta" />
paket add WPF-UI.Violeta --version 4.0.3.6
#r "nuget: WPF-UI.Violeta, 4.0.3.6"
#:package WPF-UI.Violeta@4.0.3.6
#addin nuget:?package=WPF-UI.Violeta&version=4.0.3.6
#tool nuget:?package=WPF-UI.Violeta&version=4.0.3.6


WPF UI Violeta
WPF UI Violeta is based on WPF UI, and provides the Fluent experience in your known and loved WPF framework. Some new immersive controls like Toast, Flyout, ContentDialog, MessageBox and etc.
Some idea or codes are ported from ModernWpf and Fischless.
When I decided to create this project I was listening to the song Violeta.
🚀 Getting started
Similar to WPF UI.
<Application
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:vio="http://schemas.lepo.co/wpfui/2022/xaml/violeta">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ui:ThemesDictionary Theme="Dark" />
<ui:ControlsDictionary />
<vio:ThemesDictionary Theme="Dark" />
<vio:ControlsDictionary />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
👋Examples
Toast
Toastis an independent popup notification that automatically disappears after a specified time.Toast.Information("I am information message"); Toast.Error("I am error message"); Toast.Success("I am success message"); Toast.Warning("I am warning message"); Toast.Show(owner: null!, "I am any message", new ToastConfig());Flyout
The
FlyoutServiceenables you to attachFlyoutmenus or tooltips to various controls such asButton, providing a flexible and intuitive way to display additional content or options.<ui:Button Content="Show Flyout"> <ui:FlyoutService.Flyout> <ui:Flyout Placement="Bottom"> <StackPanel> <TextBlock HorizontalAlignment="Left" Text="Show the flyout message here" /> <Button Command="{Binding GotItCommand}" Content="Got it" /> </StackPanel> </ui:Flyout> </ui:FlyoutService.Flyout> </ui:Button>ContentDialogHostService
The
ContentDialogHostServicesimplifies the creation and management ofContentDialoginstances in your application.Wpf.Ui.Controls.ContentDialog dialog = new() { Title = "My sample dialog", Content = "Content of the dialog", CloseButtonText = "Close button", PrimaryButtonText = "Primary button", SecondaryButtonText = "Secondary button" }; // Setting the dialog container dialog.DialogHost = ContentDialogHostService.ContentPresenterForDialogs; // Showing the dialog await dialog.ShowAsync(CancellationToken.None);ContentDialog
The new
ContentDialogis easy to use with smooth transitions.global using ContentDialog = Wpf.Ui.Violeta.Controls.ContentDialog; global using ContentDialogButton = Wpf.Ui.Violeta.Controls.ContentDialogButton; ContentDialog dialog = new() { Title = "My sample dialog", Content = "Content of the dialog", CloseButtonText = "Close button", PrimaryButtonText = "Primary button", SecondaryButtonText = "Secondary button", DefaultButton = ContentDialogButton.Primary, }; _ = await dialog.ShowAsync();
If you want to inherit Wpf.Ui.Violeta.Controls.ContentDialog to implement a custom dialog just using Style="{StaticResource DefaultVioletaContentDialogStyle}".
MessageBox
To utilize Win32's classic
MessageBoxmethods while supporting modern UI themes like Mica and dark mode.global using MessageBox = Wpf.Ui.Violeta.Controls.MessageBox; // Sync methods _ = MessageBox.Information("This is a information message"); _ = MessageBox.Warning("This is a warning message"); _ = MessageBox.Error("This is a error message"); MessageBoxResult result = MessageBox.Question("This is a question and do you want to click OK?"); // Async methods _ = await MessageBox.InformationAsync("This is a information message"); _ = await MessageBox.WarningAsync("This is a warning message"); _ = await MessageBox.ErrorAsync("This is a error message"); MessageBoxResult result = await MessageBox.QuestionAsync("This is a question and do you want to click OK?");PendingBox
Keep displaying 'Loading' until released.
// Default style. using IPendingHandler pending = PendingBox.Show(); // Show with title and cancel button. using IPendingHandler pending = PendingBox.Show("Doing something", "I'm a title", isShowCancel: true);ToggleButtonGroup / RadioButtonGroup / MenuItemGroup
Turn the ToggleButton and RadioButton under the same Group into a radio button.
<StackPanel Orientation="Horizontal"> <StackPanel.Resources> <vio:ToggleButtonGroup x:Key="ToggleButtonGroup" /> </StackPanel.Resources> <ToggleButton vio:ToggleButtonGroup.Group="{DynamicResource ToggleButtonGroup}" Content="1st" IsChecked="True" /> <ToggleButton vio:ToggleButtonGroup.Group="{DynamicResource ToggleButtonGroup}" Content="2nd" /> </StackPanel><StackPanel Orientation="Horizontal"> <StackPanel.Resources> <vio:RadioButtonGroup x:Key="RadioButtonGroup" /> </StackPanel.Resources> <RadioButton vio:RadioButtonGroup.Group="{DynamicResource RadioButtonGroup}" Content="1st" IsChecked="True" /> <Grid> <RadioButton Margin="8,0,0,0" vio:RadioButtonGroup.Group="{DynamicResource RadioButtonGroup}" Content="2nd" /> </Grid> </StackPanel>Splash
Show the Splash Screen in another UI thread.
public App() { Splash.ShowAsync("pack://application:,,,/Wpf.Ui.Test;component/wpfui.png"); InitializeComponent(); } public MainWindow() { InitializeComponent(); Splash.CloseOnLoaded(this, minimumMilliseconds: 1800); }TreeListView
TreeListView is a better way to display hierarchical data.
<ui:TreeListView ItemsSource="{Binding StaffList}"> <ui:TreeListView.Columns> <GridViewColumnCollection> <ui:GridViewColumn Width="400" Header="Name"> <ui:GridViewColumn.CellTemplate> <DataTemplate> <ui:TreeRowExpander Content="{Binding Name}" /> </DataTemplate> </ui:GridViewColumn.CellTemplate> </ui:GridViewColumn> <ui:GridViewColumn Width="80" DisplayMemberBinding="{Binding Age}" Header="Age" /> <ui:GridViewColumn Width="80" DisplayMemberBinding="{Binding Sex}" Header="Sex" /> <ui:GridViewColumn Width="100" DisplayMemberBinding="{Binding Duty}" Header="Duty" /> <ui:GridViewColumn Width="250" Header="IsChecked"> <ui:GridViewColumn.CellTemplate> <DataTemplate> <ui:ToggleSwitch IsChecked="{Binding IsChecked}" /> </DataTemplate> </ui:GridViewColumn.CellTemplate> </ui:GridViewColumn> </GridViewColumnCollection> </ui:TreeListView.Columns> <ui:TreeListView.ItemTemplate> <HierarchicalDataTemplate ItemsSource="{Binding StaffList}" /> </ui:TreeListView.ItemTemplate> </ui:TreeListView>public partial class ViewModel : ObservableObject { [ObservableProperty] private ObservableCollection<Staff> staffList = []; public void InitNode1Value() { Staff staff = new Staff() { Name = "Alice", Age = 30, Sex = "Male", Duty = "Manager", IsExpanded = true }; Staff staff2 = new Staff() { Name = "Alice1", Age = 21, Sex = "Male", Duty = "Normal", IsExpanded = true }; Staff staff3 = new Staff() { Name = "Alice11", Age = 21, Sex = "Male", Duty = "Normal" }; staff2.StaffList.Add(staff3); staff3 = new Staff() { Name = "Alice22", Age = 21, Sex = "Female", Duty = "Normal" }; staff2.StaffList.Add(staff3); staff.StaffList.Add(staff2); staff2 = new Staff() { Name = "Alice2", Age = 22, Sex = "Female", Duty = "Normal" }; staff.StaffList.Add(staff2); staff2 = new Staff() { Name = "Alice3", Age = 23, Sex = "Female", Duty = "Normal" }; staff.StaffList.Add(staff2); StaffList.Add(staff); staff = new Staff() { Name = "Bob", Age = 31, Sex = "Male", Duty = "CEO" }; staff2 = new Staff() { Name = "Bob1", Age = 24, Sex = "Female", Duty = "Normal" }; staff.StaffList.Add(staff2); staff2 = new Staff() { Name = "Bob2", Age = 25, Sex = "Female", Duty = "Normal" }; staff.StaffList.Add(staff2); staff2 = new Staff() { Name = "Bob3", Age = 26, Sex = "Male", Duty = "Normal" }; staff.StaffList.Add(staff2); StaffList.Add(staff); staff = new Staff() { Name = "Cyber", Age = 32, Sex = "Female", Duty = "Leader" }; staff2 = new Staff() { Name = "Cyber1", Age = 27, Sex = "Female", Duty = "Normal" }; staff.StaffList.Add(staff2); staff2 = new Staff() { Name = "Cyber2", Age = 28, Sex = "Female", Duty = "Normal" }; staff.StaffList.Add(staff2); StaffList.Add(staff); } } public partial class Staff : ObservableObject { [ObservableProperty] private string name = null!; [ObservableProperty] private int age; [ObservableProperty] private string sex = null!; [ObservableProperty] private string duty = null!; [ObservableProperty] private bool isChecked = true; [ObservableProperty] private bool isSelected = false; [ObservableProperty] private bool isExpanded = false; [ObservableProperty] private ObservableCollection<Staff> staffList = []; }TreeModelListView
TreeModelListView is a fast tree list view used
IEnumerableandITreeModelto display data but CURD is not fully supported.<ui:TreeModelListView Model="{Binding TreeTestModel}"> <ui:GridView> <ui:GridView.Columns> <ui:GridViewColumn Width="400" Header="Column1"> <ui:GridViewColumn.CellTemplate> <DataTemplate> <ui:TreeModelRowExpander Content="{Binding Column1}" /> </DataTemplate> </ui:GridViewColumn.CellTemplate> </ui:GridViewColumn> <ui:GridViewColumn Width="250" DisplayMemberBinding="{Binding Column2, Mode=TwoWay}" Header="Column2" /> <ui:GridViewColumn Width="250" DisplayMemberBinding="{Binding Column3, Mode=TwoWay}" Header="Column3" /> <ui:GridViewColumn Width="250" Header="IsChecked"> <ui:GridViewColumn.CellTemplate> <DataTemplate> <ui:ToggleSwitch IsChecked="{Binding IsChecked}" /> </DataTemplate> </ui:GridViewColumn.CellTemplate> </ui:GridViewColumn> </ui:GridView.Columns> </ui:GridView> </ui:TreeModelListView>public partial class ViewModel : ObservableObject { [ObservableProperty] private TreeCollection<TreeTestModel> treeTestModel = CreateTestModel(); public static TreeModelCollection<TreeTestModel> CreateTestModel() { return new TreeModelCollection<TreeTestModel>() { Children = new( [ new() { Column1 = "Test 1", Column2 = "Test 1", Column3 = "Test 1", Children = new( [ new() { Column1 = "Test 1.1", Column2 = "Test 1.1", Column3 = "Test 1.1", Children = new( [ new() { Column1 = "Test 1.2", Column2 = "Test 1.2", Column3 = "Test 1.2", }, ]), }, ]), }, new() { Column1 = "Test 2", Column2 = "Test 2", Column3 = "Test 2", } ]), }; } } [ObservableObject] public partial class TreeTestModel : TreeModelObject<TreeTestModel> { [ObservableProperty] private string? column1; [ObservableProperty] private string? column2; [ObservableProperty] private string? column3; [ObservableProperty] private bool isChecked = false; }ImageView
Provides a scalable image control.
<vio:ImageView Source="/wpfui.png" />ExceptionReport
Show a dialog to handle the
DispatcherUnhandledExceptionfrom Application.public partial class App : Application { public App() { InitializeComponent(); DispatcherUnhandledException += (object s, DispatcherUnhandledExceptionEventArgs e) => { e.Handled = true; ExceptionReport.Show(e.Exception); }; } }BitmapIcon
Supports to show monochrome image that match the theme color.
<ui:BitmapIcon ShowAsMonochrome="False" UriSource="pack://application:,,,/Wpf.Ui.Test;component/Resources/Images/Tiara.png" /> <ui:BitmapIcon ShowAsMonochrome="True" UriSource="pack://application:,,,/Wpf.Ui.Test;component/Resources/Images/Tiara.png" />TrayIconHost
Support NotifyIcon only using Win32 api.
TrayIconManager.Start(); internal partial class TrayIconManager { private static TrayIconManager _instance = null!; private readonly TrayIconHost? _iconHost = null; private TrayIconManager() { using Win32Icon icon = new(ResourcesProvider.GetStream(new Uri("pack://application:,,,/Wpf.Ui.Test;component/Resources/Images/ProfilePicture.ico"))); _iconHost = new TrayIconHost() { ToolTipText = "Wpf.Ui.Test", Icon = icon.Handle, Menu = [ new TrayMenuItem() { Header = Version, IsEnabled = false, }, new TraySeparator(), new TrayMenuItem() { Header = "Restart", Command = RestartCommand, }, new TrayMenuItem() { Header = "Exit", Command = ExitCommand, } ], }; _iconHost.LeftDoubleClick += (_, _) => ActivateOrRestoreMainWindow(); } public static TrayIconManager GetInstance() { return _instance ??= new TrayIconManager(); } public static void Start() { _ = GetInstance(); } public static void ShowNotification(string title, string content, ToolTipIcon icon = default, int timeout = 5000, Action? clickEvent = null, Action? closeEvent = null) { var iconHost = GetInstance()._iconHost; if (iconHost is null) return; iconHost.ShowBalloonTip(timeout, title, content, icon); iconHost.BalloonTipClicked += OnIconOnBalloonTipClicked; iconHost.BalloonTipClosed += OnIconOnBalloonTipClosed; void OnIconOnBalloonTipClicked(object? sender, EventArgs e) { clickEvent?.Invoke(); iconHost.BalloonTipClicked -= OnIconOnBalloonTipClicked; } void OnIconOnBalloonTipClosed(object? sender, EventArgs e) { closeEvent?.Invoke(); iconHost.BalloonTipClosed -= OnIconOnBalloonTipClosed; } } } internal partial class TrayIconManager : ObservableObject { [ObservableProperty] private string version = $"v{Assembly.GetExecutingAssembly().GetName().Version!.ToString(4)}"; [RelayCommand] private void ActivateOrRestoreMainWindow() { if (Application.Current.MainWindow is not null) { if (Application.Current.MainWindow.IsVisible) { Application.Current.MainWindow.Hide(); } else { Application.Current.MainWindow.Show(); Application.Current.MainWindow.Activate(); } } } [RelayCommand] private void Restart() { try { using Process process = new() { StartInfo = new ProcessStartInfo() { FileName = GetExecutablePath(), WorkingDirectory = Environment.CurrentDirectory, UseShellExecute = true, }, }; process.Start(); } catch (Win32Exception) { return; } Process.GetCurrentProcess().Kill(); static string GetExecutablePath() { string fileName = AppDomain.CurrentDomain.FriendlyName; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) fileName += ".exe"; return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName); } } [RelayCommand] private void Exit() { Application.Current.Shutdown(); } }Drawer
Support Drawer with animated sliding panel
<ui:Drawer Width="300" IsOpen="{Binding IsOpen}" Placement="Left"> <Border Width="300" Height="100" Background="Black" CornerRadius="9"> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="21" Text="Drawer" /> </Border> </ui:Drawer>
📷 Screenshots
Under construction
Thanks
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0-windows7.0 is compatible. net7.0-windows was computed. net7.0-windows7.0 is compatible. net8.0-windows was computed. net8.0-windows7.0 is compatible. net9.0-windows was computed. net9.0-windows7.0 is compatible. net10.0-windows was computed. |
| .NET Framework | net462 is compatible. net463 was computed. net47 is compatible. net471 is compatible. net472 is compatible. net48 is compatible. net481 is compatible. |
-
.NETFramework 4.6.2
- System.Net.Http (>= 4.3.4)
- WPF-UI (>= 4.0.3)
-
.NETFramework 4.7
- System.Net.Http (>= 4.3.4)
- WPF-UI (>= 4.0.3)
-
.NETFramework 4.7.1
- System.Net.Http (>= 4.3.4)
- WPF-UI (>= 4.0.3)
-
.NETFramework 4.7.2
- System.Net.Http (>= 4.3.4)
- WPF-UI (>= 4.0.3)
-
.NETFramework 4.8
- System.Net.Http (>= 4.3.4)
- WPF-UI (>= 4.0.3)
-
.NETFramework 4.8.1
- System.Net.Http (>= 4.3.4)
- WPF-UI (>= 4.0.3)
-
net6.0-windows7.0
- WPF-UI (>= 4.0.3)
-
net7.0-windows7.0
- WPF-UI (>= 4.0.3)
-
net8.0-windows7.0
- WPF-UI (>= 4.0.3)
-
net9.0-windows7.0
- WPF-UI (>= 4.0.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories (2)
Showing the top 2 popular GitHub repositories that depend on WPF-UI.Violeta:
| Repository | Stars |
|---|---|
|
QL-Win/QuickLook
Bring macOS “Quick Look” feature to Windows
|
|
|
babalae/better-genshin-impact
📦BetterGI · 更好的原神 - 自动拾取 | 自动剧情 | 全自动钓鱼(AI) | 全自动七圣召唤 | 自动伐木 | 自动刷本 | 自动采集/挖矿/锄地 | 一条龙 | 全连音游 - UI Automation Testing Tools For Genshin Impact
|
| Version | Downloads | Last Updated |
|---|---|---|
| 4.0.3.6 | 757 | 9/6/2025 |
| 4.0.3.5 | 190 | 8/22/2025 |
| 4.0.3.4 | 156 | 8/22/2025 |
| 4.0.3.3 | 147 | 8/21/2025 |
| 4.0.3.2 | 590 | 7/20/2025 |
| 4.0.3.1 | 224 | 7/8/2025 |
| 4.0.3 | 436 | 6/30/2025 |
| 4.0.2.4 | 387 | 6/21/2025 |
| 4.0.2.3 | 2,982 | 4/20/2025 |
| 4.0.2.2 | 602 | 4/1/2025 |
| 4.0.2.1 | 441 | 3/24/2025 |
| 4.0.2 | 391 | 3/24/2025 |
| 4.0.0 | 1,204 | 3/13/2025 |
| 3.0.5.28 | 765 | 12/31/2024 |
| 3.0.5.27 | 673 | 12/8/2024 |
| 3.0.5.26 | 1,331 | 11/20/2024 |
| 3.0.5.25 | 157 | 11/19/2024 |
| 3.0.5.24 | 164 | 11/19/2024 |
| 3.0.5.23 | 1,094 | 10/27/2024 |
| 3.0.5.22 | 162 | 10/27/2024 |
| 3.0.5.21 | 147 | 10/27/2024 |
| 3.0.5.20 | 214 | 10/16/2024 |
| 3.0.5.19 | 150 | 10/13/2024 |
| 3.0.5.18 | 294 | 10/9/2024 |
| 3.0.5.17 | 177 | 10/7/2024 |
| 3.0.5.16 | 266 | 9/30/2024 |
| 3.0.5.15 | 205 | 9/27/2024 |
| 3.0.5.14 | 173 | 9/23/2024 |
| 3.0.5.13 | 172 | 9/19/2024 |
| 3.0.5.12 | 474 | 9/10/2024 |
| 3.0.5.11 | 155 | 9/10/2024 |
| 3.0.5.10 | 197 | 9/10/2024 |
| 3.0.5.9 | 148 | 9/8/2024 |
| 3.0.5.8 | 135 | 9/8/2024 |
| 3.0.5.7 | 187 | 9/3/2024 |
| 3.0.5.6 | 170 | 8/26/2024 |
| 3.0.5.5 | 183 | 8/23/2024 |
| 3.0.5.4 | 204 | 8/22/2024 |
| 3.0.5.3 | 352 | 8/20/2024 |
| 3.0.5.2 | 272 | 8/15/2024 |
| 3.0.5.1 | 167 | 8/15/2024 |
| 3.0.5 | 192 | 8/13/2024 |