WPF và MVVM – Phần 3: Ứng dụng trong Windows Forms

Để hiểu được hoàn toàn làm thế nào và tại sao phải chuyển từ Windows Forms sang WPF và từ WPF sang WPF sử dụng MVVM, trước tiên chúng ta cần tìm hiểu Windows Forms.

Khi lần đầu tiên Microsoft phát triển và phát hành .NET, họ đã cung cấp một API rất đơn giản và rõ ràng cho việc tạo ra các ứng dụng Windows dựa trên các công nghệ hiện có: Windows Forms. Mô hình lập trình Windows Forms là mô hình lập trình dựa trên sự kiện. Điều này rất phù hợp với các công nghệ trước đây của Microsoft, chẳng hạn như ATL và MFC.

Trong Windows Forms, bạn bắt đầu với một “Form”, tương ứng với một cửa sổ trên màn hình. Form này chứa nhiều điều khiển, mỗi cái thực hiện thông qua một gói (wrapper) xung quanh Controls trong Windows API. Mỗi điều khiển bản thân nó cung cấp một cửa sổ xử lý riêng của mình (HWND, qua Controls.Handle), cơ bản riêng biệt với Windows. Khi ứng dụng bắt đầu, bạn tạo một cửa sổ thông điệp bằng cách gọi Application.Run, sẽ mở các cửa sổ thông điệp tiêu chuẩn đến các điều khiển thích hợp của chúng, rồi tiếp đó phát động các sự kiện trong các mã lập trình của Form đó.

Ngoài ra, việc xây dựng một form cần phải có một nhà thiết kế chăm sóc toàn diện cho việc này, do đó, các nhà phát triển đồ họa có thể bố trí các điều khiển của họ trên một mẫu, và các mã C# thích hợp sẽ được tạo ra (bên trong phương thức InitalizeComponent). Nó sẽ thêm các sử lý sự kiện cho nhà phát triển và ánh xạ chúng với các phương thức trong file .cs của Form này một cách tự động, làm cho việc tạo ra các giao diện đồ họa trở nên rất dễ dàng.

Microsoft cũng cung cấp các phương tiện để chia các thành phần của form thành các phần nhỏ hơn, dễ quản lý hơn bằng chức năng gọi là UserControl. Một UserControl cơ bản là “ruột” của một form mà bạn có thể đưa chúng qua một form khác, cho phép sử dụng lại trên nhiều form nhưng cũng tách biệt logic thành từng phần để ngăn chặn tình trạng form quá lớn.

Đây là một mô hình rất giống nhau và thân thiện với những nhà phát triển đã sử dụng MFC, VB6 hay thậm chí là Delphi. Các chi tiết thực hiện hơi khác nhau, nhưng các mô hình khái niệm cơ bản là không thay đổi – thiết kế form, ghép nối các sự kiện, xử lý các sự kiện, luôn làm việc với thông điệp trong mã lập trình. Chính điều này làm cho mô hình Windows Forms được tiếp cận rất nhanh chóng – rất thân thiện và dễ chuyển đổi từ các công nghệ khác sang Windows Forms.

Cho series của chúng ta,chúng ta bắt đầu ở đây. Chúng ta sẽ xem xét ứng dụng đọc nguồn RSS đơn giản sử dụng Windows Forms và phần Model ở đây sẽ gồm các lớp Feed và FeedItem đã mô tả ở trên.Đây là một ứng dụng rất đơn giản. Cho các mục đích của chúng ta, các ứng dụng phải đáp ứng các yêu cầu đơn giản như sau:

  • Load nguồn bằng cách sử dụng Model Hiển thị thông tin cơ bản về Feed

  • Hiển thị thông tin cơ bản về Feed

  • Hiển thị danh sách FeedItems trong Feed

  • Cho phép người dùng chọn một FeedItem cụ thể

  • Cho phép người dùng mở một FeedItem nguồn gốc trên trình duyệt

  • Hiển thị FeedItem trong một trình duyệt gói

Đây là màn hình của ứng dụng Windows Forms hoàn thiện:

Không có gì lạ trong ứng dụng này và mã lập trình cũng rất quen thuộc với những ai đã sử dụng Windows Forms. Vì vậy chúng ta hãy xem cách nó làm việc bên trong như thế nào.Phần “Feed Information” và “Select a Feed Item” được chia thành một một UserControl được tách riêng biệt cho mục đích trình diễn. Giao diện người dùng hoàn toàn được sinh ra bên trong của người thiết kế và mã lập trình cũng được viết cho chúng ta.

Khi người sử dụng nhấn vào “Load RSS Feed” bộ kiểm soát sự kiện nhỏ sẽ được chạy:

private void ButtonUpdateFeed_Click(object sender, EventArgs e)
 {
     this.feedControl.Feed = Feed.Read(new Uri(this.textBox1.Text));
 }

