2012-03-18

EventAggregator without Prism

Nếu trước đây vài năm, ai đã từng dùng EventBroker của CAB/SCSF và sau đó là EventAggregator của Prism thì không khó khăn gì nhận ra sự linh hoạt của nó so với cách viết thông thường. Tuy nhiên CAB/SCSF EventBroker khó tách ra thành 1 project, hơn nữa cách tiếp cận WorkItem và attribute có vẻ không hợp với các IoC container library sau này.

Dạo gần đây khi review 1 số dự án junior viết, mình nhận thấy code nhất là phần UI rất lộn xộn và không thể nào đọc được. Hầu như không junior nào có khái niệm phải thay đổi cách tổ chức. Nếu làm lại hết tất cả từ đầu thì không khả thi vì vậy mình tìm các apply 1 phần nhỏ để chỉnh lại đám UI code.

Tất nhiên EventAggregator của Prism theo mình nghĩ sẽ là source code hay nhất có thể dễ dàng modified và đưa vào project đã có. Nếu ai đã làm quen với Prism hay thậm chí chỉ cần biết qua về IoC contaienr library nào đó dễ thấy rằng việc đưa EventAggregator vào có thể dễ dàng dọn dẹp được rất nhiều code garbage. Đây là mô tả của Martin Flower http://martinfowler.com/eaaDev/EventAggregator.html.

OK xem thử code EventAggregator của Prism. Thực sự sau khi xem thì cũng không có nhiều việc phải chỉnh. Hơn nữa license của Prism cũng không cấm modified http://compositewpf.codeplex.com/license. Chỉ cần copy các files trong v4/PrismLibrary/Desktop/Prism/Events. Có 1 phần nhỏ để chỉnh lại là DefaultDispatcher.Desktop.cs. Class DefaultDispatcher dùng để marshal code trong trường hợp thread cần marshal đến là UI thread. Trước khi modify PL cũng search qua 1 số code trên Internet nhưng 1 số code lại comment luôn phần dispatcher trong trường hợp scope là UI. Tuy nhiên cũng không khó khăn gì nếu dùng SynchronizationContext như cách BackgroundWorker hay EventBroker của CAB.

Trong với WPF đơn giản code như sau:

if (Application.Current != null)
{
    Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, method, arg);
}

Nếu dùng code với console app hay WinForms thì cần thay bằng SynchronizationContext. Nếu muốn tìm hiểu SynchronizationContext là gì thì trên CodeProject có bài 2 phần giải thích về class này http://www.codeproject.com/Articles/31971/Understanding-SynchronizationContext-Part-I.

Code sau khi chỉnh như sau:

namespace Microsoft.Practices.Prism.Events
{
    /// Wraps the Application Dispatcher.

    public class DefaultDispatcher : IDispatcherFacade    {
        /// Forwards the BeginInvoke to the current application's .

        /// method Method to be invoked.
        /// arg Arguments to pass to the invoked method.
        public void BeginInvoke(Delegate method, object arg)
        {
#if WPF
            if (Application.Current != null)
            {
                Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, method, arg);
            }
#else

            if (SynchronizationContext.Current != null)
            {
                SynchronizationContext.Current.Send(data =>
                {
                    try
                    {
                        ((Delegate)data).DynamicInvoke(arg);
                    }
                    catch (TargetInvocationException ex)
                    {
                        Debug.WriteLine("There is an exception when marshal to UI thread: " + ex.Message);
                    }
                }, method);
            }
            else
            {
                try
                {
                    method.DynamicInvoke(arg);
                }
                catch (TargetInvocationException ex)
                {
                    Debug.WriteLine("There is an exception when marshal to UI thread: " + ex.Message);
                }
            }
#endif
        }
    }
}

No comments:

Post a Comment