Xamarin.Forms 트리거Xamarin.Forms Triggers

샘플 다운로드 샘플 다운로드Download Sample Download the sample

트리거를 사용하면 XAML에서 이벤트 또는 속성 변경에 따라 컨트롤의 모양을 변경하는 작업을 선언적으로 표현할 수 있습니다.Triggers allow you to express actions declaratively in XAML that change the appearance of controls based on events or property changes.

트리거를 컨트롤에 직접 할당하거나 여러 컨트롤에 적용될 페이지 수준 또는 애플리케이션 수준 리소스 사전에 추가할 수 있습니다.You can assign a trigger directly to a control, or add it to a page-level or app-level resource dictionary to be applied to multiple controls.

트리거에는 다음 네 가지 유형이 있습니다.There are four types of trigger:

  • 속성 트리거 - 컨트롤의 속성이 특정 값으로 설정될 때 발생합니다.Property Trigger - occurs when a property on a control is set to a particular value.

  • 데이터 트리거 - 데이터 바인딩을 사용하여 다른 컨트롤의 속성을 기반으로 하여 트리거합니다.Data Trigger - uses data binding to trigger based on the properties of another control.

  • 이벤트 트리거 - 컨트롤에서 이벤트가 발생할 때 발생합니다.Event Trigger - occurs when an event occurs on the control.

  • 다중 트리거 - 작업이 발생하기 전에 여러 트리거 조건을 설정할 수 있도록 합니다.Multi Trigger - allows multiple trigger conditions to be set before an action occurs.

속성 트리거Property Triggers

간단한 트리거는 컨트롤의 트리거 컬렉션에 Trigger 요소를 추가하는 XAML에서만 표현할 수 있습니다.A simple trigger can be expressed purely in XAML, adding a Trigger element to a control's triggers collection. 다음 예제에서는 포커스를 받을 때 Entry 배경색을 변경하는 트리거를 보여 줍니다.This example shows a trigger that changes an Entry background color when it receives focus:

<Entry Placeholder="enter name">
    <Entry.Triggers>
        <Trigger TargetType="Entry"
             Property="IsFocused" Value="True">
            <Setter Property="BackgroundColor" Value="Yellow" />
        </Trigger>
    </Entry.Triggers>
</Entry>

트리거 선언에서 중요한 부분은 다음과 같습니다.The important parts of the trigger's declaration are:

  • TargetType - 트리거가 적용되는 컨트롤 형식입니다.TargetType - the control type that the trigger applies to.

  • Property - 모니터링되는 컨트롤의 속성입니다.Property - the property on the control that is monitored.

  • Value - 모니터링되는 속성에 대해 발생할 때 트리거가 활성화되는 값입니다.Value - the value, when it occurs for the monitored property, that causes the trigger to activate.

  • Setter - 트리거 조건이 충족될 때 Setter 요소의 컬렉션을 추가할 수 있습니다.Setter - a collection of Setter elements can be added and when the trigger condition is met. 설정할 PropertyValue를 지정합니다.You must specify the Property and Value to set.

  • EnterActions 및 ExitActions(표시되지 않음) - 코드로 작성되며 Setter 요소에 추가하여(또는 대신) 사용할 수 있습니다.EnterActions and ExitActions (not shown) - are written in code and can be used in addition to (or instead of) Setter elements. 이러한 모든 부분은 아래와 같이 설명됩니다.They are described below.

Style(스타일)을 사용하여 Trigger(트리거) 적용Applying a Trigger using a Style

트리거는 컨트롤, 페이지 또는 ResourceDictionary애플리케이션의 Style 선언에도 추가할 수 있습니다.Triggers can also be added to a Style declaration on a control, in a page, or an application ResourceDictionary. 다음 예제에서는 페이지의 모든 Entry 컨트롤에 적용된다고 나타내는 암시적 스타일(즉, Key가 설정되지 않음)을 선언합니다.This example declares an implicit style (ie. no Key is set) which means it will apply to all Entry controls on the page.

<ContentPage.Resources>
    <ResourceDictionary>
        <Style TargetType="Entry">
                        <Style.Triggers>
                <Trigger TargetType="Entry"
                         Property="IsFocused" Value="True">
                    <Setter Property="BackgroundColor" Value="Yellow" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </ResourceDictionary>
</ContentPage.Resources>

데이터 트리거Data Triggers

데이터 트리거는 다른 컨트롤을 모니터링하는 데이터 바인딩을 사용하여 Setter가 호출되도록 합니다.Data triggers use data binding to monitor another control to cause the Setters to get called. 속성 트리거의 Property 특성 대신 지정된 값을 모니터링하는 Binding 특성을 설정합니다.Instead of the Property attribute in a property trigger, set the Binding attribute to monitor for the specified value.

