WPF架构分析
<?xml version="1.0" encoding="UTF-8"?> 1.DisptcherObject提供了線程和并發模型,實現了消息系統。 2.DependencyObject提供了更改通知,實現了綁定,樣式。3.Visual是托管API和非托管API(milcore)的之間的關鍵點。4.UIElement定義了Layout,Input和Events等核心子系統。Measure讓一個組件來決定自己想要的size,而Arrange讓父組件放置子組件并決定子組件的最終size。5.WPF的外觀和行為總共有3個模型:數據模型(Properties),交互模型(Commands,Events),顯示模型(Template)。6.不同應用程序域間的WPF可以通過INativeHandleContract來實現WPF AddIn。7.WPF定義了三個呈現曾:
提高方法:盡量使用最有效的Panel,功能越強大的Panel性能成本也就越高;?更新而不替換RenderTransform;?從上到下生成邏輯樹。2)二維圖形和圖像處理提高方法:Drawing對象比Shape對象結構簡單,性能更為優越,但是不是從FrameworkElement集成,使用時注意;?使用StreamGeometry而不是PathGeometry;如果需要顯示縮略圖,盡量使用小版本的圖像,或者請求WPF將圖像解碼為縮略圖大小,或者請求WPF加載縮略圖大小。始終將圖像解碼為所需的大小而不是默認大小。3)行為提高方法:注冊DependencyObject時,盡量提供默認值和PropertyMetadata,而不是放在以后賦值。凍結Freezable會改善程序性能,不再需要因維護更改通知而消耗資源。使用VirtualizingStackPanel而不是StackPanel,注意:這樣子資源蘇不可見時即被移除,這時無法訪問不可見的子元素。盡可能使用靜態資源,只在必須得情況下使用動態資源。避免在FlowDocument使用TextBlock,而應該使用Run。避免在TextBlock里使用Run來設置文本屬性。避免執行到Lable.Content屬性的數據綁定。 如果數據源頻繁更新,應用TextBlock.Text替換。?4)數據綁定提高方法:性能從高到低:DependencyObject 〉INotifyPropertyChanged ?如果綁定到較大的CLR對象,考慮將對象拆分成多個具有少量屬性的CLR對象將IList(而非IEnumerable)綁定到ItemsCount5)控件提高方法:設置?IsVirtualizing?為true,?VirtualizationMode?為Recycling,??IsDeferredScrollingEnabled為true。IsVirtualizing代表是否UI虛擬化,當設置為true時,表示只有當數據項在屏幕上可見時才會在內存中創建存儲。?VirtualizationMode代表是否容器回收,正常情況下ItemsControl會為滾動到視圖中的每個item創建項容器,并銷毀滾動到視圖之外的每個item的項容器。通過Recycling,可以讓控件能夠將現有項容器重復利用于不同的數據項。IsDeferredScrollingEnabled代表是否延長滾動,正常情況下當用戶拖到滾動條上的滑塊時,內容視圖會不會不斷更新。當設置為true, 表示只有當用戶松開滾動條時,內容才會更新。
6)其他盡量使用畫筆的不透明度(Opacity),而不是使用元素的Opacity,修改元素的Opacity會導致WPF創建臨時圖標。配置“WPF字體緩存服務”從手動為自動(延遲啟動),這個服務如果沒有啟動,會隨著第一個WPF程序啟動時啟動。這樣導致第一個WPF的初始化事件很長。
9. WPF線程模型典型的wpf程序有2個線程,一個用于負責渲染,一個用于管理UI。UI線程把工作項排序到Dispatcher對象中,Dispatcher對象根據工作項的優先級選擇執行,直到全部執行。每個UI線程必須至少有一個Dispatcher,每個Dispatcher必須在一個線程里工作。?
可以通過CheckAccess來判斷線程是否可以訪問DispatcherObject。原理是:大多數類繼承于DispatcherObject,DispatcherObject在構造時把當前運行線程的Dispatcher引用存儲。當訪問DispatcherObject時,檢查當前線程關聯的Dispatcher于構造中存儲的Dispatcher進行比較,如果相同返回True,不同返回False。
要構建響應速度快、且用戶友好的應用程序,訣竅是減小工作項,以最大限度地提高 Dispatcher 吞吐量。 這樣,工作項將永遠不會因為在 Dispatcher 隊列中等待處理而失效。 輸入與響應之間的任何可察覺的延遲都會使用戶不快。
嵌套的消息泵:比如MessageBox,我們調用show后需要用戶單擊“OK"才能返回。MessageBox創建的窗口必須要由一個消息泵才能進行交互。我們在等待用戶單擊”OK“時原始應用程序窗口不響應用戶輸入。具體實現: WPF使用一種嵌套的消息處理系統, Dispatcher類包含一個PushFrame的特殊方法, 該方法存儲應用程序的當前執行點,然后開始一個新的消息泵,當嵌套的消息泵執行結束時,執行將在最初的PushFrame調用之后繼續。PushFrame內部實現類似Win32中GetMessage、TranslateMessage、DispatchMessage的消息泵。 (通過這個原理,我們可以實現自己的MessageBox系統)Application.Run內部調用Dispatcher.Run(),Dispatcher.Run()內部調用了Dispatcher.PushFrame(..), 實現了一個Win32的消息泵。
DispatcherOperation對象用于與Dispatcher隊列上的Delegate進行交互,例如更改委托的優先級、從事件隊列中移除委托、等待委托返回、獲取委托執行之后返回的值。
Application.DoEvents方法:處理當前Dispatcher消息隊列里的所有windows消息。關于BeginInvoke和Invoke,向關聯的Dispatcher的隊列中插入同步或者異步工作項。
10.Weak Event Pattern傳統的偵聽事件可能導致內存泄漏,source.SomeEvent += new SomeEventHandler(MyEventHandler) 。這是因為為事件源添加事件處理程序時,會創建一個事件源到事件偵聽器(所謂事件偵聽器,就是Delegate對象)的強引用。這樣事件偵聽器就會有生命周期,該生命周期和事件源的生命周期有關, 除非顯式的移除了事件處理程序,?source.SomeEvent -= new SomeEventHandler(MyEventHandler) 。當事件源從可視樹中移除時,事件偵聽器還是有生命周期,但此時事件處理程序不會被調用,也就是說造成了無用的事件偵聽器的還一直存在。這種情況下就需要弱事件模式。 ? ? ?實現弱事件模式,有三種方式:使用系統已有的(CollectionChangedEventManager,PropertyChangedEventManager等等); 使用泛型弱事件管理器(WeakEventManager<TEventSource, TeventArgs>, 注意有性能損失); 繼承WeakEventManager類,實現自定義弱事件管理器。
例如:?
class SomeEventWeakEventManager : WeakEventManager{
private SomeEventWeakEventManager(){
}
/// <summary>/// Add a handler for the given source's event./// </summary>public static void AddHandler(EventSource source,?EventHandler<SomeEventEventArgs> handler){if (source == null)throw new ArgumentNullException("source");if (handler == null)throw new ArgumentNullException("handler");
CurrentManager.ProtectedAddHandler(source, handler);}
/// <summary>/// Remove a handler for the given source's event./// </summary>public static void RemoveHandler(EventSource source,?EventHandler<SomeEventEventArgs> handler){if (source == null)throw new ArgumentNullException("source");if (handler == null)throw new ArgumentNullException("handler");
CurrentManager.ProtectedRemoveHandler(source, handler);}
/// <summary>/// Get the event manager for the current thread./// </summary>private static SomeEventWeakEventManager CurrentManager{get{Type managerType = typeof(SomeEventWeakEventManager);SomeEventWeakEventManager manager =?(SomeEventWeakEventManager)GetCurrentManager(managerType);
// at first use, create and register a new managerif (manager == null){manager = new SomeEventWeakEventManager();SetCurrentManager(managerType, manager);}
return manager;}}
/// <summary>/// Return a new list to hold listeners to the event./// </summary>protected override ListenerList NewListenerList(){return new ListenerList<SomeEventEventArgs>();}
/// <summary>/// Listen to the given source for the event./// </summary>protected override void StartListening(object source){EventSource typedSource = (EventSource)source;typedSource.SomeEvent += new EventHandler<SomeEventEventArgs>(OnSomeEvent);}
/// <summary>/// Stop listening to the given source for the event./// </summary>protected override void StopListening(object source){EventSource typedSource = (EventSource)source;typedSource.SomeEvent -= new EventHandler<SomeEventEventArgs>(OnSomeEvent);}
/// <summary>/// Event handler for the SomeEvent event./// </summary>void OnSomeEvent(object sender, SomeEventEventArgs e){DeliverEvent(sender, e);}}
使用方法:?將source.SomeEvent += new SomeEventEventHandler(OnSomeEvent);source.SomeEvent -= new SomeEventEventHandler(OnSome);
替換為??
SomeEventWeakEventManager.AddHandler(source, OnSomeEvent);SomeEventWeakEventManager.RemoveHandler(source, OnSomeEvent);
參考:http://msdn.microsoft.com/zh-cn/library/ms750441.aspx? ?WPF架構http://msdn.microsoft.com/zh-cn/library/aa970683.aspx? ?優化WPF應用程序性能http://msdn.microsoft.com/en-us/library/ms741870.aspx?? WPF線程模型http://msdn.microsoft.com/zh-cn/library/system.windows.threading.dispatcheroperation.aspx?DispatcherOperation類http://msdn.microsoft.com/zh-cn/library/system.windows.forms.application.doevents.aspx?Application.DoEvents 方法http://msdn.microsoft.com/zh-cn/library/system.windows.threading.dispatcher.pushframe.aspx?Dispatcher.PushFrame 方法
http://msdn.microsoft.com/zh-cn/library/vstudio/aa970850(v=vs.90).aspx?WeakEvent模式http://msdn.microsoft.com/zh-cn/library/ms404247.aspx弱引用
呈現層 0?無圖形硬件加速。?所有圖形功能都使用軟件加速。?DirectX 版本級別低于 9.0。
呈現層 1?某些圖形功能使用圖形硬件加速。?DirectX 版本級別高于或等于 9.0。
呈現層 2?大多數圖形功能都使用圖形硬件加速。?DirectX 版本級別高于或等于 9.0。
提高方法:盡量使用最有效的Panel,功能越強大的Panel性能成本也就越高;?更新而不替換RenderTransform;?從上到下生成邏輯樹。2)二維圖形和圖像處理提高方法:Drawing對象比Shape對象結構簡單,性能更為優越,但是不是從FrameworkElement集成,使用時注意;?使用StreamGeometry而不是PathGeometry;如果需要顯示縮略圖,盡量使用小版本的圖像,或者請求WPF將圖像解碼為縮略圖大小,或者請求WPF加載縮略圖大小。始終將圖像解碼為所需的大小而不是默認大小。3)行為提高方法:注冊DependencyObject時,盡量提供默認值和PropertyMetadata,而不是放在以后賦值。凍結Freezable會改善程序性能,不再需要因維護更改通知而消耗資源。使用VirtualizingStackPanel而不是StackPanel,注意:這樣子資源蘇不可見時即被移除,這時無法訪問不可見的子元素。盡可能使用靜態資源,只在必須得情況下使用動態資源。避免在FlowDocument使用TextBlock,而應該使用Run。避免在TextBlock里使用Run來設置文本屬性。避免執行到Lable.Content屬性的數據綁定。 如果數據源頻繁更新,應用TextBlock.Text替換。?4)數據綁定提高方法:性能從高到低:DependencyObject 〉INotifyPropertyChanged ?如果綁定到較大的CLR對象,考慮將對象拆分成多個具有少量屬性的CLR對象將IList(而非IEnumerable)綁定到ItemsCount5)控件提高方法:設置?IsVirtualizing?為true,?VirtualizationMode?為Recycling,??IsDeferredScrollingEnabled為true。IsVirtualizing代表是否UI虛擬化,當設置為true時,表示只有當數據項在屏幕上可見時才會在內存中創建存儲。?VirtualizationMode代表是否容器回收,正常情況下ItemsControl會為滾動到視圖中的每個item創建項容器,并銷毀滾動到視圖之外的每個item的項容器。通過Recycling,可以讓控件能夠將現有項容器重復利用于不同的數據項。IsDeferredScrollingEnabled代表是否延長滾動,正常情況下當用戶拖到滾動條上的滑塊時,內容視圖會不會不斷更新。當設置為true, 表示只有當用戶松開滾動條時,內容才會更新。
6)其他盡量使用畫筆的不透明度(Opacity),而不是使用元素的Opacity,修改元素的Opacity會導致WPF創建臨時圖標。配置“WPF字體緩存服務”從手動為自動(延遲啟動),這個服務如果沒有啟動,會隨著第一個WPF程序啟動時啟動。這樣導致第一個WPF的初始化事件很長。
9. WPF線程模型典型的wpf程序有2個線程,一個用于負責渲染,一個用于管理UI。UI線程把工作項排序到Dispatcher對象中,Dispatcher對象根據工作項的優先級選擇執行,直到全部執行。每個UI線程必須至少有一個Dispatcher,每個Dispatcher必須在一個線程里工作。?
可以通過CheckAccess來判斷線程是否可以訪問DispatcherObject。原理是:大多數類繼承于DispatcherObject,DispatcherObject在構造時把當前運行線程的Dispatcher引用存儲。當訪問DispatcherObject時,檢查當前線程關聯的Dispatcher于構造中存儲的Dispatcher進行比較,如果相同返回True,不同返回False。
要構建響應速度快、且用戶友好的應用程序,訣竅是減小工作項,以最大限度地提高 Dispatcher 吞吐量。 這樣,工作項將永遠不會因為在 Dispatcher 隊列中等待處理而失效。 輸入與響應之間的任何可察覺的延遲都會使用戶不快。
嵌套的消息泵:比如MessageBox,我們調用show后需要用戶單擊“OK"才能返回。MessageBox創建的窗口必須要由一個消息泵才能進行交互。我們在等待用戶單擊”OK“時原始應用程序窗口不響應用戶輸入。具體實現: WPF使用一種嵌套的消息處理系統, Dispatcher類包含一個PushFrame的特殊方法, 該方法存儲應用程序的當前執行點,然后開始一個新的消息泵,當嵌套的消息泵執行結束時,執行將在最初的PushFrame調用之后繼續。PushFrame內部實現類似Win32中GetMessage、TranslateMessage、DispatchMessage的消息泵。 (通過這個原理,我們可以實現自己的MessageBox系統)Application.Run內部調用Dispatcher.Run(),Dispatcher.Run()內部調用了Dispatcher.PushFrame(..), 實現了一個Win32的消息泵。
DispatcherOperation對象用于與Dispatcher隊列上的Delegate進行交互,例如更改委托的優先級、從事件隊列中移除委托、等待委托返回、獲取委托執行之后返回的值。
Application.DoEvents方法:處理當前Dispatcher消息隊列里的所有windows消息。關于BeginInvoke和Invoke,向關聯的Dispatcher的隊列中插入同步或者異步工作項。
10.Weak Event Pattern傳統的偵聽事件可能導致內存泄漏,source.SomeEvent += new SomeEventHandler(MyEventHandler) 。這是因為為事件源添加事件處理程序時,會創建一個事件源到事件偵聽器(所謂事件偵聽器,就是Delegate對象)的強引用。這樣事件偵聽器就會有生命周期,該生命周期和事件源的生命周期有關, 除非顯式的移除了事件處理程序,?source.SomeEvent -= new SomeEventHandler(MyEventHandler) 。當事件源從可視樹中移除時,事件偵聽器還是有生命周期,但此時事件處理程序不會被調用,也就是說造成了無用的事件偵聽器的還一直存在。這種情況下就需要弱事件模式。 ? ? ?實現弱事件模式,有三種方式:使用系統已有的(CollectionChangedEventManager,PropertyChangedEventManager等等); 使用泛型弱事件管理器(WeakEventManager<TEventSource, TeventArgs>, 注意有性能損失); 繼承WeakEventManager類,實現自定義弱事件管理器。
例如:?
class SomeEventWeakEventManager : WeakEventManager{
private SomeEventWeakEventManager(){
}
/// <summary>/// Add a handler for the given source's event./// </summary>public static void AddHandler(EventSource source,?EventHandler<SomeEventEventArgs> handler){if (source == null)throw new ArgumentNullException("source");if (handler == null)throw new ArgumentNullException("handler");
CurrentManager.ProtectedAddHandler(source, handler);}
/// <summary>/// Remove a handler for the given source's event./// </summary>public static void RemoveHandler(EventSource source,?EventHandler<SomeEventEventArgs> handler){if (source == null)throw new ArgumentNullException("source");if (handler == null)throw new ArgumentNullException("handler");
CurrentManager.ProtectedRemoveHandler(source, handler);}
/// <summary>/// Get the event manager for the current thread./// </summary>private static SomeEventWeakEventManager CurrentManager{get{Type managerType = typeof(SomeEventWeakEventManager);SomeEventWeakEventManager manager =?(SomeEventWeakEventManager)GetCurrentManager(managerType);
// at first use, create and register a new managerif (manager == null){manager = new SomeEventWeakEventManager();SetCurrentManager(managerType, manager);}
return manager;}}
/// <summary>/// Return a new list to hold listeners to the event./// </summary>protected override ListenerList NewListenerList(){return new ListenerList<SomeEventEventArgs>();}
/// <summary>/// Listen to the given source for the event./// </summary>protected override void StartListening(object source){EventSource typedSource = (EventSource)source;typedSource.SomeEvent += new EventHandler<SomeEventEventArgs>(OnSomeEvent);}
/// <summary>/// Stop listening to the given source for the event./// </summary>protected override void StopListening(object source){EventSource typedSource = (EventSource)source;typedSource.SomeEvent -= new EventHandler<SomeEventEventArgs>(OnSomeEvent);}
/// <summary>/// Event handler for the SomeEvent event./// </summary>void OnSomeEvent(object sender, SomeEventEventArgs e){DeliverEvent(sender, e);}}
使用方法:?將source.SomeEvent += new SomeEventEventHandler(OnSomeEvent);source.SomeEvent -= new SomeEventEventHandler(OnSome);
替換為??
SomeEventWeakEventManager.AddHandler(source, OnSomeEvent);SomeEventWeakEventManager.RemoveHandler(source, OnSomeEvent);
參考:http://msdn.microsoft.com/zh-cn/library/ms750441.aspx? ?WPF架構http://msdn.microsoft.com/zh-cn/library/aa970683.aspx? ?優化WPF應用程序性能http://msdn.microsoft.com/en-us/library/ms741870.aspx?? WPF線程模型http://msdn.microsoft.com/zh-cn/library/system.windows.threading.dispatcheroperation.aspx?DispatcherOperation類http://msdn.microsoft.com/zh-cn/library/system.windows.forms.application.doevents.aspx?Application.DoEvents 方法http://msdn.microsoft.com/zh-cn/library/system.windows.threading.dispatcher.pushframe.aspx?Dispatcher.PushFrame 方法
http://msdn.microsoft.com/zh-cn/library/vstudio/aa970850(v=vs.90).aspx?WeakEvent模式http://msdn.microsoft.com/zh-cn/library/ms404247.aspx弱引用
轉載于:https://blog.51cto.com/muzizongheng/1333025
總結
- 上一篇: mac中插入带圆圈数字序号①②③
- 下一篇: 【java设计模式之Command(菜单