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

Ở bài trước, tôi đã giới thiệu vơi các bạn về mô hình MVVM, bài này tôi sẽ hướng dẫn bạn các tạo 1 ứng dụng đơn giản bằng môn hình MVVM.

Bài 1: Mô hình MVVM là gì? – Từng bước triển khai MVVM trong WPF

1. Tạo project và ứng dụng đầu tiên

chúng ta sẽ tạo một ứng dụng đơn giản, tính tổng hai số A và B và kết quả sẽ được giữ lại ở Datagrid bên dưới. Giao diện như bên dưới

XAML

<Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="3*"/>
            <ColumnDefinition Width="7*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition Height="200"/>
        </Grid.RowDefinitions>
        <Label  Content="Số A" VerticalAlignment="Center"/>
        <Label Grid.Row="1"  Content="Số B" VerticalAlignment="Center"/>
        <Label Grid.Row="2"  Content="A + B" VerticalAlignment="Center"/>
        <TextBox Name="soA" Grid.Column="1" VerticalAlignment="Center" />
        <TextBox Name="soB" Grid.Column="1" Grid.Row="1" VerticalAlignment="Center" />
        <TextBox Name="tongAB" Grid.Column="1" Grid.Row="2" VerticalAlignment="Center" />
        <Button Grid.Column="1" Grid.Row="3" VerticalAlignment="Center" Content="Tính tổng" HorizontalAlignment="Center" />
        <DataGrid Grid.Row="4" Grid.ColumnSpan="2" />
    </Grid>

UI

2. Cài đặt Prism.Wpf

Trong bài viết này tôi sẽ sử dụng Prism để làm ví dụ về mô hình MVVM.

Chúng ta sẽ add nuget Prism.Wpf vào project hiện tại

https://www.nuget.org/packages/Prism.Wpf/7.2.0.1422

bước tiếp theo chúng ta sẽ tạo các class trong Mô hình MVVM.

3. Tạo Model class

Tạo class SimpleClass như bên dưới

Code

namespace WpfAppMVVM.Model
{
   public class SimpleClass
    {
        public int SoA { get; set; }
        public int SoB { get; set; }
        public int TongAB { get; set; }

        /// <summary>
        /// khởi tạo dũ liệu
        /// </summary>
        /// <returns></returns>
        public List<SimpleClass> khoiTaoDuLieu()
        {
            List<SimpleClass> lstResult = new List<SimpleClass>();
            lstResult.Add(new SimpleClass { SoA = 1, SoB = 2, TongAB = 3 });
            lstResult.Add(new SimpleClass { SoA = 4, SoB = 7, TongAB = 11 });
              return lstResult;
        }
    }
}

4. Tạo ViewModel class

Tạo ViewModel như bên dưới, using Prism.Mvvm và class SimpleVM sẽ kế thừa class BindableBase

Implement các properties

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.

 public class SimpleVM : BindableBase
    {
        #region  properties

        //So Thu 1
        public int _soThu1;
        public int SoThu1
        {
            get
            {
                return this._soThu1;
            }
            set
            {
                SetProperty(ref this._soThu1, value);
            }
        }

        //So Thu 2
        public int _soThu2;
        public int SoThu2
        {
            get
            {
                return this._soThu2;
            }
            set
            {
                SetProperty(ref this._soThu2, value);
            }
        }

     //Tong
        public int _tong;
        public int Tong
        {
            get
            {
                return this._tong;
            }
            set
            {
                SetProperty(ref this._tong, value);
            }
        }


        //Danh sách Tổng, để binding lên DataGrid
        public ObservableCollection<SimpleClass> _lstTong;
        public ObservableCollection<SimpleClass> lstTong
        {
            get
            {
                return this._lstTong;
            }
            set
            {
                SetProperty(ref this._lstTong, value);
            }
        }
      
        #endregion
    }

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

Implement các commmand

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