다음 예제에서는 다른 컨트롤의 속성을 참조하는 {Binding Source={x:Reference entry}, Path=Text.Length} 데이터 바인딩 구문을The example below uses the data binding syntax {Binding Source={x:Reference entry}, Path=Text.Length} 사용합니다.which is how we refer to another control's properties. entry의 길이가 0이면 트리거가 활성화됩니다.When the length of the entry is zero, the trigger is activated. 이 샘플에서 트리거는 입력이 비어 있을 때 단추를 비활성화합니다.In this sample the trigger disables the button when the input is empty.

<!-- the x:Name is referenced below in DataTrigger-->
<!-- tip: make sure to set the Text="" (or some other default) -->
<Entry x:Name="entry"
       Text=""
       Placeholder="required field" />

<Button x:Name="button" Text="Save"
        FontSize="Large"
        HorizontalOptions="Center">
    <Button.Triggers>
        <DataTrigger TargetType="Button"
                     Binding="{Binding Source={x:Reference entry},
                                       Path=Text.Length}"
                     Value="0">
            <Setter Property="IsEnabled" Value="False" />
        </DataTrigger>
    </Button.Triggers>
</Button>

Path=Text.Length를 평가할 때 항상 대상When evaluating Path=Text.Length always provide a default value for the target property (eg. 속성(예:Text="")에 기본값을 제공합니다. 그렇지 않으면 null이 되고 트리거가 예상대로 작동하지 않기 때문입니다.Text="") because otherwise it will be null and the trigger won't work like you expect.

Setter를 지정하는 것 외에도 EnterActionsExitActions도 제공할 수 있습니다.In addition to specifying Setters you can also provide EnterActions and ExitActions.

이벤트 트리거Event Triggers

EventTrigger 요소에는 아래 예제의 "Clicked"와 같이 Event 속성만 필요합니다.The EventTrigger element requires only an Event property, such as "Clicked" in the example below.

<EventTrigger Event="Clicked">
    <local:NumericValidationTriggerAction />
</EventTrigger>

Setter 요소는 없고 오히려 local:NumericValidationTriggerAction에서 정의된 클래스에 대한 참조가 있음에 유의하세요. 이 클래스는 페이지의 XAML에서 xmlns:local을 선언해야 합니다.Notice that there are no Setter elements but rather a reference to a class defined by local:NumericValidationTriggerAction which requires the xmlns:local to be declared in the page's XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:WorkingWithTriggers;assembly=WorkingWithTriggers"

클래스 자체는 TriggerAction을 구현합니다. 즉 트리거 이벤트가 발생할 때마다 호출되는 Invoke 메서드에 대한 재정의를 제공해야 합니다.The class itself implements TriggerAction which means it should provide an override for the Invoke method that is called whenever the trigger event occurs.

트리거 작업 구현에서 수행해야 하는 작업은 다음과 같습니다.A trigger action implementation should:

  • 트리거가 적용될 컨트롤 형식에 해당하는 제네릭 매개 변수를 사용하여 제네릭 TriggerAction<T> 클래스를 구현합니다.Implement the generic TriggerAction<T> class, with the generic parameter corresponding with the type of control the trigger will be applied to. VisualElement와 같은 수퍼클래스를 사용하여 다양한 컨트롤에서 작동하는 트리거 작업을 작성하거나 Entry와 같은 컨트롤 형식을 지정할 수 있습니다.You can use superclasses such as VisualElement to write trigger actions that work with a variety of controls, or specify a control type like Entry.

  • 트리거 조건이 충족될 때마다 호출되는 Invoke 메서드를 재정의합니다.Override the Invoke method - this is called whenever the trigger criteria are met.

  • 필요에 따라 트리거를 선언할 때 XAML에서 설정할 수 있는 속성을 공개합니다.Optionally expose properties that can be set in the XAML when the trigger is declared. 이에 대한 예제는 함께 제공되는 애플리케이션 예제의 VisualElementPopTriggerAction 클래스를 참조하세요.For an example of this, see the VisualElementPopTriggerAction class in the accompanying sample application.

public class NumericValidationTriggerAction : TriggerAction<Entry>
{
    protected override void Invoke (Entry entry)
    {
        double result;
        bool isValid = Double.TryParse (entry.Text, out result);
        entry.TextColor = isValid ? Color.Default : Color.Red;
    }
}

