반응형
Popup에서 StaysOpen을 False로 두면 해당 팝업 컨트롤에서 포커스를 잃으면 알아서 닫힌다. 근데 포커스를 잃을려면 마우스를 누르거나 다양한 방법으로 상호작용을 해야하는데 이것마저 해서는 안되는 경우가 종종있다.
나의 경우는 그냥 팝업 화면에서 마우스만 빠져나가도 팝업이 닫게 하고 싶었다. Behind Code로 작성하면 편하겠지만 MVVM 패턴으론 쉽게하기 어려우니 Behavior를 쓰기로 했다.
일단 Behavior Class를 만들어준다.
class ClosePopupBehavior : Behavior<Popup>
{
protected override void OnAttached()
{
AssociatedObject.Child.MouseLeave += Child_MouseLeave;
}
private void Child_MouseLeave(object sender, MouseEventArgs e)
{
AssociatedObject.IsOpen = false;
}
protected override void OnDetaching()
{
AssociatedObject.Child.MouseLeave -= Child_MouseLeave;
}
}
보면 Behavior의 제너릭 타입에 Popup을 넣어준 것을 확인할 수 있다.
이것은 Popup 클래스 정의에 가보면 아래와 같이 Child를 쓸 수 있기 때문이다.
[System.Windows.Localizability(System.Windows.LocalizationCategory.None)]
[System.Windows.Markup.ContentProperty("Child")]
public class Popup : System.Windows.FrameworkElement, System.Windows.Markup.IAddChild
그래서 상위단인 FrameworkElement 대신에 Popup을 가져다가 쓰고, Child 컨트롤에서 MouseLeave Event에 물려서 Popup을 닫도록 해준다.
이제 xaml 에 아래와 같이 선언해준다.
Interaction을 쓰기 위에선 맨 위에 이걸 선언해주자.
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
<Popup IsOpen="{Binding PopupOpen}"
StaysOpen="False"
VerticalOffset="-30"
HorizontalOffset="-20"
Placement="Mouse">
<Button Width="100"
Content="Delete"/>
<i:Interaction.Behaviors>
<b:ClosePopupBehavior />
</i:Interaction.Behaviors>
</Popup>
여기서 중요한점은 Behaviors를 Button 보다 위에 해놓으면 안된다. 그러면 Child가 할당되기전에 Child에 접근하여 이벤트 등록을 해줘버리기때문에 Null 오류가 뜬다.
보면 offset값을 일부러 마이너스값을 줘서 팝업이 생기자마자 마우스 위치 아래에 버튼이 들어가도록 처리해줬고, 이제 마우스가 버튼을 벗어나면 Behavior가 동작되어 해당 팝업을 닫게된다.
반응형
'프로그래밍 > WPF' 카테고리의 다른 글
[WPF] Converter를 이용한 Binding Image Source (0) | 2023.03.23 |
---|---|
[오류해결] Brush - DependencyObject와 같은 스레드에서 DependencySource를 만들어야 합니다. (0) | 2022.12.21 |
[WPF] Binding SelectedItems (ItemsControl, DataGrid 등) (0) | 2022.12.07 |
[WPF] File Drag & Drop MVVM Pattern using Behavior (0) | 2022.12.07 |
[WPF] Return StaticResource as IValueConverter (0) | 2022.12.02 |