WPF EventTrigger 질문드립니다.

안녕하세요. 입력박스가 비어있거나 디폴트 값이면 버튼이 좌우로 움직이는 기능을 구현하려고 합니다.

1212121

xaml 에서 버튼 이벤트 발생시 해당 텍스트 박스의 값을 체크하면 될 것은데 EventTrigger내에서 다른

컨트롤의 상태를 가져올 수는 없는건가요?? 이 기능은 비하인드코드에서 적용을 해야만 하는건지

도움부탁드립니다.



<Button x:Name="button2" Content="IndividualPrint" HorizontalAlignment="Left" Height="55" Margin="1036,558,0,0" VerticalAlignment="Top" Width="250" FontFamily="Arial Rounded MT Bold" FontSize="24" Background="#7FFF9771" Click="onePrintButton_Click">
     <Button.Style>
         <Style TargetType="{x:Type Button}">
             <Setter Property="Template">
                 <Setter.Value>
                     <ControlTemplate TargetType="{x:Type Button}">
                         <Border Background="{TemplateBinding Background}" BorderBrush="SkyBlue" BorderThickness="0.5" CornerRadius="5,5,5,5">
                             <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                         </Border>
                     </ControlTemplate>
                 </Setter.Value>
             </Setter>
             <Style.Triggers>
                 <EventTrigger RoutedEvent="Click">
                      <!-- 
                        이곳에 왼쪽텍스트(textBox1) 값을 참고해서 아래 애니메이션 효과가 일어나도록 조건을 
                         추가했으면 합니다. 
                          -->
                     <EventTrigger.Actions>
                         <BeginStoryboard>
                             <Storyboard>
                                 <StaticResource ResourceKey="dataError"/>
                             </Storyboard>
                         </BeginStoryboard>
                     </EventTrigger.Actions>
                 </EventTrigger>

기본적으로 EventTrigger에서는 로지컬 처리가 불가능 합니다.

대신 DataTrigger로 대체 하여 처리 가능합니다.

다음은 간단한 샘플의 코드 입니다.
[xaml]

<Window.Resources>
    <Storyboard x:Key="BtnStartShake">
        <DoubleAnimationUsingKeyFrames RepeatBehavior="Forever"
                                       Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)">
            <EasingDoubleKeyFrame KeyTime="0:0:0"
                                  Value="0" />
            <EasingDoubleKeyFrame KeyTime="0:0:0.1"
                                  Value="-5" />
            <EasingDoubleKeyFrame KeyTime="0:0:0.2"
                                  Value="5" />
            <EasingDoubleKeyFrame KeyTime="0:0:0.3"
                                  Value="-5" />
            <EasingDoubleKeyFrame KeyTime="0:0:0.4"
                                  Value="5" />
            <EasingDoubleKeyFrame KeyTime="0:0:0.5"
                                  Value="0" />
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
    <Storyboard x:Key="BtnEndShake">
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)">
            <EasingDoubleKeyFrame KeyTime="0:0:0"
                          Value="0" />
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</Window.Resources>
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>

    <TextBox x:Name="xInputTextBox"
             Grid.Column="0"
             Height="35"
             Text="텍스트를 입력하세요!"
             Margin="10"/>
    <Button Grid.Column="1"
            Height="35"
            Width="100"
            Content="Click"
            Margin="10">
        <Button.RenderTransform>
            <TranslateTransform/>
        </Button.RenderTransform>
        <Button.Style>
            <Style TargetType="Button">
                <Style.Triggers>
                    <!--텍스트 박스가 기본 문구 이거나-->
                    <DataTrigger Binding="{Binding ElementName=xInputTextBox, Path=Text, UpdateSourceTrigger=PropertyChanged}"
                                 Value="텍스트를 입력하세요!">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard Storyboard="{StaticResource BtnStartShake}" />
                        </DataTrigger.EnterActions>
                        <DataTrigger.ExitActions>
                            <BeginStoryboard Storyboard="{StaticResource BtnEndShake}" />
                        </DataTrigger.ExitActions>
                    </DataTrigger>

                    <!--텍스트 박스가 비어 있거나-->
                    <DataTrigger Binding="{Binding ElementName=xInputTextBox, Path=Text, UpdateSourceTrigger=PropertyChanged}"
                                 Value="">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard Storyboard="{StaticResource BtnStartShake}" />
                        </DataTrigger.EnterActions>
                        <DataTrigger.ExitActions>
                            <BeginStoryboard Storyboard="{StaticResource BtnEndShake}" />
                        </DataTrigger.ExitActions>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
    </Button>
