0
0
Lập trình
Harry Tran
Harry Tran106580903228332612117

So sánh MVC và MVVM: Mô hình luồng thực tế - Phần 2

Đăng vào 1 tháng trước

• 14 phút đọc

Phần 2: Mô hình luồng MVVM chi tiết

Trong khi MVC điều phối các chu kỳ yêu cầu-phản hồi tuần tự, MVVM tạo ra một mạng phản ứng nơi các thay đổi tự động lan truyền qua các liên kết. Mnemonic IVVMM ám chỉ đến tính chất hai chiều này, nhưng các ứng dụng MVVM sản xuất lại kết hợp nhiều luồng đồng thời mà có thể làm cồng kềnh một kiến trúc dựa trên bộ điều khiển truyền thống.

2.1 Luồng View trực tiếp

Quản lý trạng thái hình ảnh

MVVM cho phép các view quản lý trạng thái hình ảnh của chúng mà không cần liên quan đến ViewModel:

xaml Copy
<UserControl x:Class="TradingApp.StockTickerView">
    <Grid>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="PriceStates">
                <VisualState x:Name="PriceUp">
                    <Storyboard>
                        <ColorAnimation Storyboard.TargetName="PricePanel"
                                      Storyboard.TargetProperty="Background.Color"
                                      To="LightGreen" Duration="0:0:0.3"/>
                        <DoubleAnimation Storyboard.TargetName="ArrowUp"
                                       Storyboard.TargetProperty="Opacity"
                                       To="1" Duration="0:0:0.3"/>
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="PriceDown">
                    <Storyboard>
                        <ColorAnimation Storyboard.TargetName="PricePanel"
                                      Storyboard.TargetProperty="Background.Color"
                                      To="LightPink" Duration="0:0:0.3"/>
                        <DoubleAnimation Storyboard.TargetName="ArrowDown"
                                       Storyboard.TargetProperty="Opacity"
                                       To="1" Duration="0:0:0.3"/>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <i:Interaction.Triggers>
            <ei:DataTrigger Binding="{Binding PriceDirection}" Value="Up">
                <ei:GoToStateAction StateName="PriceUp"/>
            </ei:DataTrigger>
            <ei:DataTrigger Binding="{Binding PriceDirection}" Value="Down">
                <ei:GoToStateAction StateName="PriceDown"/>
            </ei:DataTrigger>
        </i:Interaction.Triggers>
        <Border x:Name="PricePanel">
            <TextBlock Text="{Binding Price, StringFormat=C}"/>
        </Border>
    </Grid>
</UserControl>

Điều này tạo ra một luồng mà các thay đổi thuộc tính kích hoạt các chuyển tiếp trạng thái hình ảnh hoàn toàn trong lớp view, giữ cho logic trình bày ra ngoài ViewModel.

Cập nhật UI liên tục

Các view có thể kích hoạt các cập nhật liên tục thông qua các liên kết khai báo:

xaml Copy
<Window x:Class="DashboardApp.MainWindow">
    <Grid>
        <ComboBox x:Name="RegionSelector" 
                  ItemsSource="{Binding Regions}"
                  SelectedItem="{Binding SelectedRegion}"/>
        <TabControl>
            <TabItem Header="Sales" 
                     Visibility="{Binding SelectedRegion.HasSalesData, 
                                         Converter={StaticResource BoolToVisibility}}">
                <DataGrid ItemsSource="{Binding SelectedRegion.SalesData}"/>
            </TabItem>
            <TabItem Header="Inventory">
                <StackPanel>
                    <ComboBox ItemsSource="{Binding SelectedRegion.Warehouses}"
                            SelectedItem="{Binding SelectedWarehouse}"/>
                    <DataGrid ItemsSource="{Binding SelectedWarehouse.Products}">
                        <DataGrid.RowDetailsTemplate>
                            <DataTemplate>
                                <ItemsControl ItemsSource="{Binding StockMovements}"/>
                            </DataTemplate>
                        </DataGrid.RowDetailsTemplate>
                    </DataGrid>
                </StackPanel>
            </TabItem>
        </TabControl>
        <TextBlock>
            <TextBlock.Text>
                <MultiBinding StringFormat="Region: {0}, Sales: {1:C}, Products: {2}">
                    <Binding Path="SelectedRegion.Name"/>
                    <Binding Path="SelectedRegion.TotalSales"/>
                    <Binding Path="SelectedWarehouse.Products.Count"/>
                </MultiBinding>
            </TextBlock.Text>
        </TextBlock>
    </Grid>
</Window>

Mỗi thay đổi lựa chọn lan truyền qua các liên kết phụ thuộc, tạo ra các luồng View → View phức tạp mà không cần mã lệnh.

2.2 Luồng Lệnh và Sự kiện

Triển khai mẫu lệnh

Lệnh trong MVVM đóng gói các hành động với quản lý trạng thái UI tự động:

csharp Copy
public class OrderViewModel : ViewModelBase
{
    private readonly IOrderService _orderService;
    private bool _isProcessing;

    public OrderViewModel(IOrderService orderService)
    {
        _orderService = orderService;
        SubmitOrderCommand = new RelayCommand(
            execute: async () => await SubmitOrderAsync(),
            canExecute: () => !_isProcessing && IsOrderValid()
        );
        PropertyChanged += (s, e) =>
        {
            if (e.PropertyName == nameof(IsProcessing) || 
                e.PropertyName == nameof(OrderItems))
            {
                SubmitOrderCommand.RaiseCanExecuteChanged();
            }
        };
    }

    public ICommand SubmitOrderCommand { get; }

