Thứ Ba, 4 tháng 5, 2010

Khái niệm WorkItem của CAB vả SCSF

WorkItem được hiểu như một container chuyên chở cho các component cùng làm việc trọn vẹn một Use case. Đặc biệt , container này là bộ thực thi chương trình (theo thuật ngữ tiếng anh là : run-time container).

Code demo ở đây

Các component để thực thi trọn bộ một use case (fulfill use case) là :
  1. SmartPart (visual aspect, View)
  2. UIelements (Business entities)
  3. Controller (Business logic controller)
  4. Các component khác (State)
  5. Service

Ý tưởng của WorkItem container này cũng dựa trên mô hình Model View Controller mà đưa ra các kiểu chung nhất của mô hình để đưa vào WorkItem bao gồm :

  • Giá trị khởi tạo (Initialization code)
  • Chia sẽ State giữa các component trong use case.
  • Các Class Controller, đặc hành động trên state và các resource khác.
  • Các Class View đặc tương tác với Controller của nó và đọc State.
  • Disposal code
Chúng ta bắt đầu cùng làm theo một demo. Bài demo các bạn có thể download ở trên, và mình tiếp tục với một demo ở bài trước là Khái niệm Shell của CAB và SCSF

Bước 1 : Chúng ta bắt đầu từ việc tạo một module mới. Như trong bài  Khái niệm Shell của CAB và SCSF mình có tạo một module ví dụ , nhưng thật sự đó là một file thực thi exe, chẳng qua mình chỉ mô phỏng cho việc Shell khởi tạo và load theo một module. Hôm nay chúng ta mới thực sự tạo một module nằm trong một ứng dụng Shell và nó được chuyên chở bởi WorkItem. Nói về WorkItem và các thành phần của nó liệt kê ở trên thì rất là nhiều. Trong demo này mình chỉ cho các bạn thấy một module được một workItem chuyên chở thế nào và cả thành phần controller sẽ điều hướng thế nào cho một service và thực thi trên View ra sao.

  1. Trên Solution ta chọn add một project mới với project type là  Window và template mình chọn là Class library. Đặt tên là ModuleCustomer.
  2. Chọn properties của ModuleCustomer vào tab Build thay đổi đường dẫn Output Path : thư mục bin ngoài thư mục góc của Solution.(mục đích cho việc này là chúng ta cùng build các project trong một thư mục dùng chung của solution)
  3. Mở file ProfileCatalog.xml trong project ShellDemo
chỉnh code như sau :
---SolutionProfile xmlns="http://schemas.microsoft.com/pag/cab-profile">
    ---Modules>
        ---ModuleInfo AssemblyFile="ModuleCustomer.dll" />
    ---/Modules>
---/SolutionProfile>
một chương trình vẫn chưa nhiều module. Ở đây ví dụ nên mình chỉ chạy một module chúng ta đang làm. Mỗi module chúng ta chỉ cần khai báo thêm  thẻ ModuleInfo và file biên dịch chứa module.
  1. Trong ModuleCustomer chúng ta references 3 gói dll của CAB và SCSF :
  • Microsoft.Practices.CompositeUI.dll
  • Microsoft.Practices.CompositeUI.WinForms.dll
  • Microsoft.Practices.ObjectBuilder.dll
Căn bản chúng ta đã xong các bước chuẩn bị để tạo một module project.

Bước 2 : chúng ta sẽ tạo các thư mục và các class sau.
  1. Thư mục View



    • Một User control tên CustomerView.cs : đây là giao diện của module.
    • Một file class tên CustomerWorkItem.cs : đây là workItem của module sẽ chuyên chở cả use case này.
  2. Thư mục CustomerEntities



    • Một class tên Customer.cs : chứa các item giá trị của customer
    • Một class tên CustomerService.cs : như một model hay data access chứa dữ liệu và sẽ cùng hiển thị lên view.
     
  3. Ngoài thư mục góc của module là một class tên CustomerModuleInit.cs : đây là class chịu trách nhiệm load tất cả các service cũng như workItem của một module. Ngoài ra nó còn thực hiện các công việc liên quan khác như mở rộng giao diện người dùng trong module hoặc khai báo các thông tin liên quan v.v.. chúng ta sẽ có dịp đề cập sau.
  4. Một class tên CusotmerController.cs : class này thực hiện các logic với data access và views liên quan; theo mô hình MVC.
Chúng ta vừa tạo xong các file cần có trong một module trong module này. chúng ta sẽ bắt đầu code trong các file đó .

