Mô hình Model-View-ViewModel (MVVM) giúp bạn tách riêng business và presentation logic của ứng dụng khỏi giao diện người dùng (UI).
Các bài liên quan
- Prism là gì ? các khái niệm chính trong Prism Library 5.0 for WPF
- Prism Library 5.0 for WPF – Khởi tạo ứng dụng
- Prism Library 5.0 for WPF – Implementing MVVM Pattern
- Prism Library 5.0 for WPF – Sử dụng Event Aggregation xây dựng một composite application
Hình minh họa dưới đây cho thấy ba lớp MVVM và tương tác của chúng.

Bài viết này mình chỉ tập trung dịch và giới thiệu các việc Implementing MVVM Pattern theo Prism Library. Các bạn có thể tham khảo bài viết sau để hiểu chi tiết về MVVM: WPF MVVM step by step (Basics to Advance Level)
View Class
- Là nơi chứa các visual element, như window, page, user control,..
- View tham chiếu đến View Model thông qua DataContext property.
- Bạn có thể sử dụng converters để custom lại giá trị được binding từ View Model lên View. xem thêm converters ở đây
- code-behind của view nên được dùng để đinh nghĩa các code login liên quan đến giao diện hoặc các chức năng liên quan đến giao diện mà bạn khó tthuwjc hiện bằng xaml
View Model Class
- implement các properties và command mà view có thể data bind.Nó thông báo cho view bất cứ state changes thông qua notification events thông qua INotifyPropertyChanged và INotifyCollectionChanged interfaces.
- Nó cũng có thể đùng để implement data validation thông qua IDataErrorInfo hoặc INotifyDataErrorInfo interfaces.
- View model có thể định nghĩa các trạng thái logic mà view thể hiện trực quan cho người dùng.
Data context
Bạn cũng có thể chỉ định trong XAML rằng view model được thiết lập cho view thông qua data context.
<UserControl.DataContext>
<my:MyViewModel/>
</UserControl.DataContext>
hoặc từ code của view
public MyView()
{
InitializeComponent();
this.DataContext = new MyViewModel();
}
Tương tác giữa các class
Sự tương tác giữa View và View model của nó có lẽ là điều quan trọng nhất cần xem xét nhưng sự tương tác giữa Model và View model cũng rất quan trọng.
Data Binding
Chúng ta sử dụng data binding để tương tác 1 properties giữa View và Viewmodel. có thể nói dễ hiểu là bạn có 1 properties ở view model bạn muốn nó hiện vào 1 Textbox trên view và khi người ta nhập liệu trên view bạn muốn giá trị đó được gán xuống view model. Các bạn có thể xem giải thích chi tiết ở đây
Implementing INotifyPropertyChanged
Thư viện Prism cung cấp lớp cơ sở BindableBase, từ đó bạn có thể implement INotifyPropertyChanged interface một cách an toàn, như được hiển thị ở đây.
public abstract class BindableBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; ... protected virtual bool SetProperty(ref T storage, T value, [CallerMemberName] string propertyName = null) {...} protected void OnPropertyChanged( Expression<Func> propertyExpression) {...} protected void OnPropertyChanged(string propertyName) {...} }
Để khai báo 1 propeties bạn tham khảo code như bên dưới
public TransactionInfo TransactionInfo { get { return this.transactionInfo; } set { SetProperty(ref this.transactionInfo, value); // nếu muốn raised PropertyChanged cho thuộc tính TickerSymbol this.OnPropertyChanged(() => this.TickerSymbol); } }
Implementing INotifyCollectionChanged
Trong nhiều trường hợp chúng ta cần binding một danh sách lên view. khi đó bạn sẽ binding thông qua ItemSource property.
<DataGrid ItemsSource="{Binding Path=LineItems}" />
Và cách danh sách các bạn nên implement theo INotifyCollectionChanged interface, tức là chúng ta sẽ sử dụng ObservableCollection<T> . Bởi vì lớp ObservableCollection <T> implement INotifyCollectionChanged interface, các điều khiển trong view sẽ được tự động cập nhật để phản ánh danh sách hiện tại khi có item được thêm vào hoặc xoá. Tham khảo code bên dưới.
public class OrderViewModel : BindableBase { public OrderViewModel( IOrderService orderService ) { this.LineItems = new ObservableCollection( orderService.GetLineItemList() ); } public ObservableCollection LineItems { get; private set; } }
Implementing ICollectionView
Khi bạn cần ncho phép danh sách được filter hoặc sort hoặc bạn cần track selected item trong view để commands trong view model có thể hành động theo selected item hiện tại.
WPF hỗ trợ các kịch bản này bằng cách cung cấp các lớp khác nhau thực hiện giao diện ICollectionView. Giao diện này cung cấp các thuộc tính và phương pháp để cho phép danh sách được lọc, sắp xếp hoặc nhóm và cho phép theo dõi hoặc thay đổi mục được chọn hiện tại. WPF cung cấp một sự thực hiện của giao diện này bằng cách sử dụng lớp ListCollectionView.
Trong WPF, một khung nhìn mặc định sẽ được tự động tạo ra bất cứ khi nào control được ràng buộc với một danh sách.
Ví dụ mã sau đây cho thấy việc sử dụng ListCollectionView trong WPF để theo dõi khách hàng hiện đang được chọn.
public class MyViewModel : BindableBase { public ICollectionView Customers { get; private set; } public MyViewModel( ObservableCollection customers ) { // Initialize the CollectionView for the underlying model // and track the current selection. Customers = new ListCollectionView( customers ); Customers.CurrentChanged +=SelectedItemChanged; } private void SelectedItemChanged( object sender, EventArgs e ) { Customer current = Customers.CurrentItem as Customer; ... } ...
Ở View
<ListBox ItemsSource="{Binding Path=Customers}"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel> <TextBlock Text="{Binding Path=Name}"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox>
Commands
khi chúng ta cần implement một action nào đó con control mà gọi xuống view model chúng ta sẽ dùng Commands. ví dụ click vào 1 nút, chọn giá trị trong dropdownlist.
Để khai báo commands bạn tham khỏa code sau
public class QuestionnaireViewModel { public QuestionnaireViewModel() { this.SubmitCommand = new DelegateCommand(this.OnSubmit, this.CanSubmit ); } public ICommand SubmitCommand { get; private set; } private void OnSubmit() { ///implement xử lý ở đây } private bool CanSubmit() { // có thể dùng để validate return true; } }
Trên view
<Button Command="{Binding Path=SubmitCommand}" />
Các bạn có thể xem thêm tại đây
Tương tác Triggers và Commands
Sau đây cho thấy cách sử dụng Blend EventTrigger được cấu hình để nghe sự kiện SelectionChanged của ListBox. Khi sự kiện này xảy ra, SelectedCommand được gọi ra bởi InvokeCommandAction.
namespace interactivity cho XAML:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
<ListBox ItemsSource="{Binding Items}" SelectionMode="Single"> <i:Interaction.Triggers> <i:EventTrigger EventName="SelectionChanged"> <i:InvokeCommandAction Command="{Binding SelectedCommand}" /> </i:EventTrigger> </i:Interaction.Triggers> </ListBox>
Bài viết Prism Library 5.0 for WPF – Implementing MVVM Pattern
Pingback: Prism Library 5.0 for WPF – Khởi tạo ứng dụng | Phạm Duy Anh
Pingback: Bài 2: Tạo một ứng dụng với MVVM đơn giản – Từng bước triển khai MVVM trong WPF | Phạm Duy Anh
Pingback: Bài 2: Tạo một ứng dụng đơn giản với mô hình MVVM – Từng bước triển khai MVVM trong WPF | Phạm Duy Anh