日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

C# WPF MVVM开发框架Caliburn.Micro Screens, Conductors 和 Composition⑦

發布時間:2023/12/4 C# 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C# WPF MVVM开发框架Caliburn.Micro Screens, Conductors 和 Composition⑦ 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

01

Screens, Conductors and Composition

Actions, Coroutines and Conventions往往最能吸引Caliburn.Micro的注意力,但如果你想讓你的UI設計得更好,那么了解屏幕和導體可能是最重要的。如果您想利用合成,這一點尤其重要。杰里米·米勒最近在為艾迪生·韋斯利撰寫《呈現模式》一書時,將屏幕、屏幕指揮和屏幕收藏這三個術語編成了法典。雖然這些模式主要通過從特定基類繼承ViewModels來在CM中使用,但將它們視為角色而不是視圖模型是很重要的。事實上,根據您的體系結構,屏幕可以是用戶控件、演示者或視圖模型。不過這有點超前了。首先,讓我們談談這些東西的一般含義。

Theory

Screen

這是最容易理解的結構。您可能認為它是應用程序表示層中存在的一個有狀態的工作單元。它獨立于應用程序外殼。外殼可能會顯示許多不同的屏幕,有些甚至同時顯示。shell可能也會顯示很多小部件,但它們不是任何屏幕的一部分。一些屏幕示例可能是應用程序設置的模式對話框、Visual Studio中的代碼編輯器窗口或瀏覽器中的頁面。你可能對此有很好的直覺。

通常情況下,屏幕具有與其相關聯的生命周期,允許屏幕執行自定義激活和停用邏輯。這就是杰里米所說的屏幕激活器。例如,以VisualStudio代碼編輯器窗口為例。如果在一個選項卡中編輯C#代碼文件,然后切換到包含XML文檔的選項卡,您會注意到工具欄圖標會發生變化。這些屏幕中的每一個都有自定義的激活/停用邏輯,使其能夠設置/拆除應用程序工具欄,以便它們根據活動屏幕提供適當的圖標。在簡單的場景中,ScreenActivator通常與Screen是同一個類。但是,您應該記住,這是兩個獨立的角色。如果特定屏幕具有復雜的激活邏輯,則可能需要將ScreenActivator考慮到其自己的類中,以降低屏幕的復雜性。如果您的應用程序具有許多不同的屏幕,但都具有相同的激活/停用邏輯,則這一點尤為重要。

Screen Conductor

一旦將屏幕激活生命周期的概念引入到應用程序中,就需要某種方法來實施它。這是屏幕指揮的角色。當您顯示屏幕時,導線會確保屏幕已正確激活。如果您正在從屏幕過渡,它會確保屏幕被停用。還有另一個場景也很重要。假設您有一個包含未保存數據的屏幕,并且有人試圖關閉該屏幕甚至應用程序。ScreenConductor已經在強制停用,它可以通過實現正常關機來提供幫助。與您的屏幕可能實現激活/停用界面的方式相同,它也可能實現一些界面,允許售票員詢問“您可以關閉嗎?”這引出了一個重要的問題:在某些情況下,停用屏幕與關閉屏幕相同,而在其他情況下,停用屏幕與關閉屏幕不同。例如,在VisualStudio中,當您從一個選項卡切換到另一個選項卡時,它不會關閉文檔。它只是激活/停用它們。必須顯式關閉選項卡。這就是觸發正常關機邏輯的原因。然而,在基于導航的應用程序中,離開頁面導航肯定會導致停用,但也可能導致該頁面關閉。這完全取決于您的特定應用程序的體系結構,您應該仔細考慮這一點。

Screen Collection

在像VisualStudio這樣的應用程序中,您不僅有一個ScreenConductor來管理激活、停用等,而且還有一個ScreenCollection來維護當前打開的屏幕或文檔列表。通過添加這一難題,我們還可以解決停用與關閉的問題。屏幕集合中的任何內容都保持打開狀態,但一次只有其中一項處于活動狀態。在像VS這樣的MDI風格的應用程序中,導體將管理在ScreenCollection成員之間切換活動屏幕。打開一個新文檔會將其添加到屏幕集合并切換到活動屏幕。關閉文檔不僅會停用文檔,還會將其從屏幕集合中刪除。所有這一切都取決于它是否正面回答了“你能關門嗎?”。當然,文檔關閉后,指揮需要決定ScreenCollection中的哪些其他項目應該成為下一個活動文檔。

Implementations

有很多不同的方法來實現這些想法。您可以從TabControl繼承并實現IScreenConductor接口,并直接在控件中構建所有邏輯。把它添加到你的IoC容器中,你就可以開始跑步了。您可以在自定義UserControl上實現IScreen接口,也可以將其實現為POCO,用作監控控制器的基礎。ScreenCollection可以是一個自定義集合,具有維護活動屏幕的特殊邏輯,也可以只是一個簡單的IList。

Caliburn.Micro實現

這些概念通過各種接口和基類在CM中實現,這些接口和基類主要用于構建ViewModels。讓我們來看看它們:

Screens

在Caliburn.Micro中,我們將屏幕激活的概念分解為幾個界面:

IActivate–表示實現者需要激活。此接口提供激活方法、IsActive屬性和激活事件,激活時應引發這些事件。

IDeactivate–表示實現者需要停用。此接口有一個Deactivate方法,該方法采用bool屬性,指示除禁用屏幕外是否關閉屏幕。它還有兩個事件:AttemptingDeactivation(應在停用前引發)和Deactivate(應在停用后引發)。

IGuardClose–表示實現者可能需要取消關閉操作。它有一種方法:CanClose。該方法是使用異步模式設計的,允許在做出密切決策時發生復雜的邏輯,如異步用戶交互。調用方將向CanClose方法傳遞一個操作。實現者應該在保護邏輯完成時調用該操作。Pass true表示實現者可以關閉,否則為false。

除了這些核心生命周期接口之外,我們還有一些其他接口可以幫助創建表示層類之間的一致性:

IHaveDisplayName–有一個名為DisplayName的屬性

INotifyPropertyChangedEx–此接口繼承標準INotifyPropertyChanged,并使用其他行為對其進行擴展。它添加了一個IsNotifying屬性(可用于關閉/打開所有更改通知)、一個NotifyOfPropertyChange方法(可調用該方法引發屬性更改)和一個Refresh方法(可用于刷新對象上的所有綁定)。

IObservableCollection–由以下接口組成:IList、INotifyPropertyChangedEx和INotifyCollectionChanged

IChild–由作為層次結構一部分或需要引用所有者的元素實現。它有一個名為Parent的屬性。

IViewAware–由需要了解其綁定到的視圖的類實現。它有一個AttachView方法,框架在將視圖綁定到實例時調用該方法。它有一個GetView方法,框架在為實例創建視圖之前調用該方法。這允許緩存復雜視圖,甚至復雜視圖解析邏輯。最后,當視圖附加到名為ViewAttached的實例時,應該引發一個事件。

由于某些組合非常常見,我們有一些方便的接口和基類:

PropertyChangedBase–實現INotifyPropertyChangedEx(從而實現INotifyPropertyChanged)。除了標準字符串機制之外,它還提供了一個基于lambda的NotifyOfPropertyChange方法,支持強類型更改通知。此外,所有屬性更改事件都會自動封送到UI線程。

BindableCollection–通過繼承標準ObservableCollection并添加INotifyPropertyChangedEx指定的其他行為來實現IObservableCollection。此外,此類確保所有屬性更改和集合更改事件都發生在UI線程上。

IScreen–此接口由其他幾個接口組成:IHaveDisplayName、IActivate、IDeactivate、IGuardClose和INotifyPropertyChangedEx。

Screen–繼承自PropertyChangedBase并實現IScreen接口。此外,還實現了IChild和iViewWare。

這意味著您可能會從PropertyChangedBase或Screen繼承大多數視圖模型。一般來說,如果您需要任何激活功能和PropertyChangedBase來完成其他一切,您將使用Screen。CM的默認屏幕實現還具有一些附加功能,可以輕松地連接到生命周期的適當部分:

OnInitialize–重寫此方法以添加僅在屏幕第一次激活時執行的邏輯。初始化完成后,IsInitialized將為true。

OnActivate–覆蓋此方法以添加每次激活屏幕時應執行的邏輯。激活完成后,IsActive將為true。