Bước 3 : Mở file class Customer.cs tạo các entities cần dùng trong customer

  [Serializable]
    public class Customer
    {
        private int id;
        private string fullname;
        private string email;
        private string address;
        private string phone;
        private string info;

        public Customer(int _id, string _fullname, string _email, string _address,                           string _phone, string _info)
        {
            this.id = _id;
            this.fullname = _fullname;
            this.email = _email;
            this.address = _address;
            this.phone = _phone;
            this.info = _info;

        }
...
   }

Tạo getter và setter cho các entities.
Bước 4 : Mở file CustomerService.cs tạo code như sau


   [Service]
    public class CustomerService
    {
        private Customer[] customers;
        private int idx = 0;
        // thiet lap mot data mau
        public CustomerService()
        {
            customers = new Customer[]{
                new Customer(01,"Le Tuan Dung","ltdung80@yahoo.com","Cong Hoa, Ho Chi Minh","0909152263","Developer"),
                new Customer(02,"Le Minh Tuan","lmtuan90@yahoo.com","CMT8 Ho Chi Minh","0909150063","Tester"),
                new Customer(03,"Le Huu Minh","lhminh08@yahoo.com","Hanh THai HO Chi Minh","0909050063","Sale")
            };
        }

        public bool HasMore
        {
            get{return idx < customers.Length;}
        }
        public Customer GetNext()
        {
            if (!HasMore)
            {
                return null;
            }
            else { return customers[idx++]; }
        }
    }
  1. Trong file này ta có thể hiểu như chúng ta đang sử dụng DAL để lấy dữ liệu , tôi đổ dữ liệu vào một mảng object của customer entities. Định nghĩa một hàm GetNext() để có thể lướt qua từng phần tử mảng object trên. 
  2. Chúng ta sử dụng attribute tên service theo syntax [Service] ở trên khai báo class. Service là một khái niệm của CAB chính vì thế ta cần using gói Microsoft.Practices.CompositeUI; . 
  3. Service : Khái niệm này được cung cấp bởi CAB được dùng để đóng gói các tính năng chung nhất trong module hay của WorkItem. Tính năng chung này là các tính năng mà chúng ta phân tích được sẽ thường xuyên sử dụng với nó. Ví dụ một hàm GetNext() ở trên. Tôi biết chắc mảng dữ liệu đó tôi thường xuyên dùng duyệt trên từng phần tử cho nên tôi sẽ định nghĩa ra nó để tiện sử dụng cho nhiều mục đích khác nhau trong module.
Bước 5: Click duoble file CustomerView.cs và thiết kế giao diện như hình

  1. bên cạnh đó ta sử dụng một bindingsource có tên bindingsource1 và Datasource chúng ta chỉ đến object customer. 
  2. Mỗi text box chúng ta gán Databinding tương ứng cho từng entity của customer.
Bước 6 : Mở file ShellForm.cs . kéo thả DeckWorkspace control vào view ShellForm và đặt tên là mainWorkspace.
Bước 7 : mở file CustomerWorkItem.cs trong file này chúng ta sẽ viết code để tạo một Work item cho module chúng ta, nó chuyên chở view customerview hiển thị lên màn hình khi shellForm run-time. viết code như sau

 public class CustomerWorkItem : WorkItem
    {
        protected override void OnRunStarted()
        {
            base.OnRunStarted();
            IWorkspace moduleworkspace = Workspaces["mainWorkspace"];
            moduleworkspace.Show(Items.AddNew());
        }
    }
  1.  Nó thừa kế WorkItem của CAB chính vì thế bạn nhớ using gói Microsoft.Practices.CompositeUI.
  2. Bạn overide hàm OnRunStarted() của WorkItem. Hàm này thực hiện một khởi tạo được yêu cầu và hiển thị view thích hợp.
  3. Trong hàm này ta dùng một interface IWorkspace của CAB cung cấp . 
  4. Một Workspace như một control đảm nhiệm nhiệm vụ nắm giữ và hiểu thị các phần tử user interface được tạo ra bởi workItem.

    • Trong bài này CustomerView chính là một thành phần user interface.
    • Thông thường thì Workspace được add trong shell hoạt động như một container chuyên chở các User interface. 
    • Trong bài chúng ta đã sử dụng DeckWorkSpace làm workspace chuyên chở view customer cho chúng ta. Chính vì thế mà bất kỳ user interface nào cũng có thể trở thành một workspace chỉ cần chúng ta implement interface IWorkspace.
    • Như trên chúng ta dùng Interface IWorkspace tạo ra một workspace của mainWorkspace mà chúng ta tạo ra ở bước 7. có nghĩa là CustomerView sẽ chứa trong Desckworspace đó
     
