WPF:請記住改寫路由事件RoutedEventArgs.InvokeEventHandler方法

來源:互聯網
上載者:User

當你自訂一個路由事件的EventArgs,直接繼承RoutedEventArgs,然後新增成員就OK了?不!記住改寫RoutedEventArgs.InvokeEventHandler方法。這個方法是protected virtual。它的預設執行對於一個自訂的RoutedEventArgs衍生類別是很沒效率的!在細說RoutedEventArgs.InvokeEventHandler預設執行之前,先說說為什麼RoutedEventArgs.InvokeEventHandler方法很重要。原因很簡單,因為WPF路由事件的運行將會調用RoutedEventArgs.InvokeEventHandler方法,所以這個方法的效率直接影響到路由事件的最初執行效率。

 

WPF的執行路由事件方法是UIElement.RaiseEvent,這個方法實際上來自繼承的介面IInputElement。如果你用ILSpy細細追究UIElement.RaiseEvent方法執行,最終會發現如下路徑:

UIElement.RaiseEvent

UIElement.RaiseEventImpl

EventRoute.InvokeHandlers

EventRoute.InvokeHandlersImpl

RoutedItem.InvokeHandler

RoutedEventHanderInfo.InvokeHandler

RoutedEventArgs.InvokeHandler

RoutedEventArgs.InvokeEventHandler

最終會到RoutedEventArgs.InvokeEventHandler方法中。

 

接下來看看RoutedEventArgs.InvokeEventHandler的預設執行:

這是它的原始碼:

// System.Windows.RoutedEventArgs

protected virtual void InvokeEventHandler(Delegate genericHandler, object genericTarget)

{

    if (genericHandler == null)

    {

        throw new ArgumentNullException("genericHandler");

    }

    if (genericTarget == null)

    {

        throw new ArgumentNullException("genericTarget");

    }

    if (this._routedEvent == null)

    {

        throw new InvalidOperationException(SR.Get("RoutedEventArgsMustHaveRoutedEvent"));

    }

    this.InvokingHandler = true;

    try

    {

        if (genericHandler is RoutedEventHandler)

        {

            ((RoutedEventHandler)genericHandler)(genericTarget, this);

        }

        else

        {

            genericHandler.DynamicInvoke(new object[]

            {

                genericTarget,

                this

            });

        }

    }

    finally

    {

        this.InvokingHandler = false;

    }

}

 

可以看到,如果目標委託類型是RoutedEventHandler,那麼直接調用目標委託,這個是沒有效率損耗的。但如果不是,則通過Delegate.DynamicInvoke這種反射方式來調用委託,這個執行是有效率損耗的。很顯然,對於RoutedEventArgs,它屬於RoutedEventHandler的參數,而自訂的RoutedEventArgs是肯定不屬於RoutedEventHandler類型的(參數類型不符),那麼最終執行預設會用反射調用委託。

 

所以記住每次自訂RoutedEventArgs,手動改寫InvokeEventHandler,讓它更有效率:

//自訂RoutedEventArgs

class MyRoutedEventArgs : RoutedEventArgs

{

    //手動改寫RoutedEventArgs.InvokeEventHandler

    protected override void InvokeEventHandler(Delegate genericHandler, object genericTarget)

    {

        var handler = (EventHandler<MyRoutedEventArgs>)genericHandler;

        handler(genericTarget, this);

    }

}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.