Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Build and modernize WPF applications on .NET with correct XAML, data binding, commands, threading, styling, and Windows desktop migration decisions. USE FOR: working on WPF UI, MVVM, binding, commands, or desktop modernization; migrating WPF from .NET Framework to .NET; integrating newer Windows capabilities into a WPF app. DO NOT USE FOR: unrelated stacks; generic tasks that do not need this specific guidance. INVOKES: inspect the repository context, edit targeted files, and run relevant build,
.claude/skills/managedcode-wpf/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-19 | ✗→✓ | ▲ Improved | 207% | 0% |
| case-05 | ✓→✗ | ▼ Worse | 141% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 116% | 0% |
| case-06 | ✓→✓ | = Same ✓ | 170% | 0% |
| case-07 | ✓→✓ | = Same ✓ | 198% | 0% |
MyWpfApp/
├── MyWpfApp/
│ ├── App.xaml # Application entry
│ ├── MainWindow.xaml # Main window
│ ├── Views/ # XAML views/windows
│ ├── ViewModels/ # MVVM ViewModels
│ ├── Models/ # Domain models
│ ├── Services/ # Business logic
│ ├── Converters/ # Value converters
│ ├── Resources/ # Styles, templates, dictionaries
│ └── Controls/ # Custom controls
└── MyWpfApp.Tests/csharppublic partial class CustomersViewModel : ObservableObject { private readonly ICustomerService _customerService; [ObservableProperty] private ObservableCollection<Customer> _customers = []; [ObservableProperty] [NotifyCanExecuteChangedFor(nameof(SaveCommand))] private Customer? _selectedCustomer; [ObservableProperty] [NotifyCanExecuteChangedFor(nameof(RefreshCommand))] private bool _isLoading; public CustomersViewModel(ICustomerService customerService) { _customerService = customerService; } [RelayCommand(CanExecute = nameof(CanRefresh))] private async Task RefreshAsync() { IsLoading = true; try { var items = await _customerService.GetAllAsync(); Customers = new ObservableCollection<Customer>(items); } finally { IsLoading = false; } } private bool CanRefresh() => !IsLoading; [RelayCommand(CanExecute = nameof(CanSave))] private async Task SaveAsync() { if (SelectedCustomer is null) return; await _customerService.SaveAsync(SelectedCustomer); } private bool CanSave() => SelectedCustomer is not null; }
xml<Window x:Class="MyWpfApp.Views.CustomersView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vm="clr-namespace:MyWpfApp.ViewModels" d:DataContext="{d:DesignInstance Type=vm:CustomersViewModel}"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <ToolBar Grid.Row="0"> <Button Content="Refresh" Command="{Binding RefreshCommand}"/> <Button Content="Save" Command="{Binding SaveCommand}"/> </ToolBar> <DataGrid Grid.Row="1" ItemsSource="{Binding Customers}" SelectedItem="{Binding SelectedCustomer}" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Header="Name" Binding="{Binding Name}"/> <DataGridTextColumn Header="Email" Binding="{Binding Email}"/> </DataGrid.Columns> </DataGrid> </Grid> </Window>
csharppublic partial class App : Application { private readonly IHost _host; public App() { _host = Host.CreateDefaultBuilder() .ConfigureServices((context, services) => { // Services services.AddSingleton<ICustomerService, CustomerService>(); services.AddSingleton<INavigationService, NavigationService>(); // ViewModels services.AddTransient<CustomersViewModel>(); services.AddTransient<CustomerDetailViewModel>(); // Views services.AddTransient<MainWindow>(); services.AddTransient<CustomersView>(); }) .Build(); } protected override async void OnStartup(StartupEventArgs e) { await _host.StartAsync(); var mainWindow = _host.Services.GetRequiredService<MainWindow>(); mainWindow.Show(); base.OnStartup(e); } protected override async void OnExit(ExitEventArgs e) { await _host.StopAsync(); _host.Dispose(); base.OnExit(e); } }
xml<!-- OneTime: Read once at initialization --> <TextBlock Text="{Binding CreatedDate, Mode=OneTime}"/> <!-- OneWay: Source to target only (default for most properties) --> <TextBlock Text="{Binding Name, Mode=OneWay}"/> <!-- TwoWay: Bidirectional synchronization --> <TextBox Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> <!-- OneWayToSource: Target to source only --> <TextBox Text="{Binding SearchFilter, Mode=OneWayToSource}"/>
csharppublic class BooleanToVisibilityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is bool boolValue) { return boolValue ? Visibility.Visible : Visibility.Collapsed; } return Visibility.Collapsed; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return value is Visibility.Visible; } } // Multi-value converter public class MultiplyConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { if (values.Length == 2 && values[0] is double a && values[1] is double b) { return a * b; } return 0.0; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
xml<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <!-- Implicit style for all Buttons --> <Style TargetType="Button"> <Setter Property="Padding" Value="10,5"/> <Setter Property="Margin" Value="5"/> <Setter Property="Background" Value="#0078D4"/> <Setter Property="Foreground" Value="White"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Border Background="{TemplateBinding Background}" CornerRadius="4" Padding="{TemplateBinding Padding}"> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> <!-- Named style --> <Style x:Key="DangerButton" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}"> <Setter Property="Background" Value="#D32F2F"/> </Style> </ResourceDictionary>
csharp// Update UI from background thread await Task.Run(async () => { var data = await LoadDataAsync(); // Must use Dispatcher to update UI Application.Current.Dispatcher.Invoke(() => { Items.Clear(); foreach (var item in data) { Items.Add(item); } }); }); // Better: Use async/await properly private async Task LoadDataAsync() { IsLoading = true; try { // This runs on background thread var data = await _service.GetDataAsync(); // This automatically marshals to UI thread Items = new ObservableCollection<Item>(data); } finally { IsLoading = false; } }
| Anti-Pattern | Why It's Bad | Better Approach | |--------------|--------------|-----------------| | Logic in code-behind | Hard to test, tight coupling | Use MVVM with ViewModels | | Synchronous blocking calls | UI freezes | Use async/await | | Manual INotifyPropertyChanged | Boilerplate, error-prone | Use MVVM Toolkit attributes | | Hardcoded colors/sizes | Inconsistent, hard to theme | Use resource dictionaries | | Direct Dispatcher.Invoke everywhere | Complex, error-prone | Prefer async/await marshaling | | God ViewModel | Unmaintainable | Split into focused ViewModels | | Skipping binding validation | Runtime errors hidden | Use ValidatesOnDataErrors | | Event handlers for everything | Memory leaks, coupling | Use commands and bindings |
x:CompileBindings="True" for performancecsharp [ObservableProperty] [NotifyDataErrorInfo] [Required(ErrorMessage = "Name is required")] [MinLength(2, ErrorMessage = "Name must be at least 2 characters")] private string _name = string.Empty;
csharp WeakEventManager<Source, EventArgs>.AddHandler(source, "EventName", Handler);
xml <ListBox VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.VirtualizationMode="Recycling" ItemsSource="{Binding LargeCollection}"/>
csharp var brush = new SolidColorBrush(Colors.Blue); brush.Freeze(); // Thread-safe, better performance
xml <Window d:DataContext="{d:DesignInstance Type=vm:MainViewModel, IsDesignTimeCreatable=True}">
csharp[Fact] public async Task RefreshCommand_LoadsCustomers() { var mockService = new Mock<ICustomerService>(); mockService.Setup(s => s.GetAllAsync()) .ReturnsAsync(new[] { new Customer { Name = "Test" } }); var viewModel = new CustomersViewModel(mockService.Object); await viewModel.RefreshCommand.ExecuteAsync(null); Assert.Single(viewModel.Customers); Assert.Equal("Test", viewModel.Customers[0].Name); } [Fact] public void SaveCommand_CannotExecute_WhenNoSelection() { var mockService = new Mock<ICustomerService>(); var viewModel = new CustomersViewModel(mockService.Object); viewModel.SelectedCustomer = null; Assert.False(viewModel.SaveCommand.CanExecute(null)); }
Other measured skills in the registry, with their headline benchmark lift.