Bước 8 : Mở file ModuleCustomerInit.cs code như sau
  public class ModuleCustomerInit : ModuleInit
    {
        private WorkItem workitem;
        [ServiceDependency]
        public WorkItem WorkItem
        {
            set { workitem = value; }
        }
        public override void Load()
        {
            base.Load();
            CustomerWorkItem Cusworkitem = workitem.WorkItems.AddNew();
            Cusworkitem.Run();
        }
    }
  1. Mỗi module đều cần một ModuleInit để khởi tạo và load module khi Shell thực thi class này làm điều đó bằng cách thừa kế Class ModuleInit của CAB. chính vì thế chúng ta fải using Microsoft.Practices.CompositeUI .
  2. Trong hàm load chúng ta cần chúng load CustomerWorkItem của chúng ta khi ứng dụng khởi chạy thì WorkItem cũng cùng lúc chạy lên.
Bước 9 : click chuột phải và chọn View code file CustomerView.cs. and code như sau

 [SmartPart]
    public partial class CustomerView : UserControl
    {
          ........
     }
Bạn dùng attribute SmartPart trên đầu class CustomerView. điều này định nghĩa user control CustomerView là một phần view trong module. Tới đây các bạn có thể hiểu đã hiểu được một module được khởi chạy bên trong một WorkItem như thế nào. bạn có thể build chương trình và chạy chúng. CustomerView sẽ được hiễn thị trong ShellForm.

Bước 10: bước cuối cùng là chúng ta có một controller và chung chuyển để  thực hiện các service của module, các tính năng trong service và hiển thị dữ liệu vào CustomerView thế nào.
Mở file CustomerController.cs code như sau

  public class CustomerController : Controller
    {
        private CustomerService _customerservice;
        [ServiceDependency]
        public CustomerService CustomerService
        {
            set { _customerservice = value; }
        }
        public Customer getNextCustomer()
        {
            return _customerservice.GetNext();
        }
       
    }
  1.  Mô hình CAB cũng cung cấp chúng ta một class Controller dùng để thực thi các logic trong model.
  2. Chúng ta khởi tạo một property của Service là CustomerService. bằng cách dùng một attribute ServiceDependency với syntax [ServiceDependency] trước khai báo setter. Attribute này cũng được cung cấp bời CAB chính vì thế chúng ta cần using Microsoft.Practices.CompositeUI .
  3. CAB cung cấp một khái niệm Dependency Injection . đây là một pattern cho phép nó thực thi như một bộ máy để tạo và khởi tạo một cách tự động các property hoặc các members của các object. chính ObjecBuilder cung cấp chúng ta tính năng này.
  4. Sau khi tạo một property Service ở controller ta sẽ thực thi tính năng GetNext() qua controller bằng cách tạo hàm getNextCustomer() ở trên.
  5. Chúng ta trở lại file CustomerView.cs và view code để viết thêm vài dòng code cho phép hiển thị dữ liệu như sau.
 [SmartPart]
    public partial class CustomerView : UserControl
    {
        private CustomerController _customerController;
        private Customer customer;
        public CustomerView()
        {
            InitializeComponent();
        }

        [CreateNew]
        public CustomerController CustomerController
        {
            set { _customerController = value; }
        }

        private void btnNext_Click(object sender, EventArgs e)
        {
            customer = _customerController.getNextCustomer();
            if (customer == null)
            {
                MessageBox.Show(this, "Customer is null, please come back form", "Customer Note", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            this.bindingSource1.Clear();
            this.bindingSource1.Add(customer);
        }
    }
Các bạn sẽ thấy attribute CreatNew , đây cũng là một kiểu Dependency Injection của CAB cung cấp. Nó cũng khởi tạo một object được add vào các Item của WorkIem.
Hoàn thành các phần này các bạn sẽ có được một dữ liệu được điều hướng từ controller hiển thị trên view và click nút Customer Next các bạn sẽ nhận đựoc thông tin tiếp theo.

Các bạn hãy chia sẽ nhiều kiến thức thêm trong phần WorkItem . các đọan code mình làm cố gắn đơn giản để chủ yếu chúng ta học các khái niệm của CAB đưa ra. Các bạn cần nắm vững các khái niệm được giới thiệu trong bài. và có thể chia sẽ thêm kinh nghiệm của các bạn cho mình biết học hỏi.
Hãy hồi âm để cho mình biết các bạn ủng hộ mình thực hiện các bài viết này. Chúc các bạn thành công.

Không có nhận xét nào:

Đăng nhận xét