</Grid>

텍스트 박스의 Text 속성 값 기준으로
텍스트 박스에 값이 비 어 있거나,
텍스트 박스에 값이 기본 문구 라면,

버튼이 좌.우로 흔들리도록 처리 된 예제 입니다.

버튼_쉐이크


다만, 위 예는 버튼 클릭시 동작이 아닌 텍스트 박스의 값이 변경 될때 트리거가 발생 합니다.

작성하신 이 조건과도 같이 부합 되어야 한다면
버튼에 Command를 처리해서 텍스트 박스의 값을 체크하여
원하는 조건인지 판단하는 flag 속성을 바인딩 해서 처리 하셔야 합니다.

위 예시 코드에서 ElementName=xInputTextBox 부분을
조건 판단 유무의 flag속성으로 바인딩을 대체 하면 될 것 같습니다.

감사합니다. 알려주신 힌트로 클릭이벤트 TESt를 해보았습니다.

근데 이게 DataTrigger 이용시 기존값을 저장하고 있나요??

아래 코드의 CheckData 가 최초 실행시 True , 버튼을 클릭하면 False로 변경되어 정상적으로 버튼이

흔들리는데 이상태에서 재차 버튼을 클릭하면 DataTrigger에서는 값 변경이 없어서 인지 반응을 하지

않습니다. 그래서 차선책으로 일단 False로 변경 후 다시 True로 변경하는 로직을 비하인드에

넣어두면 정삭적으로 여러번 버튼을 클릭해도 버튼이 흔들립니다.

DataTrigger 부분에 뭔가 이전의 바인딩 값을 저장하고 있어서 바뀐 값이 동일하면 트리거가 작동을

안하는 느낌인데, 원래 그런가요??

<XAML>
<DataTrigger Binding="{Binding CheckData}" Value="False">
    
    <DataTrigger.EnterActions>
        <BeginStoryboard>
            <Storyboard>
                <StaticResource ResourceKey="dataError"/>
            </Storyboard>
        </BeginStoryboard>
    </DataTrigger.EnterActions>
 public Boolean CheckData 
 {
     get { return checkDataP; }
     set { checkDataP = value; OnPropertyChanged("CheckData");
         //MessageBox.Show(value.ToString());
     }
 }

 public void oneprintLabel() 
 {

     if (string.IsNullOrEmpty(printTxtP) 
         || printTxtP.Equals("출력하고자 하는 바코드를 텍스트로 입력하세요."))
     {         
         CheckData = false;
     }
     else 
     {
         //생략 
     }
      //OnpropertyChaged는 계속 발생되나 
      //DataTrigger가 동일한 값을 인지하지 못해 True로 변경, 뭔가 이상함
     //false -> false : Trigger 작동 X , false -> true -> false : Trigger 작동
     CheckData = true; 
  
 }

재현할 수 있는 간단한 전체 샘플 소스코드가 있으면 좋을 것 같습니다!

이전의 바인딩 값을 저장하고 있는게 아니고

CheckData 속성이 최초 초기값 true에서 → false로 바뀌었을때

트리거가 발동 되면서 스토리보드가 작동 되는 것 입니다.

스토리보드가 끝났다고 다시 CheckData 속성 값이 초기화 되진 않죠

