06. AsyncRelayCommand<T>

1️⃣ AsyncRelayCommand<T> 개요
더보기
📚 Microsoft Docs: AsyncRelayCommand
✅ AsyncRelayCommand<T> 개요
MVVM에서 비동기 작업을 Command로 실행하기 위해 사용하는 구조입니다.
여기서 <T>는 CommandParameter로 전달될 인자의 타입입니다.
✅ 사용 예시
문제 | 상황해결 방법 |
버튼 클릭 시 API 요청, 파일 다운로드 등 시간이 걸리는 작업이 필요 | async/await로 비동기 처리 |
ViewModel에서 Command 방식으로 비동기 로직 호출 | AsyncRelayCommand<T> 사용 |
작업 중 중복 실행 방지 | 내부적으로 IsRunning 상태 추적 가능 |
예외 처리를 깔끔하게 하고 싶음 | Try/Catch로 비동기 에러 관리 가능 |
✅ RelayCommand에 CanExecute 연동하는 방법
[RelayCommand(CanExecute = nameof(CanGreet))] // → 이 속성 하나로 CanExecute 메서드 자동 연결됨 private void Greet() { Debug.WriteLine($"안녕하세요, {userName}님!"); } private bool CanGreet() { return !string.IsNullOrWhiteSpace(userName); }
2️⃣ 예제 - AsyncRelayCommand<T>
더보기






✔️ 1. 동작 시나리오

- 기능:
- 버튼 클릭 시
- 지연시간 2초 로딩 과정에서 로딩중 메시지 출력
- 비동기 로딩 → 이름 + 인사 메시지 출력
- 중복 클릭 시 자동 비활성화 (AsyncRelayCommand)
- 기술 포인트:
- [RelayCommand] + async Task (비동기 작업) 구현
- 명령 실행 중 자동 비활성화
- UserService를 통한 서비스 추상화
- MVVM 구조 적용
✔️ 2. Async 구현
🔍 2.1 프로젝트 구조
AsyncCommandTestApp/ ├── Models/ │ └── User.cs ├── Services/ │ └── IUserService.cs │ └── UserService.cs ├── ViewModels/ │ └── MainViewModel.cs ├── MainWindow.xaml └── MainWindow.xaml.cs
🔍 2.2 Model 클래스 만들기