OnDeactivate–覆蓋此方法以添加自定義邏輯,該邏輯應在屏幕停用或關閉時執行。bool屬性將指示停用是否實際結束。停用完成后,IsActive將為false。

CanClose–默認實現始終允許關閉。重寫此方法以添加自定義保護邏輯。

OnViewLoaded–由于Screen實現了IViewAware,它借此機會讓您知道何時觸發視圖的Loaded事件。如果您遵循SupervisingController或被動查看樣式,并且需要使用視圖,請使用此選項。這也是放置視圖模型邏輯的地方,視圖模型邏輯可能依賴于視圖的存在,即使您可能沒有直接使用視圖。

TryClose–調用此方法關閉屏幕。如果屏幕由導體控制,它會要求導體啟動屏幕的關閉過程。如果屏幕不是由導體控制的,而是獨立存在的(可能是因為它是使用WindowManager顯示的),此方法將嘗試關閉視圖。在這兩種情況下,將調用CanClose邏輯,如果允許,將使用true值調用OnDeactivate。

所以,再重復一次:若你們需要一個生命周期,從屏幕繼承;否則從PropertyChangedBase繼承。

Conductors

正如我前面提到的,一旦引入生命周期,就需要一些東西來實施它。在Caliburn.Micro中,此角色由IConductor接口表示,該接口具有以下成員:

ActivateItem–調用此方法以激活特定項。如果導體使用“屏幕采集”,它也會將其添加到當前進行的項目中

DeactivateItem–調用此方法以停用特定項。第二個參數指示是否也應關閉該項。如果是這樣,如果導體使用“屏幕采集”,它也會將其從當前進行的項目中刪除

ActivationProcessed–在指揮處理項目激活時引發。它指示激活是否成功。

GetChildren–調用此方法返回導體正在跟蹤的所有項目的列表。如果導體使用“屏幕集合”,則返回所有“屏幕”,否則僅返回ActiveItem。(從iPart界面)

INotifyPropertyChangedEx–此接口由IConductor組成。

我們還有一個名為IConductActivieItem的接口,它由IConductor和IHaveActiveItem組成,用于添加以下成員:

ActiveItem–一個屬性,用于指示導體當前跟蹤的活動項目。

您可能已經注意到,CM的IConductor接口使用術語“項”而不是“屏幕”,我在引號中加了術語“屏幕集合”。原因是CM的導體實現不需要執行的項目來實現IScreen或任何特定接口。執行的項目可以是POCO。每個導體實現都是泛型的,對類型沒有約束,而不是強制使用IScreen。當要求導體激活/停用/關閉/等其正在執行的每個項目時,它會分別檢查它們是否存在以下細粒度接口:IActivate、IDeactivate、IGuardClose和IChild。實際上,我通常從Screen繼承已執行的項目,但這使您可以靈活地使用自己的基類,或者僅在每個類的基礎上實現所關心的生命周期事件的接口。您甚至可以讓一個導體跟蹤異構項,其中一些項繼承自屏幕,另一些項實現特定接口,或者根本沒有。

開箱即用的CM有三種IConductor實現,兩種與“屏幕集合”配合使用,另一種不配合使用。我們先來看看沒有收藏的售票員。

Conductor

這個簡單的導體通過顯式接口機制實現IConductor的大多數成員,并添加公開可用的相同方法的強類型版本。這允許通過接口以強類型方式(基于導體所執行的項目)處理導體。導體將停用和關閉視為同義詞。由于導線不保持“屏幕收集”,每個新項目的激活都會導致先前激活項目的停用和關閉。由于IGuardClose的異步性質以及傳導項可能實現或可能不實現此接口的事實,用于確定傳導項是否可以關閉的實際邏輯可能很復雜。因此,列車長將此委托給ICloseStrategy,ICloseStrategy負責處理此問題,并將查詢結果告知列車長。大多數情況下,您可以使用自動提供的DefaultCloseStrategy,但如果需要更改內容(可能IGuardClose不足以滿足您的需要),您可以將導體上的CloseStrategy屬性設置為您自己的自定義策略。

Conductor.Collection.OneActive

此實現具有導體的所有功能,但也添加了“屏幕集合”的概念。由于CM中的導體可以執行任何類型的類,因此此集合通過稱為Items而不是Screens的IObservableCollection公開。由于存在項目收集,已執行項目的停用和關閉不會被視為同義詞。激活新項目時,前一個激活項目僅被停用,并保留在“項目”集合中。要使用此導體關閉項,必須顯式調用其CloseItem方法。當項目關閉且該項目為激活項目時,指揮必須確定下一步應激活的項目。默認情況下,這是列表中上一個活動項之前的項。如果需要更改此行為,可以覆蓋DetermineExtItemToActivate。

Conductor.Collection.AllActive

類似地,此實現還具有Conductor的功能,并添加了“屏幕集合”的概念。主要區別在于,與單個項目同時處于活動狀態不同,許多項目可以處于活動狀態。關閉項目將停用該項目并將其從集合中移除。

關于CMs IConductor實現,我還沒有提到兩個非常重要的細節。首先,它們都繼承自屏幕。這是這些實現的一個關鍵特性,因為它在屏幕和導體之間創建了一個復合模式。假設您正在構建一個基本的導航樣式應用程序。您的shell將是導體的一個實例,因為它一次顯示一個屏幕,并且不維護集合。但是,假設其中一個屏幕非常復雜,需要一個多選項卡界面,每個選項卡都需要生命周期事件。嗯,這個特定的屏幕可能繼承自Conductor.Collection.OneActive。shell不需要考慮單個屏幕的復雜性。如果需要的話,其中一個屏幕甚至可以是實現IScreen而不是ViewModel的UserControl。第二個重要細節是第一個細節的結果。由于IConductor的所有OOTB實現都繼承自Screen,這意味著它們也有一個生命周期,生命周期級聯到它們正在執行的任何項目。因此,如果導體被停用,其活動項也將被停用。如果你試圖關閉一個導體,它將只能在它所執行的所有項目都可以關閉的情況下才能關閉。這是一個非常強大的功能。關于這一點,我注意到有一個方面經常絆倒開發人員**如果您在導體中激活了一個本身未激活的項目,則該項目在導體被激活之前不會被激活。**這一點在您思考時是有意義的,但偶爾會導致頭發拉扯。

Quasi-Conductors

在CM中,并不是所有可以成為屏幕的東西都植根于導體內部。例如,您的根視圖模型是什么?如果是指揮員,誰在激活它?這是引導程序執行的工作之一。引導程序本身不是引導者,但它理解上面討論的細粒度生命周期接口,并確保根視圖模型得到應有的尊重。WindowManager的工作方式與此類似,它的作用有點像一個指揮者,目的是強制執行模態(僅限非模態WPF)窗口的生命周期。所以,生命周期并不神奇。所有屏幕/導體必須植根于導體,或由引導程序或WindowManager管理,才能正常工作;否則,您將需要自己管理生命周期。

View-First

如果您正在使用WP7或Silverlight導航框架,您可能想知道是否/如何利用屏幕和導體。到目前為止,我一直在假設外殼工程主要采用ViewModel優先的方法。但是WP7平臺通過控制頁面導航來實施視圖優先的方法。SL Nav框架也是如此。在這些情況下,電話/導航框架就像一個導體。為了更好地使用ViewModels,WP7版本的CM有一個FrameAdapter,它與NavigationService掛鉤。這個適配器是由PhoneBootstrapper設置的,它理解導體所做的相同的細粒度生命周期接口,并確保在導航過程中在適當的時候在ViewModels上調用它們。您甚至可以通過在ViewModel上實現IGuardClose來取消手機的頁面導航。雖然FrameAdapter只是WP7版本的CM的一部分,但如果您希望將其與Silverlight導航框架結合使用,它應該可以方便地移植到Silverlight。

之前,我們在Caliburn.Micro中討論了屏幕和導體的理論和基本API。現在,我將介紹幾個示例中的第一個。此特定示例演示如何使用導體和兩個“頁面”視圖模型設置一個簡單的導航樣式shell。正如您從項目結構中看到的,我們有典型的Bootstrapper和ShellViewModel模式。為了使這個示例盡可能簡單,我甚至沒有使用帶引導程序的IoC容器。讓我們先看看ShellViewModel。它繼承自導體,實現如下:

