AgentStack
SKILL verified MIT Self-run

Wpf

skill-managedcode-dotnet-skills-wpf · by managedcode

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 spe…

No reviews yet
0 installs
7 views
0.0% view→install

Install

$ agentstack add skill-managedcode-dotnet-skills-wpf

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Wpf? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

WPF

Trigger On

  • 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
  • implementing data binding, styles, templates, or control customization

Documentation

References

  • [patterns.md](references/patterns.md) - MVVM patterns, binding patterns, command patterns, and reusable architectural approaches
  • [anti-patterns.md](references/anti-patterns.md) - Common WPF mistakes and how to avoid them

Workflow

  1. Confirm Windows-only scope — WPF is Windows-only even when the wider .NET stack is cross-platform
  2. Apply MVVM pattern — keep views dumb, logic in ViewModels, use commands
  3. Manage data binding explicitly — choose correct binding modes, validate at runtime
  4. Use styles and templates deliberately — keep UI composable, avoid page-specific hacks
  5. Handle threading correctly — use Dispatcher for UI updates, async/await for long operations
  6. Validate both designer and runtime — XAML composition failures often surface only at runtime

Current Upstream Notes

  • The refreshed WPF overview page reiterates WPF as a Windows desktop UI stack with XAML, data binding, styling, templates, resources, and vector/rich-media composition. Keep WPF-specific guidance separate from WinUI or MAUI unless the task is explicitly a migration or comparison.
  • For modernization work, check both .NET Framework compatibility constraints and current .NET desktop migration docs before moving project files or XAML resource dictionaries.

Project Structure

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/

MVVM Pattern

ViewModel with MVVM Toolkit

public partial class CustomersViewModel : ObservableObject
{
    private readonly ICustomerService _customerService;

    [ObservableProperty]
    private ObservableCollection _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(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;
}

View Binding


    
        
            
            
        

        
            
            
        

        
            
                
                
            
        
    

Dependency Injection

public partial class App : Application
{
    private readonly IHost _host;

    public App()
    {
        _host = Host.CreateDefaultBuilder()
            .ConfigureServices((context, services) =>
            {
                // Services
                services.AddSingleton();
                services.AddSingleton();

                // ViewModels
                services.AddTransient();
                services.AddTransient();

                // Views
                services.AddTransient();
                services.AddTransient();
            })
            .Build();
    }

    protected override async void OnStartup(StartupEventArgs e)
    {
        await _host.StartAsync();
        var mainWindow = _host.Services.GetRequiredService();
        mainWindow.Show();
        base.OnStartup(e);
    }

    protected override async void OnExit(ExitEventArgs e)
    {
        await _host.StopAsync();
        _host.Dispose();
        base.OnExit(e);
    }
}

Data Binding Modes

Value Converters

public 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();
    }
}

Styles and Templates

Resource Dictionary


    
    
        
        
        
        
        
            
                
                    
                        
                    
                
            
        
    

    
    
        
    

Threading and Dispatcher

// 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(data);
    }
    finally
    {
        IsLoading = false;
    }
}

Anti-Patterns to Avoid

| 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 |

Best Practices

  1. Use compiled bindings in .NET 5+:
  • Enable x:CompileBindings="True" for performance
  1. Implement INotifyDataErrorInfo for validation:

``csharp [ObservableProperty] [NotifyDataErrorInfo] [Required(ErrorMessage = "Name is required")] [MinLength(2, ErrorMessage = "Name must be at least 2 characters")] private string _name = string.Empty; ``

  1. Use weak event patterns for long-lived subscriptions:

``csharp WeakEventManager.AddHandler(source, "EventName", Handler); ``

  1. Virtualize large collections:

```xml

```

  1. Freeze Freezables when possible:

``csharp var brush = new SolidColorBrush(Colors.Blue); brush.Freeze(); // Thread-safe, better performance ``

  1. Use design-time data:

```xml

```

Testing

[Fact]
public async Task RefreshCommand_LoadsCustomers()
{
    var mockService = new Mock();
    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();
    var viewModel = new CustomersViewModel(mockService.Object);

    viewModel.SelectedCustomer = null;

    Assert.False(viewModel.SaveCommand.CanExecute(null));
}

Deliver

  • cleaner WPF views and view-model boundaries
  • safer binding and threading behavior
  • migration guidance grounded in actual Windows constraints
  • MVVM pattern with testable ViewModels

Validate

  • binding and command flows are explicit
  • code-behind is not carrying hidden business logic
  • Windows-only assumptions are acknowledged
  • threading and dispatcher usage is correct
  • styles and resources are properly organized

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.