Sự kiện này sẽ thiết lập thuộc tính “Feed” bên trong UserControl đến Feed (Model của chúng ta). UserControl này có thuộc tính “Feed” trong đó quy định một số mã để chạy khi nguồn cấp dữ liệu được cập nhật:

public Feed Feed
    {
        get
        {
            return this.feed;
        }
    
        set
        {
             this.feed = value;
             this.ResetFeed();
        }
    }

Đến lượt này gọi đến phương thức ResetFeed(), trong đó lần đầu tiên gọi đến ClearFeed() để xóa UI hiện tại và sau đó thiết lập các giá trị bên trong mỗi điều khiển:

private void ResetFeed()
{
    this.ClearFeed();

    if (this.Feed == null)
    {
        return;
    }

    this.textBoxTitle.Text = this.Feed.Title;
    this.textBoxLink.Text = this.Feed.Link.AbsoluteUri;
    this.textBoxDescription.Text = this.Feed.Description;

    foreach (var item in this.Feed.Items)
    {
        this.listBoxFeeds.Items.Add(item.Title);
    }
}

private void ClearFeed()
{
    this.listBoxFeeds.Items.Clear();
    this.textBoxTitle.Text = string.Empty;
    this.textBoxLink.Text = string.Empty;
    this.textBoxDescription.Text = string.Empty;
    this.textBoxItemTitle.Text = string.Empty;
    this.textBoxItemLink.Text = string.Empty;
    this.textBoxItemDescription.Text = string.Empty;
}

Usercontrol của chúng ta sẽ điền hết tất các các thông tin của feed. Khi người sử dụng chọn một feed trong ListBox, chúng ta sẽ xử lý nó thông qua một bộ kiểm soát sự kiện khác:

private void ListBoxFeeds_SelectedIndexChanged(object sender, EventArgs e)
{
    FeedItem item = this.Feed.Items[this.listBoxFeeds.SelectedIndex];
    this.textBoxItemTitle.Text = item.Title;
    this.textBoxItemLink.Text = item.Link.AbsoluteUri;
    this.textBoxItemDescription.Text = item.Description;

    if (this.UriChanged != null)
    {
        this.UriChanged(this, new UriChangedEventArgs(new Uri(this.textBoxItemLink.Text)));
    }
}

Khi chọn một mục nào đó trong danh sách, chúng ta sẽ cập nhật lại các điều khiển của feed item và cũng phát ra một sự kiện trên UserControl. Form chính của chúng ta mô tả sự kiện này và sử dụng nó để cập nhật vào điều khiển trình duyệt (WebBrowser control) nằm ở bên dưới UserControl của form.

Cuối cùng, chúng ta có một nút tên là “Open” với bộ xử lý sự kiện kèm theo để mở Feed trên trình duyệt:

private void ButtonOpenLink_Click(object sender, EventArgs e)
{
    if (this.Feed != null)
    {
        FeedItem item = this.Feed.Items[this.listBoxFeeds.SelectedIndex];
        if (item != null)
        {
            System.Diagnostics.Process.Start(item.Link.AbsoluteUri);
        }
    }
}

Điều này cũng quen thuộc với hầu hết các lập trình viên Windows Forms. Có nhiều cách khác để viết loại mã nguồn này, tuy nhiên đây là cách rất thông dụng và khá tiêu biểu mà các chương trình Windows Forms được viết. Đây không những là một ví dụ hoàn hảo cho một ứng dụng Windows Forms mà hơn thế còn thể hiện cách thức điển hình để viết ứng dụng này.

Có một số điều quan trọng cần nhận biết ở đây.

  • Tất cả logic của chúng ta đều được kiểm soát trong các sự kiện, được
    kích hoạt bởi người dùng tương tác với giao diện người dùng trong cửa
    sổ của chúng ta.
  • Mặc dù người thiết kế Windows Forms đưa ra một giao diện rất đẹp, nếu
    bạn thực sự xem mã nguồn bên trong, toàn bộ giao diện người sử dụng
    được chúng ta hay người thiết kế định nghĩa theo hình thức mệnh lệnh.
  • Mã nguồn và logic thực sự phụ thuộc vào loại control đang được sử
    dụng. Chẳng hạn, nếu chúng ta thay đổi ListBox thành một loại control
    nào đó, chúng ta gần như cần thay đổi mã nguồn bên trong của control
    này.
6 Likes

thực sự là chưa hiểu mấy cái này !! nhưng cũng cảm ơn đã chia sẻ
:grinning:

1 phần là dịch từ tiếng anh nên mình cố gắng dịch theo nghĩa thoáng nhất, nếu bạn đã coi 2 phần trước thì dễ hiểu hơn :smiley:

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?