그런 다음 XAML에서 이벤트 트리거를 사용할 수 있습니다.The event trigger can then be consumed from XAML:

<EventTrigger Event="TextChanged">
    <local:NumericValidationTriggerAction />
</EventTrigger>

ResourceDictionary에서 트리거를 공유할 때 주의하세요. 하나의 인스턴스가 컨트롤 간에 공유되므로 한 번 구성된 상태가 모든 컨트롤에 적용됩니다.Be careful when sharing triggers in a ResourceDictionary, one instance will be shared among controls so any state that is configured once will apply to them all.

이벤트 트리거는 아래에서 설명하는 EnterActionsExitActions를 지원하지 않습니다.Note that event triggers do not support EnterActions and ExitActions described below.

다중 트리거Multi Triggers

MultiTrigger는 둘 이상의 조건이 있을 수 있다는 점을 제외하고는 Trigger 또는 DataTrigger와 비슷합니다.A MultiTrigger looks similar to a Trigger or DataTrigger except there can be more than one condition. Setter가 트리거되기 전에 모든 조건이 true여야 합니다.All the conditions must be true before the Setters are triggered.

두 개의 서로 다른 입력(emailphone)에 바인딩되는 단추 트리거의 예제는 다음과 같습니다.Here's an example of a trigger for a button that binds to two different inputs (email and phone):

<MultiTrigger TargetType="Button">
    <MultiTrigger.Conditions>
        <BindingCondition Binding="{Binding Source={x:Reference email},
                                   Path=Text.Length}"
                               Value="0" />
        <BindingCondition Binding="{Binding Source={x:Reference phone},
                                   Path=Text.Length}"
                               Value="0" />
    </MultiTrigger.Conditions>

  <Setter Property="IsEnabled" Value="False" />
    <!-- multiple Setter elements are allowed -->
</MultiTrigger>

Conditions 컬렉션에도 다음과 같은 PropertyCondition 요소가 포함될 수 있습니다.The Conditions collection could also contain PropertyCondition elements like this:

<PropertyCondition Property="Text" Value="OK" />

"모두가 필수인" 다중 트리거 작성Building a "require all" multi trigger

모든 조건이 true인 경우에만 다중 트리거에서 컨트롤을 업데이트합니다.The multi trigger only updates its control when all conditions are true. "영(0)보다 큰 Text.Length" 조건이 필요하지만 XAML에서는 표시할 수 없으므로 "모든 필드의 길이가 영(0)임"(예: 모든 입력이 완료되어야 하는 로그인 페이지)에 대한 테스트는 까다롭습니다.Testing for "all field lengths are zero" (such as a login page where all inputs must be complete) is tricky because you want a condition "where Text.Length > 0" but this can't be expressed in XAML.

이 작업은 IValueConverter를 사용하여 수행할 수 있습니다.This can be done with an IValueConverter. 아래의 변환기 코드는 Text.Length 바인딩을 필드가 비어 있는지 여부를 나타내는 bool로 변환합니다.The converter code below transforms the Text.Length binding into a bool that indicates whether a field is empty or not:

public class MultiTriggerConverter : IValueConverter
{
    public object Convert(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        if ((int)value > 0) // length > 0 ?
            return true;            // some data has been entered
        else
            return false;            // input is empty
    }

    public object ConvertBack(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        throw new NotSupportedException ();
    }
}

다중 트리거에서 이 변환기를 사용하려면 먼저 사용자 지정 xmlns:local 네임스페이스 정의와 함께 해당 변환기를 페이지의 리소스 사전에 추가합니다.To use this converter in a multi trigger, first add it to the page's resource dictionary (along with a custom xmlns:local namespace definition):

<ResourceDictionary>
   <local:MultiTriggerConverter x:Key="dataHasBeenEntered" />
</ResourceDictionary>

XAML은 아래와 같습니다.The XAML is shown below. 첫 번째 다중 트리거 예제와의 차이점은 다음과 같습니다.Note the following differences from the first multi trigger example:

  • 단추는 기본적으로 IsEnabled="false"로 설정되어 있습니다.The button has IsEnabled="false" set by default.
  • 다중 트리거 조건은 변환기를 사용하여 Text.Length 값을 boolean으로 변환합니다.The multi trigger conditions use the converter to turn the Text.Length value into a boolean.
  • 모든 조건이 true이면 setter에서 단추의 IsEnabled 속성을 true로 설정합니다.When all the conditions are true, the setter makes the button's IsEnabled property true.
<Entry x:Name="user" Text="" Placeholder="user name" />

<Entry x:Name="pwd" Text="" Placeholder="password" />

