Popup 안에 있는 Button으로 Popup 닫기

<TabControl>
    <TabItem>
        <Grid>
            <ListView>
                <ItemTemplate>
                    <Button> <!--버튼1-->
    <Popup>
        <Button> <!--버튼2-->

저는 현재 DataContext를 사용할 수 없는 조건에서 개발하고 있습니다.

바인딩 처리를 할 수 있었으면 이 질문은 매우 쉽기 때문에 질문을 안 드렸겠지만…

혹시 대충 위와 같은 구조에서

XAML만 사용해서 버튼2로 Popup을 닫을 수 있을까요? (이벤트 트리거만 이용한다던지…)

이런 것도 봤는데, 제 구조는 ListView 안에 있는 Button이라서 ElementName을 참조할 수 없어서 맞지 않는 솔루션이었습니다…

좋아요 2

일단은 이걸 보고 진행하고 있습니다.

좋아요 2

DataContext를 쓰지 않으시면 Button의 Click 이벤트에서 Popup을 처리하면 되는 것 같은데 다른 이슈가 있는걸까요?

좋아요 2

아 xaml 로만 이었네요…
이벤트 트리거를 사용하면 될 것 같아요.
뭔가 로직이 필요하면 triggeraction이나 behavior를 쓰셔도 될 것 같고요~

<Button Content="Button!">
    <Button.Triggers>
        <EventTrigger RoutedEvent="Click">
            <Setter TargetName="popUp" Property="IsOpen" Value="False" />
        </EventTrigger>
    </Button.Trigger>
</Button>

실제로 해보니 EventTrigger에서 Setter 설정이 되지 않아 storyboard로 해야 될 것 같아요.

<Popup Placement="Absolute" Width="100" Height="100" x:Name="popUp" IsOpen="True">
    <Button Content="Button!">
        <Button.Triggers>
            <EventTrigger RoutedEvent="Button.Click">
                <BeginStoryboard>
                    <Storyboard>
                        <BooleanAnimationUsingKeyFrames
                            Storyboard.TargetName="popUp"
                            Storyboard.TargetProperty="(Popup.IsOpen)">
                            <DiscreteBooleanKeyFrame
                                KeyTime="00:00:00"
                                Value="False" />
                        </BooleanAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Button.Triggers>
    </Button>
</Popup>
좋아요 3

@nyjin 님의 답변 xaml 코드는 의사 코드로 간결하게 알려주신 것 같아서 별도로 답변 드립니다.

이벤트 트리거로 특정 속성 값을 변경하려면 스토리보드를 사용해야 합니다.

<Popup x:Name="xPopup">
            <Button Content="닫기">
                <Button.Triggers>
                    <EventTrigger RoutedEvent="Button.Click">
                        <BeginStoryboard>
                            <Storyboard TargetProperty="IsOpen">
                                <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsOpen"
                                                                Storyboard.TargetName="xPopup">
                                    <DiscreteBooleanKeyFrame KeyTime="0:0:0"
                                                             Value="False" />
                                </BooleanAnimationUsingKeyFrames>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                </Button.Triggers>
</Button>
좋아요 4

엇 테스트하고 있는 와중에 해결해주셨네요~

좋아요 2

요걸로 해서 해결했습니다.

말씀해주신 @aroooong @nyjin 두 분 코드가 링크된 스택오버플로우 방법과 매우 유사하네요!

“(Popup.IsOpen)” 이런 문법은 처음봤네요…

답변 주신 두 분 매우 감사드립니다!! (나이스 한글 레퍼런스)

좋아요 2

(Popup.IsOpen) 표현식은

계층적인 비주얼트리 구조에서 해당 속성을 찾아서 타고 들어가야 할때

저렇게 괄호로 묶고 . <-쩜 기준으로 뎁스를 표현해서 속성을 접근할 수 있습니다.

(UIElement.RenderTransform).(ScaleTransform.ScaleY)

형식 처럼.,

좋아요 3

와우…부가적인 설명 매우 감사드립니다…!

좋아요 1

코드로 처리하면 쉽게 될 것 같은데… XAML로만 처리하려는 이유를 알 수 있을까요?

좋아요 2

사실 저도
저런 처리는 뷰의 cs 코드비하인드나

IsOpen을 바인딩 처리해서 뷰모델에서 처리하는게 더 좋다고 생각합니다.

그래야 남이 보았을때 바로 해석이 가능하고 또 그것이 맞다고 생각합니다. ㅎ

좋아요 3

현재 회사에서 WPF를 하지만 MVVM으로 하지 않고 Binding으로 처리하는 게 거의 없고, 대부분의 컨트롤 생성과 Style을 Code Behind에서 하고 있습니다…

Code Behind에서 ItemsControl 상속 컨트롤들의 ItemsSource를 할당해서 사용하고 있기 때문에 ItemsControl을 상속하는 컨트롤들은 제가 SelectedItem들과 Binding 처리 해놓은 상태 정도만 겨우 쓰고 있습니다.

제가 들어와서 Code Behind를 안쓰고 XAML 의존적으로 하려고 많이 하고 있고 물어보니까 언젠가는 MVVM을 할 생각이라고 하셔서 최대한 XAML 의존적으로 해두려고 합니다.

좋아요 1

그렇군요. 하지만 XAML 코드도 마찬가지로 XAML의 부분 집합이니 이걸 칼 자르듯이 생각할 필요는 없다고 말씀 드리고 싶네요.

되려 반대로 XAML 코드에 화면과 상관없는 코드를 제거하는 방향성이 좋지 않을까… 의견 드려봅니다.

좋아요 3

나중에 뷰모델을 사용가능하게 되어 observableproperty에 의한 바인딩이 가능해지면 바인딩 방식으로 바꾸려고 합니다.

좋아요 3

behavior를 사용한 예시 입니다.

WPF에서 behavior를 사용하려면 Microsoft.Xaml.Behaviors.Wpf 패키지를 설치해야 합니다.

ChangePropertyAction을 사용할 수 있고 다음은 XAML 코드 입니다.

<Window
    x:Class="WpfPopupToggleUsingXAML.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
    xmlns:local="clr-namespace:WpfPopupToggleUsingXAML"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="800"
    Height="450"
    mc:Ignorable="d">
    <Grid>
        <TabControl>
            <TabItem Header="Tab1">
                <Button Content="Button!">
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="Click">
                            <i:ChangePropertyAction
                                PropertyName="IsOpen"
                                TargetName="popUp"
                                Value="True" />
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                </Button>
            </TabItem>
        </TabControl>

        <Popup
            x:Name="popUp"
            Width="100"
            Height="100"
            IsOpen="False"
            Placement="MousePoint">
            <Button Content="Close!">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <i:ChangePropertyAction
                            PropertyName="IsOpen"
                            TargetName="popUp"
                            Value="False" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>

        </Popup>
    </Grid>
</Window>

image

좋아요 5

말끔하네요~! 코드 비하인드를 쓰지 않아도 되는 상황이라면, xaml의 연결로 선언적인 처리가 가능해 간결하게 구성될 수 있을 것 같네요~

좋아요 3

아 맞다…바보가 된 느낌이네요 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ…
원래 한창 MVVM 하면서 dxmvvm쓸땐 behavior 매우 잘 가져다 썼었는데
그러다가 순정 MVVM을 까먹었나 봅니다…ㅎㅎ
이렇게 바꿔야겠네요! (이건 써도 되나 모르겠지만…)

기억을 다시 꺼내와주셔서 감사드립니다!

좋아요 2