以下是相應的ShellView:

請注意,ShellViewModel有兩個方法,每個方法都將視圖模型實例傳遞給ActivateItem方法。回想一下我們之前的討論,ActivateItem是導體上的一種方法,它將導體的ActiveItem屬性切換到此實例,并將實例推過屏幕生命周期的激活階段(如果它通過實現IActivate支持它)。還記得,如果ActiveItem已設置為實例,則在設置新實例之前,將檢查前一個實例是否實現了IGuardClose,這可能會取消ActiveItem的切換,也可能不會取消。假設當前ActiveItem可以關閉,那么導體將推動它通過生命周期的停用階段,將true傳遞給Deactivate方法以指示視圖模型也應該關閉。這就是在Caliburn.Micro中創建導航應用程序所需的全部內容。導體的ActiveItem表示“當前頁面”,導體管理從一個頁面到另一個頁面的轉換。這一切都是以ViewModel優先的方式完成的,因為驅動導航而不是“視圖”的是指揮家和子視圖模型

一旦基本導體結構就位,就很容易獲得它。ShellView演示了這一點。我們所要做的就是在視圖中放置ContentControl。通過將其命名為“ActiveItem”,我們的數據綁定約定開始生效。ContentControl的約定有點有趣。如果綁定到的項不是值類型,也不是字符串,那么我們假設內容是ViewModel。因此,我們沒有像在其他情況下那樣綁定到Content屬性,而是使用CM的自定義附加屬性:View.Model設置綁定。此屬性使CM的ViewLocator為視圖模型查找適當的視圖,并使CM的ViewModelBinder將兩者綁定在一起。完成后,我們將視圖彈出到ContentControl的Content屬性中。這個單一的約定使得框架中功能強大但簡單的ViewModel優先組合成為可能。

為了完整起見,讓我們看看PageOneViewModel和PageTwoViewModel:

Along with their views:

<UserControl x:Class="Caliburn.Micro.SimpleNavigation.PageOneView"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><TextBlock FontSize="32">Page One</TextBlock> </UserControl><UserControl x:Class="Caliburn.Micro.SimpleNavigation.PageTwoView"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><TextBlock FontSize="32">Page Two</TextBlock> </UserControl>

我想指出最后幾點。請注意,PageOneViewModel只是一個POCO,但PageTwoViewModel繼承自Screen。請記住,CM中的導線不會對可以進行的操作施加任何限制。相反,他們會在必要的時候檢查每個實例是否支持各種細粒度生命周期實例。因此,當為PageTwoViewModel調用ActivateItem時,它將首先檢查PageOneViewModel以查看是否實現了IGuardClose。由于它沒有,它將嘗試關閉它。然后,它將檢查是否實現了IDeactivate。由于沒有,它將繼續激活新項目。首先,它檢查新項是否實現了IChild。因為Screen是這樣做的,所以它連接了層次關系。接下來,它將檢查PageTwoViewModel以查看是否實現了IActivate。因為Screen會這樣做,所以OnActivate方法中的代碼將運行。最后,它將在導體上設置ActiveItem屬性并引發適當的事件。這里有一個重要的結果應該記住:激活是一個特定于ViewModel的生命周期過程,不能保證任何有關視圖狀態的信息。很多時候,即使您的ViewModel已激活,其視圖也可能不可見。運行示例時,您將看到這一點。消息框將在激活發生時顯示,但第二頁的視圖仍不可見。請記住,如果您有任何依賴于已加載視圖的激活邏輯,則應覆蓋Screen.OnViewLoaded,而不是與OnActivate結合使用。

Simple MDI

讓我們看另一個例子:這一次是一個使用“屏幕集合”的簡單MDI shell。正如您再次看到的,我讓事情變得非常小和簡單:

下面是應用程序運行時的屏幕截圖:

這里我們有一個簡單的WPF應用程序,其中包含一系列選項卡。單擊“打開選項卡”按鈕會產生明顯的效果。單擊選項卡內的“X”將關閉該特定選項卡(也可能是顯而易見的)。讓我們通過查看ShellViewModel深入了解代碼:

public class ShellViewModel : Conductor<IScreen>.Collection.OneActive {int count = 1;public void OpenTab() {ActivateItem(new TabViewModel {DisplayName = "Tab " + count++});} }

由于我們希望維護一個打開項目的列表,但一次只保持一個項目處于活動狀態,因此我們使用Conductor.Collection.OneActive作為基類。注意,與前面的示例不同,我實際上是將已執行項的類型限制為IScreen。在這個示例中并沒有真正的技術原因,但這更接近于我在實際應用程序中的實際操作。OpenTab方法只需創建TabViewModel的一個實例,并設置其DisplayName屬性(來自IScreen),使其具有人類可讀的唯一名稱。讓我們思考幾個關鍵場景中導體與其屏幕之間的交互邏輯:

打開第一項

將項目添加到“項目”集合。

檢查項目是否存在IActivate,如果存在則調用它。

將項目設置為ActiveItem。

關閉現有項目

將該項傳遞給CloseStrategy,以確定是否可以關閉該項(默認情況下,它查找IGuardClose)。否則,操作將被取消。

檢查結束項是否為當前活動項。如果是,請確定下一步要激活的項目,并按照“打開其他項目”中的步驟進行操作

檢查結賬項目是否已激活。如果是這樣,則使用true調用以指示應該停用和關閉它。

從Items集合中刪除該項。

這些是主要的情況。希望你能看到一些不同的指揮家沒有收集,并理解為什么這些差異存在。讓我們看看ShellView如何渲染:

<Window x:Class="Caliburn.Micro.SimpleMDI.ShellView"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:cal="http://www.caliburnproject.org"Width="640"Height="480"><DockPanel><Button x:Name="OpenTab"Content="Open Tab" DockPanel.Dock="Top" /><TabControl x:Name="Items"><TabControl.ItemTemplate><DataTemplate><StackPanel Orientation="Horizontal"><TextBlock Text="{Binding DisplayName}" /><Button Content="X"cal:Message.Attach="DeactivateItem($dataContext, 'true')" /></StackPanel></DataTemplate></TabControl.ItemTemplate></TabControl></DockPanel> </Window>

如您所見,我們使用的是WPF選項卡控件。CM的約定將其ItemsSource綁定到Items集合,將其SelectedItem綁定到ActiveItem。它還將添加一個默認ContentTemplate,用于在ActiveItem的ViewModel/View對中進行組合。約定還可以提供ItemTemplate,因為我們的選項卡都實現IHaveDisplayName(通過屏幕),但我選擇通過提供我自己的來啟用關閉選項卡來覆蓋它。我們將在后面的文章中更深入地討論約定。為完整起見,以下是TabViewModel及其視圖的簡單實現:

namespace Caliburn.Micro.SimpleMDI {public class TabViewModel : Screen {} }<UserControl x:Class="Caliburn.Micro.SimpleMDI.TabView"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><StackPanel Orientation="Horizontal"><TextBlock Text="This is the view for "/><TextBlock x:Name="DisplayName" /><TextBlock Text="." /></StackPanel> </UserControl>

到目前為止,我一直試圖保持簡單,但我們的下一個樣本并非如此。在準備過程中,您可能希望至少仔細考慮或嘗試做以下事情:

擺脫常規的TabViewModel。在真正的應用程序中,您不會真的做這樣的事情。創建兩個自定義視圖模型和視圖。將對象連接起來,以便可以在導體中打開不同的視圖模型。當激活每個視圖模型時,確認在選項卡控件中看到正確的視圖。

在Silverlight中重建此示例。不幸的是,Silverlight的TabControl完全崩潰,無法充分利用數據綁定。相反,嘗試使用水平列表框作為選項卡,使用ContentControl作為選項卡內容。將它們放在DockPanel中,并使用一些命名約定,您將獲得與TabControl相同的效果。

創建工具欄視圖模型。添加IoC容器并將ToolBarViewModel注冊為singleton。將其添加到ShellViewModel,并確保在ShellView中呈現(請記住,您可以為此使用命名ContentControl)。接下來,將工具欄ViewModel插入到每個選項卡ViewModels中。在選項卡ViewModel OnActivate和OnActivate中編寫代碼,以便在激活特定選項卡ViewModel時從工具欄中添加/刪除上下文項。額外好處:創建一個DSL來完成這項工作,它不需要在激活覆蓋中使用顯式代碼。提示:使用事件。

取SimpleMDI樣本和SimpleNavigation樣本,并將它們組合在一起。在導航示例中將MDI外殼添加為PageViewModel,或在MDI示例中將導航外殼添加為選項卡。

Hybrid

此示例大致基于Billy Hollis在這部著名的DNR電視劇中展示的想法。與其花時間解釋UI的功能,不如看一下這個簡短的視頻,以獲得一個簡短的視覺解釋。

好的,現在您已經看到了它的功能,讓我們看看它是如何組合在一起的。正如您從屏幕截圖中看到的,我選擇按功能組織項目:客戶、訂單、設置等。在大多數項目中,我更喜歡這樣做,而不是按“技術”分組組織,如視圖和視圖模型。如果我有一個復雜的特性,那么我可能會將其分解為這些區域。

我不打算逐行檢查這個樣本。如果你花點時間仔細看看,自己弄清楚事情是如何運作的,那就更好了。但是,我想指出一些有趣的實現細節。

ViewModel Composition

Caliburn.Micro的屏幕和導體最重要的特征之一是,它們是復合模式的實現,使它們易于以不同的配置組合在一起。一般來說,組合是面向對象編程最重要的方面之一,學習如何在表示層中使用它可以帶來很大的好處。為了了解構圖在這個特定示例中的作用,讓我們看兩個屏幕截圖。第一個顯示視圖中包含CustomerWorkspace的應用程序,編輯特定客戶的地址。第二個屏幕是相同的,但其視圖/視圖模型對是三維旋轉的,因此您可以看到UI是如何組成的。

編輯客戶地址

編輯客戶地址(3D分支)

在此應用程序中,ShellViewModel是一個Conductor.Collection.OneActive。它在視覺上由窗口鍍鉻、標題和底部底座表示。碼頭有按鈕,每個正在進行的IWorkspace都有一個按鈕。單擊特定按鈕可使Shell激活該特定工作區。由于ShellView有一個綁定到ActiveItem的TransitionContentControl,激活的工作區被注入,其視圖顯示在該位置。在本例中,激活的是CustomerWorkspace視圖模型。CustomerWorkspaceViewModel恰好繼承了Conductor.Collection.OneActive。此ViewModel有兩個上下文視圖(請參見下文)。在上面的屏幕截圖中,我們顯示了詳細信息視圖。details視圖還有一個TransitionContentControl綁定到CustomerWorkspaceViewModel的ActiveItem,從而導致當前CustomerServiceWModel與其視圖一起組成。CustomerViewModel能夠顯示本地模式對話框(它們只是特定自定義記錄的模式對話框,而不是其他任何對話框)。這是由DialogConductor的實例管理的,DialogConductor是CustomServiceWModel上的一個屬性。DialogConductor的視圖覆蓋CustomerView,但僅當DialogConductor的ActiveItem不為null時才可見(通過值轉換器)。在上面描述的狀態中,DialogConductor的ActiveItem被設置為AddressViewModel的實例,因此模態對話框與AddressView一起顯示,并且基礎CustomerView被禁用。本示例中使用的整個shell框架就是以這種方式工作的,只需實現IWorkspace即可完全擴展。CustomerViewModel和SettingsViewModel是此接口的兩種不同實現,您可以深入研究。

同一ViewModel上的多個視圖

您可能不知道這一點,但是Caliburn.Micro可以在同一個ViewModel上顯示多個視圖。在View/ViewModel的注入站點上設置View.Context attached屬性可以支持這一點。以下是默認CustomerWorkspace視圖中的一個示例:

<clt:TransitioningContentControl cal:View.Context="{Binding State, Mode=TwoWay}"cal:View.Model="{Binding}" Style="{StaticResource specialTransition}"/>

圍繞它還有許多其他Xaml,以形成CustomerWorkSpace視圖的chrome,但內容區域是視圖中最值得注意的部分。請注意,我們正在將View.Context附加屬性綁定到CustomerWorkspaceViewModel的State屬性。這允許我們根據該屬性的值動態更改視圖。因為這些都托管在TransitioningContentControl中,所以每當視圖發生更改時,我們都會得到一個很好的轉換。此技術用于將CustomerWorkSpace視圖模型從“主”視圖(其中顯示所有打開的CustomerViewModel)、搜索UI和新按鈕切換到“詳細”視圖,其中顯示當前激活的CustomerViewModel及其特定視圖(由中組成)。為了讓CM找到這些上下文視圖,您需要一個基于ViewModel名稱的名稱空間,減去單詞“View”和“Model”,其中一些視圖的名稱與上下文對應。例如,當框架查找Caliburn.Micro.HelloScreens.Customers.CustomersWorkspaceViewModel的詳細視圖時,它將查找Caliburn.Micro.HelloScreens.Customers.CustomersWorkspace.Detail,這是現成的命名約定。如果這不適用于您,只需自定義ViewLocator.LocateForModelType函數。

自定義IConductor實現

盡管Caliburn.Micro為開發人員提供了IScreen和IConductor的默認實現。很容易實現您自己的。在這個示例中,我需要一個對話框管理器,它可以是應用程序特定部分的模態,而不會影響其他部分。正常情況下,默認導體可以工作,但我發現我需要微調關機順序,所以我實現了自己的。讓我們看一看:

[Export(typeof(IDialogManager)), PartCreationPolicy(CreationPolicy.NonShared)] public class DialogConductorViewModel : PropertyChangedBase, IDialogManager, IConductActiveItem {readonly Func<IMessageBox> createMessageBox;[ImportingConstructor]public DialogConductorViewModel(Func<IMessageBox> messageBoxFactory) {createMessageBox = messageBoxFactory;}public IScreen ActiveItem { get; private set; }public IEnumerable GetChildren() {return ActiveItem != null ? new[] { ActiveItem } : new object[0];}public void ActivateItem(object item) {ActiveItem = item as IScreen;var child = ActiveItem as IChild;if(child != null)child.Parent = this;if(ActiveItem != null)ActiveItem.Activate();NotifyOfPropertyChange(() => ActiveItem);ActivationProcessed(this, new ActivationProcessedEventArgs { Item = ActiveItem, Success = true });}public void DeactivateItem(object item, bool close) {var guard = item as IGuardClose;if(guard != null) {guard.CanClose(result => {if(result)CloseActiveItemCore();});}else CloseActiveItemCore();}object IHaveActiveItem.ActiveItem{get { return ActiveItem; }set { ActivateItem(value); }}public event EventHandler<ActivationProcessedEventArgs> ActivationProcessed = delegate { };public void ShowDialog(IScreen dialogModel) {ActivateItem(dialogModel);}public void ShowMessageBox(string message, string title = "Hello Screens", MessageBoxOptions options = MessageBoxOptions.Ok, Action<IMessageBox> callback = null) {var box = createMessageBox();box.DisplayName = title;box.Options = options;box.Message = message;if(callback != null)box.Deactivated += delegate { callback(box); };ActivateItem(box);}void CloseActiveItemCore() {var oldItem = ActiveItem;ActivateItem(null);oldItem.Deactivate(true);} }

嚴格地說,我實際上不需要實現IConductor來完成這項工作(因為我沒有將它組合成任何東西)。但我選擇這樣做是為了表示這個類在系統中扮演的角色,并盡可能保持體系結構上的一致性。實現本身非常簡單。導體主要需要確保正確激活/停用其項目,并正確更新ActiveItem屬性。我還創建了兩個簡單的方法來顯示對話框和消息框,這些對話框和消息框通過IDialogManager界面公開。該類在MEF中注冊為非共享,以便希望顯示本地模態的應用程序的每個部分都將獲得自己的實例,并能夠維護自己的狀態,如上面討論的CustomServiceWModel所示。

自定義策略

本示例最酷的特性之一可能是如何控制應用程序關閉。由于IShell繼承了IGuardClose,因此在引導程序中,我們只需覆蓋啟動并連接Silverlight的主窗口。關閉事件以調用IShell.CanClose:

protected override void OnStartup(object sender, StartupEventArgs e) {base.OnStartup(sender, e);if(Application.IsRunningOutOfBrowser) {mainWindow = Application.MainWindow;mainWindow.Closing += MainWindowClosing;} }void MainWindowClosing(object sender, ClosingEventArgs e) {if (actuallyClosing)return;e.Cancel = true;Execute.OnUIThread(() => {var shell = IoC.Get<IShell>();shell.CanClose(result => {if(result) {actuallyClosing = true;mainWindow.Close();}});}); }

ShellViewModel通過其基類Conductor.Collection.OneActive繼承此功能。由于所有內置導體都有閉合策略,因此我們可以創建特定于導體的關機機制,并輕松地將其插入。以下是我們如何插入自定義策略:

[Export(typeof(IShell))] public class ShellViewModel : Conductor<IWorkspace>.Collection.OneActive, IShell {readonly IDialogManager dialogs;[ImportingConstructor]public ShellViewModel(IDialogManager dialogs, [ImportMany]IEnumerable<IWorkspace> workspaces) {this.dialogs = dialogs;Items.AddRange(workspaces);CloseStrategy = new ApplicationCloseStrategy();}public IDialogManager Dialogs {get { return dialogs; }} }

以下是該戰略的實施情況:

public class ApplicationCloseStrategy : ICloseStrategy<IWorkspace> {IEnumerator<IWorkspace> enumerator;bool finalResult;Action<bool, IEnumerable<IWorkspace>> callback;public void Execute(IEnumerable<IWorkspace> toClose, Action<bool, IEnumerable<IWorkspace>> callback) {enumerator = toClose.GetEnumerator();this.callback = callback;finalResult = true;Evaluate(finalResult);}void Evaluate(bool result){finalResult = finalResult && result;if (!enumerator.MoveNext() || !result)callback(finalResult, new List<IWorkspace>());else{var current = enumerator.Current;var conductor = current as IConductor;if (conductor != null){var tasks = conductor.GetChildren().OfType<IHaveShutdownTask>().Select(x => x.GetShutdownTask()).Where(x => x != null);var sequential = new SequentialResult(tasks.GetEnumerator());sequential.Completed += (s, e) => {if(!e.WasCancelled)Evaluate(!e.WasCancelled);};sequential.Execute(new ActionExecutionContext());}else Evaluate(true);}} }

我在這里做的有趣的事情是重用IResult功能來異步關閉應用程序。以下是自定義策略如何使用它:

檢查每個IWorkspace以查看它是否是IConductor。

如果為true,則獲取實現應用程序特定接口IHaveShutdownTask的所有已執行項。

通過調用GetShutdownTask檢索關機任務。如果沒有任務,它將返回null,所以將其過濾掉。

由于關機任務是IResult,因此將所有這些傳遞給SequentialResult并開始枚舉。

IResult可以將ResultCompletionEventArgs.wasCancelled設置為true以取消應用程序關閉。

繼續執行所有工作區,直到完成或取消。

如果所有IResults成功完成,將允許關閉應用程序。

如果存在臟數據,CustomerViewModel和OrderViewModel將使用此機制顯示模式對話框。但是,您也可以將其用于任意數量的異步任務。例如,假設您有一個長時間運行的進程,希望防止應用程序關閉。這也會很好地解決這個問題。

02

最后

原文標題:Caliburn.Micro Xaml made easy

原文鏈接:https://caliburnmicro.com/documentation/coroutines

翻譯:dotnet編程大全

C#技術群?:?添加小編微信mm1552923,備注:進群!

總結

以上是生活随笔為你收集整理的C# WPF MVVM开发框架Caliburn.Micro Screens, Conductors 和 Composition⑦的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

