wpf-mvvm-generator
WPF MVVM code generator. Creates ViewModel, View, and Model with CommunityToolkit.Mvvm source generators. Use when scaffolding new WPF features or entities following MVVM pattern.
How do I install this agent skill?
npx skills add https://github.com/jeongheonk/c-sharp-custom-marketplace --skill wpf-mvvm-generatorIs this agent skill safe to install?
- Gen Agent Trust Hubpass
The skill is a WPF MVVM code generator that scaffolds project files based on user input and existing project patterns. It contains a minor indirect prompt injection surface by reading local project files, but lacks dangerous capabilities like network access.
- Socketpass
No alerts
- Snykpass
Risk: LOW · No issues
- Runlayerpass
1 file scanned · No issues
What does this agent skill do?
WPF MVVM Generator 스킬
CommunityToolkit.Mvvm source generator를 사용하여 WPF MVVM 컴포넌트를 생성합니다.
중요: 모든 결과는 반드시 한국어로 작성합니다. 코드 식별자, 기술 용어, 패턴 이름 등은 원문 그대로 유지하되, 설명 부분은 한국어를 사용합니다.
인자
$ARGUMENTS[0]: 엔티티 이름 (필수) - 예:User,Product,Order$ARGUMENTS[1]: 생성 유형 (선택):viewmodel,view,model,all(기본값:all)all: Model + ViewModel + View + Code-Behind + Messages + Service Interface 모두 생성
실행 단계
1단계: 인자 검증
$ARGUMENTS[0]이 비어있는 경우:
- 사용자에게 엔티티 이름 요청
- 프로젝트의 기존 Model 기반으로 제안
엔티티 이름 검증:
- PascalCase 여부 확인
- C# 예약어 사용 확인
- 특수문자, 공백 포함 시 사용자에게 재입력 요청
2단계: 프로젝트 구조 탐색
기존 패턴을 식별:
Glob("**/*ViewModel.cs")로 기존 ViewModel 패턴 확인- 첫 번째 발견된 파일에서 네임스페이스 추출
/ViewModels,/Views,/Models디렉토리 존재 여부 확인- 기존 베이스 클래스 또는 인터페이스 탐색
3단계: 코드 생성
$ARGUMENTS[1] 기준으로 생성:
생성 컴포넌트
Model (model)
namespace {Namespace}.Models;
/// <summary>
/// {EntityName} domain model
/// </summary>
public sealed class {EntityName}
{
public required int Id { get; init; }
public required string Name { get; init; }
// 컨텍스트에 따른 추가 프로퍼티
}
ViewModel (viewmodel)
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
namespace {Namespace}.ViewModels;
/// <summary>
/// ViewModel for {EntityName} management
/// </summary>
public partial class {EntityName}ViewModel : ObservableObject
{
private readonly I{EntityName}Service _{entityName}Service;
public {EntityName}ViewModel(I{EntityName}Service {entityName}Service)
{
_{entityName}Service = {entityName}Service;
}
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(HasSelection))]
[NotifyCanExecuteChangedFor(nameof(DeleteCommand))]
private {EntityName}? _selected{EntityName};
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(SaveCommand))]
private bool _isModified;
[ObservableProperty]
private bool _isLoading;
public bool HasSelection => Selected{EntityName} is not null;
[RelayCommand]
private async Task LoadAsync(CancellationToken cancellationToken = default)
{
IsLoading = true;
try
{
// Load logic
}
finally
{
IsLoading = false;
}
}
[RelayCommand(CanExecute = nameof(CanSave))]
private async Task SaveAsync(CancellationToken cancellationToken = default)
{
await _{entityName}Service.SaveAsync(Selected{EntityName}!, cancellationToken);
IsModified = false;
}
private bool CanSave() => IsModified && Selected{EntityName} is not null;
[RelayCommand(CanExecute = nameof(CanDelete))]
private async Task DeleteAsync(CancellationToken cancellationToken = default)
{
if (Selected{EntityName} is null) return;
await _{entityName}Service.DeleteAsync(Selected{EntityName}.Id, cancellationToken);
WeakReferenceMessenger.Default.Send(
new {EntityName}DeletedMessage(Selected{EntityName}));
Selected{EntityName} = null;
}
private bool CanDelete() => Selected{EntityName} is not null;
}
View (view)
<UserControl x:Class="{Namespace}.Views.{EntityName}View"
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="{Namespace}.ViewModels"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance vm:{EntityName}ViewModel, IsDesignTimeCreatable=False}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Header -->
<TextBlock Grid.Row="0"
Text="{EntityName} Management"
Style="{StaticResource HeaderStyle}"/>
<!-- Content -->
<ContentControl Grid.Row="1"
Content="{Binding Selected{EntityName}}"
Visibility="{Binding HasSelection, Converter={StaticResource BoolToVisibility}}"/>
<!-- Actions -->
<StackPanel Grid.Row="2"
Orientation="Horizontal"
HorizontalAlignment="Right">
<Button Content="Save"
Command="{Binding SaveCommand}"/>
<Button Content="Delete"
Command="{Binding DeleteCommand}"/>
</StackPanel>
<!-- Loading Overlay -->
<Border Grid.RowSpan="3"
Background="#80000000"
Visibility="{Binding IsLoading, Converter={StaticResource BoolToVisibility}}">
<ProgressBar IsIndeterminate="True" Width="200"/>
</Border>
</Grid>
</UserControl>
Code-Behind (최소한)
namespace {Namespace}.Views;
public partial class {EntityName}View : UserControl
{
public {EntityName}View()
{
InitializeComponent();
}
}
Message Types
namespace {Namespace}.Messages;
public sealed record {EntityName}DeletedMessage({EntityName} Deleted{EntityName});
public sealed record {EntityName}SelectedMessage({EntityName} Selected{EntityName});
public sealed record {EntityName}SavedMessage({EntityName} Saved{EntityName});
Service Interface
namespace {Namespace}.Services;
public interface I{EntityName}Service
{
Task<IReadOnlyList<{EntityName}>> GetAllAsync(CancellationToken cancellationToken = default);
Task<{EntityName}?> GetByIdAsync(int id, CancellationToken cancellationToken = default);
Task SaveAsync({EntityName} entity, CancellationToken cancellationToken = default);
Task DeleteAsync(int id, CancellationToken cancellationToken = default);
}
출력 형식
모든 내용은 한국어로 작성합니다. 코드 식별자와 기술 용어는 원문을 유지합니다.
# MVVM 생성 결과
## 엔티티: {EntityName}
### 생성된 파일
| 파일 | 경로 | 상태 |
|------|------|------|
| Model | /Models/{EntityName}.cs | 생성됨 |
| ViewModel | /ViewModels/{EntityName}ViewModel.cs | 생성됨 |
| View | /Views/{EntityName}View.xaml | 생성됨 |
| Code-Behind | /Views/{EntityName}View.xaml.cs | 생성됨 |
| Messages | /Messages/{EntityName}Messages.cs | 생성됨 |
| Service Interface | /Services/I{EntityName}Service.cs | 생성됨 |
### 다음 단계
1. `I{EntityName}Service` 구현
2. DI 컨테이너에 등록
3. View 내비게이션 추가
4. 필요 시 디자인 타임 데이터 생성
에러 처리
| 상황 | 처리 |
|---|---|
| 엔티티 이름 미입력 | 사용자에게 요청, 기존 Model 기반 제안 |
| 유효하지 않은 이름 (특수문자, 예약어) | 사용자에게 재입력 요청 |
| ViewModels/Views/Models 디렉토리 없음 | 디렉토리 자동 생성 후 진행 |
| 동일 이름 파일 존재 | 사용자에게 덮어쓰기 확인 |
가이드라인
- CommunityToolkit.Mvvm source generator를 사용합니다
- 기존 프로젝트 명명 규칙을 따릅니다
- 최소한의 Code-Behind을 생성합니다 (UI 로직만)
- 적절한 XML 문서화를 포함합니다
- 비동기 작업에 CancellationToken을 지원합니다
- ViewModel 간 통신에 WeakReferenceMessenger를 사용합니다
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/jeongheonk/c-sharp-custom-marketplace/wpf-mvvm-generator">View wpf-mvvm-generator on skillZs</a>