namespace WPF_ToolKit04_06.Model { // User 클래스는 MVVM 아키텍처에서 Model 역할을 수행합니다. // 이 클래스는 사용자 데이터를 표현하며, ViewModel과 Service에서 데이터를 주고받는 데 사용됩니다. public class User { // 사용자 이름을 저장하는 속성입니다. // 기본값은 빈 문자열로 초기화되어 있으며, 비어 있는 상태에서도 안전하게 사용 가능합니다. public string Name { get; set; } = string.Empty; } }
🔍 2.3 Interface 만들기

using WPF_ToolKit04_06.Model; namespace WPF_ToolKit04_06.Service { // IUserService 인터페이스는 사용자 정보를 가져오는 서비스를 정의합니다. // MVVM 패턴에서 ViewModel은 이 인터페이스에 의존함으로써 // 구현체(UserService)에 대한 직접적인 의존을 피하고 느슨한 결합(Loosely Coupled)을 유지할 수 있습니다. // 테스트 또는 확장 시 다양한 구현체(UserServiceMock 등)를 대체하여 활용할 수 있습니다. public interface IUserService { // 비동기 방식으로 현재 사용자 정보를 가져오는 메서드 정의입니다. // 실제 구현은 UserService 클래스에서 담당하며, API 또는 데이터베이스에서 데이터를 가져올 수 있습니다. Task<User> GetCurrentUserAsync(); } }
🔍 2.4 Service 클래스 만들기

public class UserService : IUserService { // GetCurrentUserAsync 메서드는 사용자 정보를 비동기적으로 반환합니다. // 실제 프로젝트에서는 이 메서드가 데이터베이스, 웹 API, 파일 등에서 데이터를 로드하도록 구현됩니다. // 여기서는 Task.Delay를 통해 2초간 지연시켜 비동기 처리의 흐름을 학습할 수 있도록 구성되어 있습니다. public async Task<User> GetCurrentUserAsync() { await Task.Delay(2000); // 사용자 정보 로딩 시뮬레이션 (예: API 호출 대기) // 사용자 정보를 담은 User 객체를 반환합니다. // 실습 목적상 정적인 데이터를 반환하지만, 실제 구현에서는 외부 소스에서 가져온 데이터를 기반으로 구성됩니다. return new User { Name = "홍길동" }; } }
🔍 2.5 ViewModel 클래스 만들기

using WPF_ToolKit04_06.Model; using WPF_ToolKit04_06.Service; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; namespace WPF_ToolKit04_06.ViewModel { // MainViewModel 클래스는 MVVM 패턴에서 ViewModel에 해당하며, // View와 Model(Service) 사이의 데이터 바인딩과 명령 처리를 담당합니다. // ObservableObject를 상속받아 속성 변경 알림(INotifyPropertyChanged)을 자동으로 처리합니다. public partial class MainViewModel : ObservableObject { // IUserService 인터페이스를 통해 사용자 정보를 제공받는 의존성 주입 필드입니다. // ViewModel은 인터페이스에만 의존하고 구체적인 구현은 외부에서 주입되므로 테스트와 유지보수에 유리합니다. private readonly IUserService userService; // 생성자에서 IUserService 구현체를 주입받아 ViewModel 내부에서 사용할 수 있게 합니다. public MainViewModel(IUserService userService) { this.userService = userService; } // 사용자 인사 메시지를 저장하는 속성입니다. // ObservableProperty 특성을 사용하면 자동으로 Greeting 속성이 생성되고 // 속성 값 변경 시 View에 자동으로 알림이 전파됩니다. [ObservableProperty] private string? greeting; // GreetUser는 버튼 클릭 시 실행될 비동기 명령 메서드입니다. // [RelayCommand] 특성을 사용하면 GreetUserCommand 또는 GreetUserCommandAsync 같은 ICommand 속성이 자동 생성됩니다. // async 메서드를 사용하므로 CommunityToolkit은 내부적으로 AsyncRelayCommand를 생성합니다. // 실행 중에는 명령이 자동으로 비활성화되어 중복 실행을 방지합니다. [RelayCommand] private async Task GreetUser() { Greeting = "사용자 정보를 가져오는 중..."; Console.WriteLine(Greeting); // 서비스에서 사용자 정보를 비동기로 가져옵니다 (예: API 호출, DB 조회 등) User user = await userService.GetCurrentUserAsync(); // 사용자 이름을 포함한 인사 메시지를 설정하고, UI에 자동 반영됩니다. Greeting = $"안녕하세요, {user.Name}님!"; Console.WriteLine(Greeting); } } }
🔍 2.6 XAML 화면 구성

Title="GreetApp" Height="200" Width="300"> <StackPanel Margin="20" VerticalAlignment="Center"> <!-- 버튼 UI 요소. Content: 버튼에 표시될 텍스트. Command: ViewModel에 정의된 GreetUser 메서드에서 생성된 GreetUserCommand 속성과 바인딩됨. [RelayCommand] 특성이 붙은 GreetUser 메서드는 MVVM Toolkit이 자동으로 GreetUserCommand라는 ICommand 속성을 생성해 줌. 사용자가 버튼을 클릭하면 GreetUserCommand가 실행되고, ViewModel에서 사용자 정보를 비동기로 가져와 인사 메시지를 구성함. --> <Button Content="사용자에게 인사하기" Command="{Binding GreetUserCommand}" Margin="0,0,0,10" /> <!-- 사용자에게 인사 메시지를 보여주는 TextBlock. Text 속성이 ViewModel의 Greeting 속성과 바인딩되어 있음. ViewModel의 Greeting 속성이 변경되면 INotifyPropertyChanged에 의해 UI가 자동으로 갱신됨. FontWeight="Bold": 텍스트 강조 FontSize="14": 글자 크기 TextWrapping="Wrap": 텍스트가 길 경우 자동 줄바꿈 --> <TextBlock Text="{Binding Greeting}" FontWeight="Bold" FontSize="14" TextWrapping="Wrap"/> </StackPanel>
✔️ 결과
- 항목 클릭 시 ViewModel.SelectedItem이 변경되며, 해당 항목의 IsSelected가 true가 됩니다.
- 트리거에 의해 선택된 항목만 배경색이 변경됩니다.
3️⃣ 예제 - AsyncRelayCommand<T> 동작 구조
더보기

✔️ 1. 예제의 RelayCommand<T> 살펴보기
// 사용자 정보 로딩 서비스 public class UserService : IUserService { public async Task<User> GetCurrentUserAsync() { await Task.Delay(2000); // 사용자 정보 로딩 지연 시뮬레이션 return new User { Name = "홍길동" }; } }
public partial class MainViewModel : ObservableObject { [RelayCommand] private async Task GreetUser() { Greeting = "사용자 정보를 가져오는 중..."; Console.WriteLine(Greeting); // 서비스에서 사용자 정보를 비동기로 가져옵니다 (예: API 호출, DB 조회 등) User user = await userService.GetCurrentUserAsync(); Greeting = $"안녕하세요, {user.Name}님!"; Console.WriteLine(Greeting); } }
✔️ 2. 자동 생성되는 코드

댓글을 사용할 수 없습니다.