国产精品伦一区二区三区视频 | 国产精品久久久久久久久久尿 | 亚洲免费在线视频 | 日本久久免费电影 | 亚洲午夜精品一区二区三区电影院 | 人人澡人人爽欧一区 | 欧美一级久久久久 | 激情五月婷婷丁香 | av免费试看 | 四虎国产精品成人免费影视 | 天天色天天草天天射 | 91成人精品国产刺激国语对白 | 免费成人在线视频网站 | a级片久久久 | 亚洲精品视频在线 | 4p变态网欧美系列 | 日韩欧美综合视频 | 日韩欧美高清在线 | 国产特级毛片 | 91成版人在线观看入口 | 欧美午夜一区二区福利视频 | 婷婷性综合 | 国产少妇在线观看 | 日韩精品极品视频 | 日韩免费成人 | 天天射天天干天天插 | 成人午夜剧场在线观看 | 九九热在线精品视频 | 亚洲精品资源在线观看 | 免费视频xnxx com | 超碰人人草人人 | 亚洲欧美日韩精品久久久 | 天天干天天干天天干天天干天天干天天干 | 香蕉色综合 | 四虎在线免费观看视频 | 国产96精品 | 久久国产片 | 亚洲黄网站 | 中文字幕超清在线免费 | 丁香视频免费观看 | 国产色婷婷精品综合在线手机播放 | 中文字幕av在线播放 | 久久精品中文 | a色网站| 免费视频a | 免费高清无人区完整版 | 久久精品4 | 国产精品久久久久久婷婷天堂 | 欧美性视频网站 | 国产99在线 | 国产裸体视频bbbbb | 天堂成人在线 | 在线观看黄色的网站 | 免费久久99精品国产 | 成人精品国产 | 国产精品1区2区在线观看 | 久久97久久97精品免视看 | 国产涩图| 欧美午夜精品久久久久久浪潮 | 五月婷婷综合在线 | 国产91亚洲精品 | 国产人在线成免费视频 | 99热免费在线 | 欧美孕妇与黑人孕交 | 久久久久久久久久福利 | 亚洲视频 在线观看 | 国产乱对白刺激视频在线观看女王 | 夜夜躁日日躁狠狠久久av | 欧美久久电影 | 91麻豆精品久久久久久 | 成人免费视频网站在线观看 | 午夜精品999| 国产亚洲欧洲 | 国产精品电影在线 | 日韩在线视频看看 | 一级免费黄色 | 久久人人爽人人爽人人片av软件 | 深夜免费福利在线 | 中文字幕有码在线 | 91大神dom调教在线观看 | 国产99久久久精品视频 | 精品国产大片 | 92中文资源在线 | 99免费国产| www.国产在线 | 亚洲全部视频 | 日韩视频一区二区三区 | 国产一级片一区二区三区 | 国产精品久久久久久久久久了 | 国产精品久久久久久影院 | 97超碰在线播放 | 日韩精品中文字幕在线不卡尤物 | 91丨porny丨九色 | 国产尤物在线 | 九九视频这里只有精品 | 国产亚洲综合性久久久影院 | 亚洲精品99久久久久久 | 国产视频一区在线播放 | 精品亚洲国产视频 | 国产精品视频区 | 中文字幕成人 | 亚洲春色奇米影视 | 欧美国产日韩一区二区三区 | 亚洲欧美日韩在线一区二区 | 国产一区二区高清不卡 | 97av免费视频 | 日日爱视频 | 天天在线免费视频 | 欧美精品久久久久久久久久丰满 | 91高清不卡 | 天天射天| 狠狠色2019综合网 | 日韩a在线 | 久久综合爱| 中文字幕一区二区三区久久 | 中文字幕在线观看视频免费 | 久久国产精彩视频 | 日韩三级在线观看 | 国产精品国产精品 | 182午夜在线观看 | 麻豆视频成人 | 成年人看片| 婷婷在线视频观看 | 亚洲视频六区 | 五月婷婷av在线 | 日韩精品电影在线播放 | 免费看网站在线 | 激情导航 | 天天综合色天天综合 | 五月综合色 | 天天综合91 | 四虎国产精品免费 | 亚洲区视频在线观看 | 久草免费在线视频观看 | a成人在线 | 丁香六月伊人 | 欧美日本在线视频 | 国产成人久久 | 国产伦精品一区二区三区无广告 | 国产福利在线 | 精品国产激情 | 欧美精品久久久久久久免费 | 狠狠狠综合 | 亚洲黄在线观看 | 激情视频免费在线 | 免费在线中文字幕 | 国产免费专区 | av大全在线免费观看 | 青青河边草免费视频 | 欧美精品乱码久久久久久 | 国产精品系列在线 | 精品日本视频 | 98超碰在线| www.五月婷婷 | 婷婷天天色 | 亚洲人xxx | 亚洲成人av在线电影 | 色在线国产 | 日韩av不卡在线观看 | 99视频导航 | 黄色在线视频网址 | 亚洲一一在线 | 婷婷激情欧美 | 69国产成人综合久久精品欧美 | 天天操天天摸天天爽 | 国产黄色片在线 | 三级小视频在线观看 | 久久天天躁狠狠躁亚洲综合公司 | 欧美巨乳网 | av青草 | 久久久久久久久久久久久影院 | 日韩色视频在线观看 | 久久天天躁狠狠躁夜夜不卡公司 | 成人资源在线 | 国产一区二区在线免费播放 | 日韩免费在线网站 | 久久久精品国产免费观看一区二区 | 人人干人人做 | 黄色a三级| 蜜臀av性久久久久蜜臀aⅴ涩爱 | 国产片免费在线观看视频 | 国产精品自产拍在线观看桃花 | 国产精品入口66mio女同 | 日韩丝袜在线观看 | 99re8这里有精品热视频免费 | 婷婷综合激情 | 国产成人亚洲精品自产在线 | 久久电影中文字幕视频 | 91在线免费观看国产 | 97av影院| 国产尤物一区二区三区 | 中文十次啦 | 99精品在线免费观看 | 亚洲精品五月天 | 国产黑丝袜在线 | 视频国产精品 | 亚洲一区二区三区91 | 欧美成年人在线观看 | 日韩中文幕 | 爱爱av在线 | 婷婷色婷婷 | 狠狠的操狠狠的干 | 国产精品av在线免费观看 | 最近最新最好看中文视频 | 久久久久久久影视 | 在线 国产 日韩 | av亚洲产国偷v产偷v自拍小说 | 永久免费精品视频 | 亚洲小视频在线观看 | 久久99欧美| 手机av永久免费 | 国产特级毛片aaaaaa高清 | av在线播放免费 | 午夜少妇av | 午夜久久视频 | 久久国产视频网 | 天天久久综合 | 天天操夜 | 91丨九色丨蝌蚪丨老版 | 在线观看日韩视频 | 超碰在线日韩 | 日本免费久久高清视频 | 日韩av成人在线 | 激情电影影院 | 久久精品网站视频 | 一级成人免费视频 | 久久精品在线 | 69精品在线 | 一区二区精品久久 | 黄色片视频在线观看 | 国产成人一区二区在线观看 | av电影在线不卡 | 很黄很黄的网站免费的 | 国产日韩精品一区二区三区在线 | 九热精品 | 成人中文字幕在线观看 | 国产一在线精品一区在线观看 | 成人av在线资源 | 中国老女人日b | 在线a视频免费观看 | 亚洲欧美国产精品 | 色婷婷亚洲婷婷 | 黄色com| 麻豆成人在线观看 | 亚洲视频一级 | 91视频在线观看免费 | av在线免费在线 | 久久久影院官网 | 99久国产| 片网址| 区一区二区三在线观看 | 精品国产区 | 日本黄色a级大片 | av在线a | 97视频免费观看 | 国产一区二区久久久 | 久av在线 | 成人影音在线 | 日韩精品网址 | 欧美一级片免费 | 国产精品理论片在线观看 | 综合在线色 | 日韩在线观看视频在线 | 久产久精国产品 | 日韩大片在线 | 操操操综合 | www.在线观看av| 欧美激情另类 | 国产在线一区二区 | 亚洲精品美女在线 | 日韩中文字幕视频在线 | 超碰在线官网 | 国产精品视频免费看 | 91精品一区二区三区蜜臀 | 久久久久久久久久久久久国产精品 | 国产1区在线 | 日韩国产精品久久 | 97av在线 | 97精品国产一二三产区 | 久久人人精 | 久久99最新地址 | 制服丝袜一区二区 | 国产999| www国产亚洲精品久久网站 | 欧美精品一区二区在线观看 | 深爱激情五月网 | 精品人人人 | 91福利区一区二区三区 | 天天做日日做天天爽视频免费 | 亚洲专区欧美专区 | 99精品视频在线播放观看 | 亚洲欧美怡红院 | 性色av香蕉一区二区 | 在线观看视频免费播放 | 亚洲国产精品日韩 | 色九九视频 | 欧美日韩久久 | 黄色毛片网站在线观看 | 久热免费在线观看 | 88av色| 成人毛片一区 | 91av资源网 | 成人精品亚洲 | 久久久久久免费网 | 日韩性色| 深夜男人影院 | 午夜精品在线看 | 中文字幕色站 | 国产99久久精品一区二区300 | 五月婷婷中文字幕 | 久久久免费播放 | 91探花在线 | 午夜视频一区二区三区 | 成人av一区二区三区 | 日本精a在线观看 | 欧美日韩综合在线 | 成人av电影免费 | 国产在线欧美在线 | 亚洲精品一区二区三区四区高清 | 黄色免费av | 免费成人av网站 | 亚洲自拍av在线 | 久草在线视频精品 | 97碰视频| 中文字幕av有码 | 久久精品99国产精品亚洲最刺激 | 天天插日日射 | 欧美在线free | 一区二区欧美在线观看 | 中文字幕一区二区三区乱码不卡 | 亚洲欧美成人在线 | 日韩在线观看精品 | 在线观看的黄色 | 欧美国产日韩在线观看 | 国产在线欧美 | 四虎最新域名 | 在线观看视频你懂 | 国产视频一区在线免费观看 | 国产视频精选在线 | 中文字幕资源网 国产 | 日韩在线视频在线观看 | 亚洲最大成人免费网站 | 国产69精品久久99的直播节目 | 国产成人精品在线观看 | 999成人网 | 亚洲黄色影院 | 亚洲永久字幕 | 观看免费av | 狠狠操夜夜| 国产一区二区免费在线观看 | 精品人妖videos欧美人妖 | 国产一区二区在线免费播放 | 午夜精品一区二区三区可下载 | 蜜臀av在线一区二区三区 | 亚洲涩涩色 | 国产成人高清在线 | 91中文字幕视频 | 在线黄色国产 | 国产九九在线 | 久久99国产一区二区三区 | 色偷偷88888欧美精品久久久 | 久久一区二区免费视频 | 69人人| 日韩美视频 | 成年人在线 | 午夜av色| 久久国产精品成人免费浪潮 | 久久人人爽人人爽人人片 | 中文字幕在线观看完整 | 在线中文字幕电影 | www.91成人 | 欧美午夜一区二区福利视频 | 国产美腿白丝袜足在线av | 欧美性护士 | 亚洲精品乱码白浆高清久久久久久 | 亚洲欧美在线视频免费 | 精品人妖videos欧美人妖 | 亚洲精品a区 | 五月婷婷综合激情 | 在线观看色视频 | 色a网| 久久精品视频在线播放 | 91在线观 | 激情欧美一区二区三区免费看 | 99精品黄色片免费大全 | 国产亚洲综合性久久久影院 | 探花视频在线观看免费版 | 亚洲精品国产精品国产 | 韩日av在线 | 精品亚洲二区 | 日韩欧美精品在线视频 | 激情伊人五月天 | 国产精品欧美一区二区 | av电影在线播放 | 天天综合网入口 | 欧美久久久久久久 | 天天色天天操天天爽 | 天天干天天干天天干天天干天天干天天干 | av在线播放免费 | 99精品欧美一区二区 | 精品欧美一区二区三区久久久 | www.精选视频.com| av电影中文字幕 | 91新人在线观看 | 久久久久久久久久免费视频 | 天天干天天干天天干 | 久久99精品久久久久婷婷 | 91免费网址| 亚洲精品av在线 | 91精品国产乱码在线观看 | 亚洲国产成人精品电影在线观看 | 色就是色综合 | 1024久久 | 日韩午夜大片 | 国产一级大片在线观看 | 久久免费看a级毛毛片 | 国产精品av在线免费观看 | 六月丁香伊人 | av超碰在线 | 香蕉网在线 | 波多野结衣视频网址 | 四虎影视久久久 | 九草视频在线 | 中国成人一区 | 亚洲香蕉在线观看 | 久久精品久久99 | 午夜精品久久久久久久99婷婷 | 成人资源在线观看 | 国产高清在线观看 | 99午夜 | 天堂av在线网站 | 婷婷激情欧美 | 亚洲高清激情 | 久久免费成人精品视频 | 日韩高清不卡在线 | 色综合亚洲精品激情狠狠 | 国产精品粉嫩 | 久久综合偷偷噜噜噜色 | 中文字幕在线看视频国产中文版 | 狠狠色丁香婷婷综合橹88 | 国产精品美女网站 | 久久97久久 | www操操| 黄色福利网 | 欧美一级电影在线观看 | 69视频在线播放 | 美女网站在线 | 97在线看片| 午夜精品一区二区三区视频免费看 | 色婷久久 | 精品视频 | 久草91视频 | 欧美精品在线观看免费 | 在线91网| 欧美视频在线观看免费网址 | 国产精品成人在线观看 | 久久久久久美女 | 午夜精品一区二区三区免费 | 97电影在线 | 久久99国产精品视频 | 国产永久网站 | 国产精品99久久99久久久二8 | 欧美性粗大hdvideo | 九九视频网站 | 中文字幕在线成人 | 日韩免费观看一区二区三区 | 精品视频专区 | 国产成人精品999在线观看 | 天天艹天天 | 免费看一级特黄a大片 | 天天插天天色 | 国产区欧美 | 日本中文字幕影院 | 丁香花在线视频观看免费 | 色婷婷a | 久久精品国产一区二区三区 | 你操综合| 91丨九色丨蝌蚪丨老版 | 久久久久二区 | 中文字幕在线国产精品 | 天天色图 | 亚洲午夜精品久久久 | 人人射 | 精品视频免费播放 | 亚洲天堂va | 夜添久久精品亚洲国产精品 | 免费激情网 | 亚洲人成免费网站 | 99产精品成人啪免费网站 | av黄色在线播放 | 天天鲁天天干天天射 | 夜夜夜精品| 久久久久久免费毛片精品 | 麻豆一级视频 | 韩日电影在线观看 | 在线视频区 | 色射色 | a亚洲视频| 久久国产露脸精品国产 | 欧美一二三视频 | av综合站| 天天爽天天爽夜夜爽 | 免费三级黄 | 手机av网站 | 五月天综合激情网 | 成人黄色毛片 | 国产精品6 | 在线婷婷| 日韩城人在线 | 亚洲日本一区二区在线 | 五月天久久综合网 | 99久久99| 在线观看免费视频你懂的 | 国产99区 | 中文字幕在线一二 | 成年人国产视频 | 日韩在线精品视频 | 在线观看不卡视频 | 日韩黄色一级电影 | 四虎国产精品成人免费4hu | 婷色| 中国一区二区视频 | 国产免费视频一区二区裸体 | 99c视频高清免费观看 | 久久不卡日韩美女 | 国产在线a免费观看 | 中文字幕久久亚洲 | 深爱激情亚洲 | 玖玖在线视频观看 | 亚洲精品短视频 | 婷婷丁香花 | 精品视频不卡 | 91尤物在线播放 | 日韩av女优视频 | 96精品视频 | 成人sm另类专区 | 久久久www| 日韩视频一二三区 | 国产精品去看片 | 狠狠躁日日躁狂躁夜夜躁 | 青青河边草免费观看完整版高清 | 狠狠色丁香婷婷综合久小说久 | 人人看人人草 | 久久免费视频精品 | 在线免费亚洲 | 中文字幕精品在线 | 日韩精品专区在线影院重磅 | 国产九九热视频 | 中文字幕在线观看一区二区 | 香蕉视频18 | 黄色福利网站 | 国产91精品一区二区绿帽 | 欧美日韩精品影院 | 久久久精品免费观看 | 五月天综合网 | 999抗病毒口服液 | 伊人网综合在线观看 | 色爱成人网 | 在线免费黄色毛片 | 国产精品一区一区三区 | 天天射天天操天天色 | 91精品国产92久久久久 | 久久99国产视频 | 中文字幕999| 国产精品毛片完整版 | 亚洲精品综合欧美二区变态 | 狠狠躁18三区二区一区ai明星 | 日韩欧美视频一区二区 | 特级xxxxx欧美| 亚洲欧洲av | 久久一区国产 | 国产在线观看高清视频 | 91视频 - 114av| 黄色在线成人 | 国产一区黄色 | 日韩特黄一级欧美毛片特黄 | 91成人精品一区在线播放 | 一区二区三区在线观看 | 成人av在线亚洲 | 日日干美女 | 色在线视频 | 精品视频在线免费观看 | 国内久久久久 | 7777精品伊人久久久大香线蕉 | 久久这里有精品 | 欧美性成人 | 午夜三级影院 | 99精品在线免费 | 91精品视频免费 | 亚洲午夜在线视频 | 国产精品丝袜久久久久久久不卡 | 久久五月婷婷丁香 | 人人澡人人草 | 97超碰在线免费 | 亚洲精品视频在线观看免费 | 亚洲国产片 | 久久久久伦理电影 | 最近最新mv字幕免费观看 | 久草视频国产 | 98超碰人人 | 免费成人在线观看 | 亚洲视频电影在线 | 午夜美女福利 | 波多野结衣在线观看一区二区三区 | 国产色综合天天综合网 | av色综合网 | 天天夜操 | 亚洲麻豆精品 | 亚洲综合最新在线 | 免费视频久久久久久久 | a视频免费看 | 成人在线中文字幕 | 日韩 在线观看 | 国产精品视频大全 | 国产精品免费久久久久影院仙踪林 | 亚洲一级黄色av | 色综合天天狠天天透天天伊人 | www.天天干| 日韩一区二区三 | 五月天视频网站 | 亚洲欧美日本一区二区三区 | 免费下载高清毛片 | 日韩一区二区三 | 能在线观看的日韩av | 亚洲精品国产片 | 欧美9999| 色偷偷网站视频 | 99久久99视频只有精品 | 爱射综合 | 日本久久久精品视频 | 欧美另类视频 | 久久综合九色综合欧美狠狠 | 亚洲欧洲日韩 | www.午夜色.com | 97视频久久久 | 国产五月天婷婷 | 午夜丁香视频在线观看 | 国产成人精品久久亚洲高清不卡 | 国产成人一区在线 | 伊人影院在线观看 | 天堂在线一区二区 | 婷婷在线看 | 免费看黄的视频 | 久久影视一区 | 美女精品久久久 | 久久一区91 | 久久中文字幕视频 | 99精品热 | 国产精品不卡在线观看 | 欧美日韩不卡一区二区三区 | 青青草国产精品视频 | 日韩在线播放av | 午夜精品一区二区三区免费 | 国产精品久久精品国产 | 99精品视频在线免费观看 | 麻豆传媒在线视频 | 色婷婷九月 | 亚洲成a人片综合在线 | 在线观看国产日韩 | 日韩三级不卡 | 国产中文在线字幕 | 国产青草视频在线观看 | 在线观看av不卡 | 成人在线小视频 | 国产精品女 | 青草视频在线 | 日韩肉感妇bbwbbwbbw | www.久久久| 午夜性生活 | 操碰av| 亚洲电影自拍 | 91精品视频观看 | 久久不卡日韩美女 | 天天草综合网 | 免费a视频 | 亚洲欧美日韩国产一区二区三区 | 国产精品久久久久久久免费 | 中文字幕高清免费日韩视频在线 | 欧美精品在线观看 | av免费在线观看1 | 在线观看日本高清mv视频 | 激情深爱五月 | 97电影网站| 五月婷婷综合激情网 | 日韩电影中文字幕在线 | 国产亚洲精品av | 最近高清中文在线字幕在线观看 | 激情综合婷婷 | 久久久久黄色 | 四虎成人精品 | 日韩另类在线 | 99 视频 高清 | 亚洲精品视频一 | 亚洲最大免费成人网 | 中文字幕一区二区三区在线播放 | 国产999精品久久久影片官网 | 伊人天堂久久 | 91成人午夜 | 四虎5151久久欧美毛片 | 精品国模一区二区三区 | 一级黄色a视频 | 97精品在线观看 | 99热精品国产一区二区在线观看 | 欧美精品久久久久a | 人人草在线视频 | 亚洲日本va中文字幕 | 91网址在线观看 | 91精品在线播放 | 久久婷亚洲五月一区天天躁 | 在线不卡a | 久久精品网站视频 | 成人午夜精品福利免费 | 色视频网站免费观看 | 国产另类av | 高潮久久久| 亚洲精品456在线播放乱码 | 成人播放器 | 黄色av观看| 99性视频 | 国产在线精 | 欧美三级高清 | 香蕉国产91 | 美女视频是黄的免费观看 | 人人射人人射 | 91视频国产高清 | 深夜免费福利视频 | 亚洲乱码久久久 | 国产精品美女毛片真酒店 | 夜夜视频| 成人国产亚洲 | 午夜视频在线观看一区二区三区 | 丁香婷婷网 | 日狠狠| 99999精品| 久久久久久久久久久久亚洲 | 国产高清视频在线免费观看 | 麻豆传媒在线免费看 | 亚洲精品天天 | 国产啊v在线| 国产欧美中文字幕 | 久久久精品国产一区二区三区 | 日本激情视频中文字幕 | 亚洲成a人片在线观看网站口工 | 欧美一区二区三区免费看 | 91人人爱| 国产高清在线看 | 亚洲在线免费视频 | 久久久久这里只有精品 | 日本在线观看中文字幕 | 91色在线观看视频 | 精品国自产在线观看 | 久操中文字幕在线观看 | 香蕉影视| 成人四虎影院 | 久产久精国产品 | 国产精品情侣视频 | 国产精品99久久99久久久二8 | 91在线免费看片 | 成年人黄色在线观看 | av资源免费在线观看 | 成人av影视观看 | 国产 欧美 在线 | 九九综合九九综合 | 毛片网在线 | 高清不卡一区二区在线 | 麻豆视频网址 | 17videosex性欧美 | 国产成人免费精品 | 人人擦 | 亚洲国产大片 | 在线三级av | 中文字幕三区 | sesese图片| 91人人澡 | 香蕉网在线播放 | 2018好看的中文在线观看 | 99r在线| 色999精品| 亚洲午夜精品在线观看 | 夜夜爽www| 99福利影院 | 人人躁| 亚洲高清网站 | www.亚洲| 久久久精品国产免费观看一区二区 | 狠狠色狠狠色综合日日小说 | 97精品国产97久久久久久免费 | 午夜性色| 日韩欧美一区二区三区视频 | 久久激情综合 | 麻豆视频免费网站 | 96精品在线| 少妇bbb好爽 | 欧美日韩国产二区 | 99久久精品日本一区二区免费 | 婷久久 | 日韩视频在线不卡 | 亚洲精品自拍 | 亚洲久在线 | mm1313亚洲精品国产 | 亚洲成人资源网 | 国产麻豆传媒 | 日日操日日操 | 久久久69 | 五月天综合激情 | 91av视屏 | 国内综合精品午夜久久资源 | 国产在线观看,日本 | 一级黄色片网站 | 国产精品久久久99 | 国产91精品在线播放 | 日本在线观看中文字幕 | 免费看一级特黄a大片 | 99视频国产精品 | 午夜视频黄 | 国产人成一区二区三区影院 | 久久婷婷一区二区三区 | 国产小视频在线看 | 激情 婷婷 | 337p日本欧洲亚洲大胆裸体艺术 | 五月天六月婷 | 欧美伊人网 | 久久不射网站 | 国产精品久久久99 | 日日日操操 | 黄色录像av| 色婷婷狠狠五月综合天色拍 | 欧美a级在线免费观看 | 狠狠激情中文字幕 | 久久久久久黄 | 日日操天天操夜夜操 | 毛片网在线播放 | 国产一级久久久 | 在线观av| 1000部国产精品成人观看 | 久久综合成人 | 国产偷在线| 久久精品视频观看 | www.色婷婷| av中文资源在线 | 色综合天天综合 | 亚洲丁香久久久 | 欧美日韩国产亚洲乱码字幕 | 天天草综合网 | 91精品国产入口 | 欧美综合色在线图区 | 亚洲精品男人的天堂 | 免费视频久久久 | 免费福利在线视频 | 国产中文视频 | 国产精品美女在线 | 91成人免费看片 | 亚洲午夜精品久久久久久久久 | 久久久久99999 | 国产日产av | 天天色天天干天天色 | 精品视频免费观看 | 91精品国自产在线观看 | 福利网址在线观看 | www.久艹 | 国产又黄又爽又猛视频日本 | 亚洲.www | 国产18精品乱码免费看 | 超碰97免费 | 中文字幕视频在线播放 | 国产在线观看污片 | 中文字幕在线播放av | 婷婷激情五月综合 | 色综合天天做天天爱 | 久久99精品一区二区三区三区 | 天天做综合网 | 午夜精品一区二区三区在线视频 | 又黄又刺激的视频 | 97操操操 | av中文字幕免费在线观看 | 一区精品在线 | 成人午夜电影网站 | 亚洲另类视频在线 | av色综合网 | 亚洲激情久久 | 天天色天天色 | 成人毛片100免费观看 | 狠狠操精品 | 欧美精品一二三 | 天天综合天天做 | 人人爽人人爽人人片av | 成人av一级片 | 丁香六月婷婷开心婷婷网 | 欧美日韩精品免费观看 | 国产视频一区二区三区在线 | 免费看色网站 | 91九色成人蝌蚪首页 | 日韩精品免费一区二区 | 综合久久精品 | 成人免费在线播放 | 国产专区在线 | 99久久久国产精品美女 | 黄色小说视频网站 | 视频 天天草 | 99热最新 | 免费在线观看日韩 | 日韩婷婷| 韩国精品视频在线观看 | 国产精品一区二区三区观看 | 亚洲1区在线 | 久久久片 | 91丨九色丨高潮 | 国产精品手机播放 | 欧美日韩在线精品 | 成年人电影免费看 | 狠狠狠干 | 中文字幕视频一区二区 | 五月天综合在线 | 成人黄色国产 | 97视频免费在线看 | 97精品视频在线播放 | 96视频在线 | 日本中文在线观看 | 99爱精品视频 | 91在线视频免费播放 | 中文字幕一区在线 | 国产精品wwwwww | 在线视频久 | 久久久久久久免费看 | 午夜精品久久久久久久99 | 中文字幕在线专区 | 日韩精品在线一区 | 九九国产精品视频 | 91视频这里只有精品 | 亚洲黄色一级大片 | 色a综合 | 国产精品第一页在线 | 狠狠色狠狠色合久久伊人 | 亚洲婷婷综合色高清在线 | 久久亚洲综合国产精品99麻豆的功能介绍 | 久久手机免费观看 | 91在线视频免费播放 | 天天操狠狠操网站 | 国产中文字幕在线免费观看 | 日日夜夜精品免费 | 日韩在线播放视频 | 深爱激情av | 久久亚洲私人国产精品va | 精品在线视频一区二区三区 | 黄网在线免费观看 | 成人中文字幕在线 | 999国产在线 | 免费观看一区二区三区视频 | 中文字幕免费一区二区 | 欧美性生活一级片 | av免费高清观看 | 国产成人精品亚洲精品 | 久久国产精品99久久人人澡 | 久草免费资源 | 少妇按摩av| 人人草人| 五月天激情在线 | 国产剧情一区 | 国产亚洲精品无 | 天堂视频中文在线 | 久久看片 | 色人久久 | 十八岁以下禁止观看的1000个网站 | 色婷婷影视 | 粉嫩av一区二区三区四区 | 亚洲国产成人在线 | 天天草视频 | 国产精品免费久久久久久 | 草久在线视频 | 欧美精品免费在线观看 | 少妇精69xxtheporn | 婷婷六月综合网 | 一区二区三区免费在线观看 | 午夜精品久久久 | 日韩中文字幕免费 | 国产精品久久久久影视 | 蜜臀av性久久久久蜜臀av | 免费视频91蜜桃 | 99视频99 | 免费a级大片| 久久精品官网 | 国产精品欧美一区二区 | 天堂在线一区二区 | 久久一区精品 | 一区二区三区免费网站 | 日韩在线网址 | 中文字幕资源在线 | 99精品视频网站 | 国产又粗又猛又爽又黄的视频先 | 国产在线播放一区 | 99久久精品免费看国产免费软件 | 韩国中文三级 | 亚洲国产精品激情在线观看 | 91桃花视频| 久久大片网站 | 婷婷精品国产一区二区三区日韩 | 色婷婷亚洲婷婷 | 天天操网址 |