XAML 태그 만 사용하여 다른 컨트롤을 클릭 할 때 WPF 팝업을 여는 방법은 무엇입니까?
두 개의 컨트롤, TextBlock과 PopUp이 있습니다. 사용자가 텍스트 블록에서 (MouseDown)을 클릭하면 팝업을 표시하고 싶습니다. Popup에서 EventTrigger를 사용하여이 작업을 수행 할 수 있다고 생각하지만 EventTrigger에서 setter를 사용할 수 없으며 스토리 보드 만 시작할 수 있습니다. 두 컨트롤이 템플릿에 있고 코드에서 팝업을 찾는 방법을 모르기 때문에이 작업을 XAML에서 엄격하게 수행하고 싶습니다.
이것은 개념적으로 내가하고 싶은 일이지만 EventTrigger에 setter를 넣을 수 없기 때문에 할 수 없습니다 (DataTrigger로 할 수있는 것처럼).
<TextBlock x:Name="CCD">Some text</TextBlock>
<Popup>
<Popup.Style>
<Style>
<Style.Triggers>
<EventTrigger SourceName="CCD" RoutedEvent="MouseDown">
<Setter Property="Popup.IsOpen" Value="True" />
</EventTrigger>
</Style.Triggers>
</Style>
</Popup.Style>
...
이벤트가 다른 컨트롤에서 발생할 때 XAML에서 팝업을 엄격하게 표시하는 가장 좋은 방법은 무엇입니까?
나는 간단한 일을했지만 작동합니다.
컨트롤 템플릿을 변경하여 텍스트 블록으로 스타일을 변경 한 전형적인 ToggleButton을 사용했습니다. 그런 다음 ToggleButton의 IsChecked 속성을 팝업의 IsOpen 속성에 바인딩했습니다. Popup에는 닫기 동작을 수정할 수있는 StaysOpen과 같은 몇 가지 속성이 있습니다.
다음은 XamlPad에서 작동합니다.
<StackPanel>
<ToggleButton Name="button">
<ToggleButton.Template>
<ControlTemplate TargetType="ToggleButton">
<TextBlock>Click Me Here!!</TextBlock>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
<Popup IsOpen="{Binding IsChecked, ElementName=button}" StaysOpen="False">
<Border Background="LightYellow">
<TextBlock>I'm the popup</TextBlock>
</Border>
</Popup>
</StackPanel>
다음 접근 방식은 Helge Klein과 동일하지만 팝업 외부의 아무 곳이나 클릭하면 팝업이 자동으로 닫힙니다 (ToggleButton 자체 포함).
<ToggleButton x:Name="Btn" IsHitTestVisible="{Binding ElementName=Popup, Path=IsOpen, Mode=OneWay, Converter={local:BoolInverter}}">
<TextBlock Text="Click here for popup!"/>
</ToggleButton>
<Popup IsOpen="{Binding IsChecked, ElementName=Btn}" x:Name="Popup" StaysOpen="False">
<Border BorderBrush="Black" BorderThickness="1" Background="LightYellow">
<CheckBox Content="This is a popup"/>
</Border>
</Popup>
"BoolInverter"는 IsHitTestVisible 바인딩에서 사용되므로 ToggleButton을 다시 클릭하면 팝업이 닫힙니다.
public class BoolInverter : MarkupExtension, IValueConverter
{
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool)
return !(bool)value;
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Convert(value, targetType, parameter, culture);
}
}
... IValueConverter와 MarkupExtension 을 하나로 결합 하는 편리한 기술을 보여줍니다 .
이 기술에서 한 가지 문제를 발견했습니다. 두 개의 팝업이 동시에 화면에 표시 될 때 WPF가 버그가 있습니다. 특히, 토글 버튼이 툴바의 "오버플로 팝업"에있는 경우 클릭하면 두 개의 팝업이 열립니다. 그러면 창에서 다른 곳을 클릭해도 두 번째 팝업 (팝업)이 계속 열려있는 것을 알 수 있습니다. 이 시점에서 팝업을 닫는 것은 어렵습니다. 팝업이 열려 있기 때문에 IsHitTestVisible이 false이므로 사용자는 ToggleButton을 다시 클릭하여 팝업을 닫을 수 없습니다! 내 앱에서는이 문제를 완화하기 위해 몇 가지 해킹을 사용해야했습니다. 예를 들어 메인 창에서 다음과 같은 테스트를 수행해야했습니다.이 테스트는 (Louis Black의 목소리로) "팝업이 열려 있고 사용자가 팝업 외부 어딘가를 클릭하면 friggin '팝업을 닫습니다. ":
PreviewMouseDown += (s, e) =>
{
if (Popup.IsOpen)
{
Point p = e.GetPosition(Popup.Child);
if (!IsInRange(p.X, 0, ((FrameworkElement)Popup.Child).ActualWidth) ||
!IsInRange(p.Y, 0, ((FrameworkElement)Popup.Child).ActualHeight))
Popup.IsOpen = false;
}
};
// Elsewhere...
public static bool IsInRange(int num, int lo, int hi) =>
num >= lo && num <= hi;
어때 :
<Button x:Name="OpenPopup">Popup
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames
Storyboard.TargetName="ContextPopup"
Storyboard.TargetProperty="IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
</Button>
<Popup x:Name="ContextPopup"
PlacementTarget="{Binding ElementName=OpenPopup}"
StaysOpen="False">
<Label>Popupcontent...</Label>
</Popup>
Please note that the Popup
is referecing the Button
by name and vice versa. So x:Name="..."
is required on both, the Popup
and the Button
.
It can actually be further simplified by replacing the Storyboard
stuff with a custom SetProperty
EventTrigger Action described in this SO Answer
I had some issues with the MouseDown part of this, but here is some code that might get your started.
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<Control VerticalAlignment="Top">
<Control.Template>
<ControlTemplate>
<StackPanel>
<TextBox x:Name="MyText"></TextBox>
<Popup x:Name="Popup" PopupAnimation="Fade" VerticalAlignment="Top">
<Border Background="Red">
<TextBlock>Test Popup Content</TextBlock>
</Border>
</Popup>
</StackPanel>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="UIElement.MouseEnter" SourceName="MyText">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="Popup" Storyboard.TargetProperty="(Popup.IsOpen)">
<DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="True"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="UIElement.MouseLeave" SourceName="MyText">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="Popup" Storyboard.TargetProperty="(Popup.IsOpen)">
<DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="False"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Control.Template>
</Control>
</Grid>
</Window>
another way to do it:
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<StackPanel>
<Image Source="{Binding ProductImage,RelativeSource={RelativeSource TemplatedParent}}" Stretch="Fill" Width="65" Height="85"/>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
<Button x:Name="myButton" Width="40" Height="10">
<Popup Width="100" Height="70" IsOpen="{Binding ElementName=myButton,Path=IsMouseOver, Mode=OneWay}">
<StackPanel Background="Yellow">
<ItemsControl ItemsSource="{Binding Produkt.SubProducts}"/>
</StackPanel>
</Popup>
</Button>
</StackPanel>
</Border>
'IT Share you' 카테고리의 다른 글
Ruby on Rails 양식의 HTML5 '필수'유효성 검사 (0) | 2020.12.06 |
---|---|
jQuery를 사용하여 클래스 변경시 이벤트를 발생시키는 방법은 무엇입니까? (0) | 2020.12.06 |
자바의 함수형 프로그래밍 (0) | 2020.12.06 |
Unity를 사용하여 개발하는 데 사용되는 언어 (0) | 2020.12.06 |
iOS에서 간단한 체크 박스를 만드는 방법은 무엇입니까? (0) | 2020.12.06 |