    private async Task SubmitOrderAsync()
    {
        IsProcessing = true;
        try
        {
            var order = await _orderService.SubmitOrderAsync(OrderItems);
            OrderConfirmation = order;
            OrderItems.Clear();
        }
        catch (Exception ex)
        {
            ErrorMessage = ex.Message;
            ErrorVisibility = Visibility.Visible;
        }
        finally
        {
            IsProcessing = false;
        }
    }
}

Tích hợp dịch vụ bên ngoài

MVVM xử lý các cuộc gọi dịch vụ bên ngoài thông qua các lệnh với các cập nhật phản ứng:

csharp Copy
public class WeatherViewModel : ViewModelBase
{
    private readonly IWeatherService _weatherService;

    public WeatherViewModel()
    {
        RefreshCommand = new RelayCommand(async () => await RefreshWeatherAsync());
        InitializeAutoRefresh();
    }

    private void InitializeAutoRefresh()
    {
        var timer = new DispatcherTimer { Interval = TimeSpan.FromMinutes(5) };
        timer.Tick += async (s, e) =>
        {
            if (AutoRefreshEnabled)
                await RefreshWeatherAsync();
        };
        timer.Start();
    }

    private async Task RefreshWeatherAsync()
    {
        IsRefreshing = true;
        try
        {
            var location = await _locationService.GetCurrentLocationAsync();
            var weather = await _weatherService.GetWeatherAsync(location);
            CurrentWeather = weather;
        }
        finally
        {
            IsRefreshing = false;
        }
    }
}

Thông báo đẩy

Các thay đổi trong mô hình có thể đẩy cập nhật qua ViewModels đến Views:

csharp Copy
public class StockPortfolioViewModel : ViewModelBase, IDisposable
{
    private readonly IStockPriceService _priceService;
    public ObservableCollection<StockViewModel> Stocks { get; }

    public StockPortfolioViewModel(IStockPriceService priceService)
    {
        _priceService = priceService;
        Stocks = new ObservableCollection<StockViewModel>();
        var subscription = _priceService.PriceUpdates.Subscribe(update =>
        {
            var stock = Stocks.FirstOrDefault(s => s.Symbol == update.Symbol);
            if (stock != null)
            {
                stock.Price = update.Price;
            }
        });
    }
}

2.3 Giao tiếp Multi-ViewModel

Mẫu Messenger/Mediator

Các ViewModels giao tiếp mà không cần tham chiếu trực tiếp thông qua messaging:

csharp Copy
public class OrderPlacedMessage
{
    public Order Order { get; set; }
}

public class OrderViewModel : ViewModelBase
{
    private readonly IMessenger _messenger;

    private async Task PlaceOrderAsync()
    {
        var order = await _orderService.CreateOrderAsync(Items);
        _messenger.Send(new OrderPlacedMessage { Order = order });
    }
}

public class DashboardViewModel : ViewModelBase
{
    public DashboardViewModel(IMessenger messenger)
    {
        messenger.Register<OrderPlacedMessage>(this, message =>
        {
            RecentOrders.Insert(0, new OrderSummary(message.Order));
        });
    }
}

2.4 Luồng dịch vụ trung gian

Mẫu Repository

Các ViewModels tương tác với dữ liệu thông qua trừu tượng repository:

csharp Copy
public class CustomerManagementViewModel : ViewModelBase
{
    private readonly ICustomerRepository _repository;

    public CustomerManagementViewModel(ICustomerRepository repository)
    {
        _repository = repository;
        LoadCustomersCommand = new RelayCommand(async () => await LoadCustomersAsync());
    }
}

2.5 Luồng xác thực

Xác thực nội tuyến

Xác thực theo thời gian thực với phản hồi ngay lập tức:

csharp Copy
public class RegistrationViewModel : ValidatableViewModelBase
{
    public string Email
    {
        get => _email;
        set
        {
            if (SetProperty(ref _email, value))
            {
                ValidateProperty();
            }
        }
    }
}

Các Thực Hành Tốt Nhất

  • Sử dụng Binding một cách hợp lý để tránh lặp lại mã lệnh.
  • Tận dụng các lệnh để quản lý trạng thái UI.
  • Thực hiện xác thực và thông báo lỗi một cách đồng bộ.

Những Cạm Bẫy Thông Thường

  • Không quản lý đúng các liên kết có thể dẫn đến rò rỉ bộ nhớ.
  • Sử dụng quá nhiều Binding có thể làm giảm hiệu suất UI.

Mẹo Hiệu Suất

  • Cố gắng giảm số lượng Binding không cần thiết.
  • Sử dụng các công cụ đo hiệu suất để theo dõi ứng dụng.

Giải Quyết Vấn Đề

  • Nếu có vấn đề với Binding không hoạt động, hãy kiểm tra các thuộc tính có thông báo thay đổi.

Câu Hỏi Thường Gặp

  1. MVVM là gì?
    MVVM là một mẫu thiết kế giúp tách biệt logic ứng dụng và giao diện người dùng.
  2. Tại sao nên sử dụng MVVM?
    MVVM giúp dễ dàng duy trì và mở rộng ứng dụng, đặc biệt là trong các ứng dụng phức tạp.

Kết Luận: Lợi Thế Phản Ứng

MVVM cung cấp một phương pháp hiệu quả cho việc xây dựng giao diện người dùng động, tự động đồng bộ hóa các thay đổi mà không cần nhiều mã lệnh điều phối.

Đọc Thêm

  • Tìm hiểu thêm về MVC và MVVM qua các bài viết liên quan trong danh sách tài liệu.
Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào