天天看點

第二十三章:觸發器和行為(二)觸發器

觸發器

在最普遍(和最模糊)的意義上,觸發器是導緻響應的條件。 更具體地說,觸發器通過設定另一個屬性或運作一些代碼來響應屬性更改或觸發事件。 幾乎總是,設定的屬性或運作的代碼涉及使用者界面,并在XAML中表示。

VisualElement和Style都定義了IList 類型的Triggers屬性。 抽象TriggerBase類派生自BindableObject。 四個密封類派生自TriggerBase:

  • Trigger設定屬性(或運作代碼)以響應屬性更改。
  • EventTrigger,用于運作代碼以響應事件。
  • DataTrigger,用于設定屬性(或運作代碼)以響應資料綁定中引用的屬性更改。
  • MultiTrigger用于在發生多個觸發器時設定屬性(或運作代碼)。

這些之間的差異将在實踐中變得更加清晰。

最簡單的觸發器

在其通常的形式中,Trigger類檢查元素的屬性更改,并通過設定同一進制素的另一個屬性來響應。

例如,假設您設計了一個包含多個Entry視圖的頁面。 您已經确定當特定條目獲得輸入焦點時,您希望條目變大。 您希望使條目脫穎而出,包括使用者鍵入的文本。

更具體地說,當Entry的IsFocused屬性變為True時,您希望Entry的Scale屬性設定為1.5。 當IsFocused屬性恢複為False時,您希望Scale屬性也恢複為其先前的值。

為了适應這個概念,Trigger定義了三個屬性:

  • BindableProperty類型的屬性。
  • 對象類型的值。
  • IList類型的setter。 這是Trigger的内容屬性。

必須設定所有這些屬性才能使觸發器起作用。 從TriggerBase,Trigger繼承了另一個基本屬性:

  • TargetType 類型為Type。

這是連接配接觸發器的元素的類型。

Trigger的Property和Value屬性有時被認為是一個條件。 當Property引用的屬性的值等于Value時,條件為true,并且Setter對象的集合将應用于該元素。

正如您将在第12章“樣式”中回憶的那樣,Setter定義了兩個與前兩個Trigger屬性相同的屬性:

  • Property 類型為BindableProperty。
  • Value類型為Object。

使用觸發器,我們隻處理可綁定屬性。 Trigger條件屬性必須由BindableProperty以及Setter設定的屬性支援。

當條件變為false時,Setter對象是“未應用的”,這意味着Setter引用的屬性将恢複為沒有Setter的值,這可能是屬性的預設值,直接設定的值 元素,或通過Style應用的值。

這是EntryPop程式的XAML檔案。 頁面上的三個Entry視圖中的每一個都使用Entry.Triggers屬性元素标記将一個Trigger對象添加到其Triggers集合中。 每個Trigger對象都有一個Setter添加到其Setters集合中。 因為Setters是Trigger的content屬性,是以不需要Trigger.Setters屬性元素标記:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="EntryPop.EntryPopPage"
             Padding="20, 50, 120, 0">
    <StackLayout Spacing="20">
        <Entry Placeholder="enter name"
                AnchorX="0">
            <Entry.Triggers>
                <Trigger TargetType="Entry" Property="IsFocused" Value="True">
                    <Setter Property="Scale" Value="1.5" />
                </Trigger>
            </Entry.Triggers>
        </Entry>
        <Entry Placeholder="enter address"
                AnchorX="0">
            <Entry.Triggers>
                <Trigger TargetType="Entry" Property="IsFocused" Value="True">
                    <Setter Property="Scale" Value="1.5" />
                </Trigger>
            </Entry.Triggers>
        </Entry>
        <Entry Placeholder="enter city and state"
                    AnchorX="0">
            <Entry.Triggers>
                <Trigger TargetType="Entry" Property="IsFocused" Value="True">
                    <Setter Property="Scale" Value="1.5" />
                </Trigger>
            </Entry.Triggers>
        </Entry>
    </StackLayout>
</ContentPage>           

每個Trigger對象必須設定其TargetType,在這種情況下,這是一個Entry。 在内部,Trigger使用PropertyChanged處理程式來監視IsFocused屬性的值。 當該屬性等于True時,單個Setter對象将Scale屬性設定為1.5。 AnchorX設定為零會訓示從Entry的左側進行縮放。 (AnchorX的非預設值表示如果更改iOS螢幕的方向,則無法正确定位Entry視圖。)