<Button x:Name="loginButton" Text="Login"
        FontSize="Large"
        HorizontalOptions="Center"
        IsEnabled="false">
  <Button.Triggers>
    <MultiTrigger TargetType="Button">
      <MultiTrigger.Conditions>
        <BindingCondition Binding="{Binding Source={x:Reference user},
                              Path=Text.Length,
                              Converter={StaticResource dataHasBeenEntered}}"
                          Value="true" />
        <BindingCondition Binding="{Binding Source={x:Reference pwd},
                              Path=Text.Length,
                              Converter={StaticResource dataHasBeenEntered}}"
                          Value="true" />
      </MultiTrigger.Conditions>
      <Setter Property="IsEnabled" Value="True" />
    </MultiTrigger>
  </Button.Triggers>
</Button>

다음 스크린샷에서는 위의 두 가지 다중 트리거 예제 사이의 차이점을 보여 줍니다.These screenshots show the difference between the two multi trigger examples above. 화면의 위쪽에서는 Entry의 텍스트 입력만으로 저장 단추를 사용할 수 있습니다.In the top part of the screens, text input in just one Entry is enough to enable the Save button. 화면의 아래쪽에서는 두 필드 모두에 데이터가 포함될 때까지 로그인 단추가 비활성 상태로 유지됩니다.In the bottom part of the screens, the Login button remains inactive until both fields contain data.

EnterActions 및 ExitActionsEnterActions and ExitActions

트리거가 발생할 때 변경 내용을 구현하는 또 다른 방법은 EnterActionsExitActions 컬렉션을 추가하고 TriggerAction<T> 구현을 지정하는 것입니다.Another way to implement changes when a trigger occurs is by adding EnterActions and ExitActions collections and specifying TriggerAction<T> implementations.

EnterActions 컬렉션은 트리거 조건이 충족될 때 호출되는 TriggerAction 개체의 IList를 정의하는 데 사용됩니다.The EnterActions collection is used to define an IList of TriggerAction objects that will be invoked when the trigger condition is met. ExitActions 컬렉션은 트리거 조건이 더 이상 충족되지 않을 때 호출되는 TriggerAction 개체의 IList를 정의하는 데 사용됩니다.The ExitActions collection is used to define an IList of TriggerAction objects that will be invoked after the trigger condition is no longer met.

참고

EnterActionsExitActions 컬렉션에 정의된 TriggerAction 개체는 EventTrigger 클래스에 의해 무시됩니다.The TriggerAction objects defined in the EnterActions and ExitActions collections are ignored by the EventTrigger class.

트리거에서 Setter뿐만 아니라 EnterActionsExitActions모두 제공할 수 있지만, Setter가 즉시 호출된다는 점에 주의하세요(EnterAction 또는 ExitAction이 완료될 때까지 기다리지 않음).You can provide both EnterActions and ExitActions as well as Setters in a trigger, but be aware that the Setters are called immediately (they do not wait for the EnterAction or ExitAction to complete). 또는 코드에 있는 모든 작업을 수행할 수 있으며 Setter는 전혀 사용하지 않습니다.Alternatively you can perform everything in the code and not use Setters at all.

<Entry Placeholder="enter job title">
    <Entry.Triggers>
        <Trigger TargetType="Entry"
                 Property="Entry.IsFocused" Value="True">
            <Trigger.EnterActions>
                <local:FadeTriggerAction StartsFrom="0"" />
            </Trigger.EnterActions>

            <Trigger.ExitActions>
                <local:FadeTriggerAction StartsFrom="1" />
            </Trigger.ExitActions>
            <!-- You can use both Enter/Exit and Setter together if required -->
        </Trigger>
    </Entry.Triggers>
</Entry>

항상 그렇듯이 XAML에서 클래스가 참조되는 경우 다음과 같이 xmlns:local과 같은 네임스페이스를 선언해야 합니다.As always, when a class is referenced in XAML you should declare a namespace such as xmlns:local as shown here:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:WorkingWithTriggers;assembly=WorkingWithTriggers"

FadeTriggerAction 코드는 아래와 같습니다.The FadeTriggerAction code is shown below:

public class FadeTriggerAction : TriggerAction<VisualElement>
{
    public FadeTriggerAction() {}

    public int StartsFrom { set; get; }

    protected override void Invoke (VisualElement visual)
    {
            visual.Animate("", new Animation( (d)=>{
                var val = StartsFrom==1 ? d : 1-d;
                visual.BackgroundColor = Color.FromRgb(1, val, 1);

            }),
            length:1000, // milliseconds
            easing: Easing.Linear);
    }
}