이전 포스팅에서 도서 상세페이지로 이동하는 기능을 모두 구현하였습니다. 이번 포스팅에서는 도서 상세 페이지로 이동할 때 파라미터를 넘기는 다른 방식을 소개하려 합니다. 이전 방식에서는 아래와 같이 도서 리스트 페이지에서 상세 페이지로 이동할 때 Book 객체를 넘겨 주었습니다.
[MainPage.xaml]
<Frame.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:BookListViewModel}}, Path=GetBookDetailCommand}" CommandParameter="{Binding .}" />
</Frame.GestureRecognizers>
MainPage.xaml 에서는 특정 도서를 클릭했을 때 선택한 Book 객체를 BookListViewModel 의 GetBookDetailCommand 의 파라미터로 넘겨주었습니다.
BookListViewModel.cs
[RelayCommand]
public async Task GetBookDetail(Book book)
{
if (book == null) return;
await Shell.Current.GoToAsync(nameof(BookDetailPage), true, new Dictionary<string, object>
{
{nameof(Book), book }
});
}
GetBookDeatail 메서드에서는 “Book” 이라는 파라미터이름으로 book 객체를 BookDetailPage 로 넘겨주었습니다. BookDetailPage 에서는 BindingContext 로 BookDetailViewModel 이 설정되어 있기 때문에 BookDetailPage 로 넘겨준 book 객체는 BookDetailViewModel 에 전달이 됩니다.
[BookDetailViewModel.cs]
[QueryProperty(nameof(Book), "Book")]
public partial class BookDetailViewModel : BaseViewModel
{
[ObservableProperty]
Book book;
public BookDetailViewModel()
{
}
}
[QueryProperty 어노테이션을 통해서 전달된 book 객체는 BookDetailViewModel 의 ObservableProperty 인 book 에 할당이 됩니다. BookDetailPage 에서는 BookDetailViewModel 의 Book 속성을 이용해서 화면에 도서 상세 정보를 표현하게 됩니다.
이번에는 Book 객체를 파라미터로 넘기는 대신의 Book 의 Id 속성을 파라미터로 전달해서 동일한 기능을 구현해보도록 하겠습니다. MainPage.xaml 을 아래와 같이 변경해 보겠습니다.
<Frame.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:BookListViewModel}}, Path=GetBookDetailCommand}" CommandParameter="{Binding Id}" />
</Frame.GestureRecognizers>
{Binding .} 로 Book 객체를 넘겨주던 방식을 {Binding Id} 로 변경하였습니다.
[BookListViewModel.cs]
[RelayCommand]
public async Task GetBookDetail(int id)
{
if (id == 0) return;
await Shell.Current.GoToAsync($"nameof(BookDetailPage)?Id={id}");
}
GetBookDetail 메서드에서는 네비게이션 문자열을 이용해서 BookDetailPage 로 이동하고 있고, Id 속성에 파라미터로 넘어온 id 값을 할당하고 있습니다. 해당 id 값을 BookDetailViewModel 에서 어떻게 처리하는 지 확인해 보겠습니다.
BookDetailViewModel.cs
public partial class BookDetailViewModel : BaseViewModel, IQueryAttributable
{
BookService bookService;
[ObservableProperty]
Book book;
[ObservableProperty]
int id;
public BookDetailViewModel(BookService bookService)
{
this.bookService = bookService;
}
public void ApplyQueryAttributes(IDictionary<string, object> query)
{
Id = Convert.ToInt32(HttpUtility.UrlDecode(query[nameof(Id)].ToString()));
Book = bookService.GetBook(Id);
}
}
수정된 점을 요약하면 아래와 같습니다.
- 넘어온 파라미터를 저장할 ObservableProperty 정의
- IQueryAttributable 인터페이스 구현
이 코드에서 BookDetailViewModel은 BaseViewModel을 상속받고 있으며, .NET MAUI에서 페이지 간 네비게이션 시 쿼리 매개변수를 받기 위해 IQueryAttributable 인터페이스를 구현하고 있습니다.
주요 흐름
- ViewModel 생성자에서 BookService를 주입받습니다. 이는 의존성 주입(Dependency Injection)을 활용하여 BookService를 사용하는 방식입니다.
- ApplyQueryAttributes 메서드는 페이지 네비게이션 시 전달된 쿼리 매개변수를 처리합니다.
- 전달된 Id 쿼리 매개변수를 HttpUtility.UrlDecode로 디코딩한 후, 정수형으로 변환(Convert.ToInt32)하여 Id 속성에 저장합니다.
- BookService를 통해 해당 Id에 해당하는 책 정보를 가져와 Book 속성에 저장합니다.
이러한 과정을 통하여 Book 속성이 업데이트 되고 , BookDetailView 에서는 BindingContext 인 BookListViewModel 의 변경된 Book 속성을 기반으로 도서 상세 내역을 표시하게 됩니다. 아래는 실행화면 모습입니다.