當Entry失去輸入焦點并且IsFocused屬性再次變為False時,Trigger會自動删除Setter的應用程式,在這種情況下,Scale屬性将恢複為

它的預觸發值,不一定是它的預設值。

以下是帶有輸入焦點的放大的Entry視圖:

第二十三章:觸發器和行為(二)觸發器

此示例中的每個Entry視圖隻有一個Trigger,每個Trigger隻有一個Setter,但在一般情況下,visual元素在其Triggers集合中可以有多個Trigger對象,每個Trigger在其Setters集合中可以有多個Setter對象。

如果要在代碼中執行類似的操作,則可以将PropertyChanged事件處理程式附加到每個Entry,并通過設定Scale屬性來響應IsFocused屬性中的更改。 觸發器的優點是你可以在定義元素的位置完成标記的整個工作,留下工作代碼可能比增加Entry元素的大小更重要!

是以,您不太可能需要在代碼中建立Trigger對象。 從來沒有,EntryPopCode程式示範了你是如何做到的。 代碼已被設計為盡可能類似于XAML:

public class EntryPopCodePage : ContentPage
{
    public EntryPopCodePage()
    {
        Padding = new Thickness(20, 50, 120, 0);
        Content = new StackLayout
        {
            Spacing = 20,
            Children = 
            {
                new Entry
                {
                    Placeholder = "enter name",
                    AnchorX = 0,
                    Triggers = 
                    {
                        new Trigger(typeof(Entry))
                        {
                            Property = Entry.IsFocusedProperty,
                            Value = true,
                            Setters = 
                            {
                                new Setter
                                {
                                    Property = Entry.ScaleProperty,
                                    Value = 1.5
                                }
                            }
                        }
                    }
                },
                new Entry
                {
                    Placeholder = "enter addresss",
                    AnchorX = 0,
                    Triggers = 
                    {
                        new Trigger(typeof(Entry))
                        {
                            Property = Entry.IsFocusedProperty,
                            Value = true,
                            Setters = 
                            {
                                new Setter
                                {
                                    Property = Entry.ScaleProperty,
                                    Value = 1.5
                                }
                            }
                        }
                    }
                },
                new Entry
                {
                    Placeholder = "enter city and state",
                    AnchorX = 0,
                    Triggers = 
                    {
                        new Trigger(typeof(Entry))
                        {
                            Property = Entry.IsFocusedProperty,
                            Value = true,
                            Setters = 
                            {
                                new Setter
                                {
                                    Property = Entry.ScaleProperty,
                                    Value = 1.5
                                }
                            }
                        }
                    }
                }
            }
        };
    }
}           

XAML和代碼之間唯一真正的差別是TargetType屬性的處理。 在XAML中,TargetType屬性在三個Trigger定義中的每一個中設定為“Entry”。 但是,在代碼中,必須将typeof(Entry)作為參數傳遞給Trigger構造函數。 如果檢視Trigger類的文檔,則會發現TargetType屬性是get-only。 XAML解析器使用TargetType屬性設定來執行個體化Trigger對象。

Style類還定義了IList 類型的Triggers屬性,這意味着您可以使用Style在多個元素之間共享Trigger對象。 StyledTriggers程式顯示了如何。 請注意,Style和Trigger标記都包含TargetType屬性設定。 Style包含一個Setter對象,并為單個Trigger對象使用Style.Triggers屬性 - 元素标記,該對象還包含Setter對象:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="StyledTriggers.StyledTriggersPage"
             Padding="20, 50, 120, 0">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Style TargetType="Entry">
                <Setter Property="AnchorX" Value="0" />
                <Style.Triggers>
                    <Trigger TargetType="Entry" Property="IsFocused" Value="True">
                        <Setter Property="Scale" Value="1.5" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>
    <StackLayout Spacing="20">
        <Entry Placeholder="enter name" />
        <Entry Placeholder="enter address" />
        <Entry Placeholder="enter city and state" />
    </StackLayout>
</ContentPage>           

由于Style沒有字典鍵,是以它是一種隐式樣式,可自動應用于Entry類型的所有元素。 單個Entry元素隻需包含每個元素的唯一進制素。

也許在嘗試使用EntryPop程式(或兩個變體)之後,您決定不希望Scale屬性簡單地“彈出”到值1.5。 你想要一個動畫。 您希望它在獲得輸入焦點時“膨脹”大小,并在失去輸入焦點時将其動畫恢複正常。

那也是可能的。

繼續閱讀