Để khai báo commands  bạn tham khảo code sau

 #region commmand


        public DelegateCommand SubmitCommand { get; private set; }

        private void OnSubmit()
        {
            ///implement xử lý ở đây
            Tong = SoThu1 + SoThu2;
            // add vào danh sách history, để cập nhật lên view
            lstTong.Add(new SimpleClass { SoA = SoThu1, SoB = SoThu2, TongAB = Tong });
        }
        private bool CanSubmit()
        {
            // chỉ được click khi nhập 2 số thứ 1 và số thứ 2
            if (SoThu1 != 0 && SoThu2 != 0)
                return true;
            else
                return false;
        }
        #endregion

        /// <summary>
        /// SimpleVM constructor
        /// </summary>
        public SimpleVM()
        {
            this.SubmitCommand = new DelegateCommand(this.OnSubmit, this.CanSubmit);
  // khởi tạo dữ liệu ban đầu cho datagrid
            SimpleClass temp = new SimpleClass();
            lstTong = new ObservableCollection<SimpleClass>(temp.khoiTaoDuLieu());
        }

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

mở file MainWindow.xaml và thêm dòng sau vào

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

mở file MainWindow.xaml và chúng ta tiến hành việc binding data

<Label  Content="Số A" VerticalAlignment="Center"/>
        <Label Grid.Row="1"  Content="Số B" VerticalAlignment="Center"/>
        <Label Grid.Row="2"  Content="A + B" VerticalAlignment="Center"/>
        <TextBox Name="soA" Text="{Binding SoThu1,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Grid.Column="1" VerticalAlignment="Center" />
        <TextBox Name="soB" Text="{Binding SoThu2,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Grid.Column="1" Grid.Row="1" VerticalAlignment="Center" />
        <TextBox Name="tongAB" Text="{Binding Tong,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Grid.Column="1" Grid.Row="2" VerticalAlignment="Center" />
        <Button Grid.Column="1" Command="{Binding SubmitCommand}"  Grid.Row="3" VerticalAlignment="Center" Content="Tính tổng" HorizontalAlignment="Center" />
        <DataGrid Grid.Row="4" ItemsSource="{Binding lstTong}" Grid.ColumnSpan="2" />

Set command cho button Tính tổng

<Button Grid.Column="1" Command="{Binding SubmitCommand}"  Grid.Row="3" VerticalAlignment="Center" Content="Tính tổng" HorizontalAlignment="Center" />

Chúng ta sẽ run app và xem kết quả

bạn sẽ thấy là nút “Tính tổng sẽ chưa click được. vì điều kiện trong hàm CanSubmit ở viewmodel chúng ta đã viết

   private bool CanSubmit()
        {
            // chỉ được click khi nhập 2 số thứ 1 và số thứ 2
            if (SoThu1 != 0 && SoThu2 != 0)
                return true;
            else
                return false;
        }

và vì khi số thứ 1 và số thứ 2 có thay đổi giá trị, chúng ta chưa gọi hàm CanSubmit lại. chúng ta cần phải gọi RaiseCanExecuteChanged method để command’s CanExecute có thể được gọi và kiểm tra lại trạng thái.

The view model can indicate a change in the command’s CanExecute status by calling the RaiseCanExecuteChanged method on the DelegateCommand object. This causes the CanExecuteChanged event to be raised. Any controls in the UI that are bound to the command will update their enabled status to reflect the availability of the bound command.

 //So Thu 1
        public int _soThu1;
        public int SoThu1
        {
            get
            {
                return this._soThu1;
            }
            set
            {
                SetProperty(ref this._soThu1, value);
               SubmitCommand.RaiseCanExecuteChanged();
            }
        }

        //So Thu 2
        public int _soThu2;
        public int SoThu2
        {
            get
            {
                return this._soThu2;
            }
            set
            {
                SetProperty(ref this._soThu2, value);
                SubmitCommand.RaiseCanExecuteChanged();
            }
        }

Run lại chương trình, bạn hãy thử các cặp số sau cho A và B

A=0 B=1 => nút tính tổng disable

A=1 B=0 => nút tính tổng disable

A>0 B>0 => nút tính tổng enable

Như vậy chúng ta đã hoàn thành một ứng dụng đơn giản sử dụng mô hình MVVM (prism). Nếu có thắc mắc và góp ý gì các bạn hãy để lại comment bên dưới .

Tham khảo

Leave a Reply

Your email address will not be published. Required fields are marked *