여전히 계속 true이기에 한번 스토리보드는 작동 되었기에 다시 재생 하진 않습니다.


그냥 작성 하신 것 처럼 그냥 다시 true로 설정 하셔도 딱히 이상할건 없습니다.


저 방식이 마음에 안드신다 하면…
비해이비어를 별도로 구성하셔서 버튼 클릭시 조건을 체크해서 스토리보드를 작동해도 됩니다.

다음은 대충 비해이비어를 구현해 보았습니다.

public class WhenStoryboardBehavior : Behavior<ButtonBase>
{
    private const string Default_InputText = "텍스트를 입력하세요!";

    protected override void OnAttached()
    {
        AssociatedObject.Click += (_, __) =>
        {
            if (Storyboard is not null)
            {
                if (string.IsNullOrWhiteSpace(InputText) ||
                    InputText is Default_InputText)
                {
                    AssociatedObject.BeginStoryboard(Storyboard);
                }
            }
        };
    }

    public static readonly DependencyProperty InputTextProperty =
        DependencyProperty.Register("InputText",
            typeof(string),
            typeof(WhenStoryboardBehavior));

    public string? InputText
    {
        get { return base.GetValue(InputTextProperty) as string; }
        set { base.SetValue(InputTextProperty, value); }
    }

    public static readonly DependencyProperty StoryboardProperty =
        DependencyProperty.Register("Storyboard",
            typeof(Storyboard),
            typeof(WhenStoryboardBehavior));

    public Storyboard? Storyboard
    {
        get { return base.GetValue(StoryboardProperty) as Storyboard; }
        set { base.SetValue(StoryboardProperty, value); }
    }

}
<TextBox x:Name="xInputTextBox"
         Grid.Column="0"
         Height="35"
         Text="{Binding InputText, UpdateSourceTrigger=PropertyChanged}"
         Margin="10"/>
<Button Grid.Column="1"
        Height="35"
        Width="100"
        Content="Click"
        Command="{Binding ClickCommand}"
        Margin="10">
    <Button.RenderTransform>
        <TranslateTransform/>
    </Button.RenderTransform>

    <bi:Interaction.Behaviors>
        <local:WhenStoryboardBehavior InputText="{Binding InputText}"
                                      Storyboard="{StaticResource BtnStartShake}"/>
    </bi:Interaction.Behaviors>
</Button>

아니고 맘에 안들다니요;; 너무 감사하죠~^^;; 다만 제가 아직 초보이다 보니 알려주신 방법으로 구현을 하던중 생각했던 동작이 나오질 않아 이유가 궁금해서 추가질문을 드렸던 겁니다~~^^ 다른 구현방법까지 알려주시고 너무 감사합니다~!

우선 궁금한게 텍스트가 변경 되었을때 버튼이 움직이는 건지
아니면 버튼 클릭 했을때 버튼이 움직이는 건지가 내용으로는 판단이 안되네요.

일반적으로 잘못된 값을 넣는 중간에는 특별히 에러 표시를 안하고
액션( 엔터나 버튼 클릭 ) 했을때
에러를 노티 하는 방식을 많이 쓰는 걸로 알고 있습니다.

텍스트가 변경 되었을때는
위에서 말씀해 주신 거처럼 데이터트리거로 처리 하는게 맞고
액션 했을때는 이벤트 트리거로 해주시면 될거 같습니다.

안녕하세요. 원 질문이 버튼 클릭 이벤트 트리거에서 해당 조건을 확인해서 버튼이 흔들리는 걸 문의드렸습니다. 버튼이 흔들리는것 까지는 구현했었는데 해당 버튼의 이벤트 트리거에서 textBox의 Text를 어찌가져올 수가 있는지가 핵심 질문내용이었습니다.
aroooong 님께서 eventTrigger에서는 로지컬 처리가 불가하다고 하여 바인딩으로 처리했습니다~!