source

XAML 마크업만 사용하여 다른 컨트롤을 클릭했을 때 WPF 팝업을 열려면 어떻게 해야 합니까?

ittop 2023. 4. 17. 22:26
반응형

XAML 마크업만 사용하여 다른 컨트롤을 클릭했을 때 WPF 팝업을 열려면 어떻게 해야 합니까?

두 가지 컨트롤이 있습니다. TextBlock과 PopUp입니다.사용자가 텍스트 블록에서 (마우스 다운)을 클릭하면 팝업이 표시됩니다.팝업에서 EventTrigger로 할 수 있다고 생각하지만 EventTrigger에서는 세터를 사용할 수 없고 스토리보드만 시작할 수 있습니다.2개의 컨트롤이 템플릿에 있고 코드에서 팝업이 어떻게 표시되는지 모르기 때문에 XAML에서는 엄밀하게 하고 싶습니다.

개념적으로 다음과 같은 작업을 수행하려고 하는데, DataTrigger에서처럼 EventTrigger에 세터를 넣을 수 없기 때문에 수행할 수 없습니다.

<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에서 팝업을 엄격하게 표시하는 가장 좋은 방법은 무엇입니까?

간단한 걸 했는데 효과가 있어요.

일반적인 Toggle Button을 사용했는데 컨트롤 템플릿을 변경하여 텍스트 블록으로 다시 스타일링했습니다.그런 다음 ToggleButton의 IsChecked 속성을 팝업의 IsOpen 속성에 바인딩했습니다.팝업에는 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>

팝업 이외의 임의의 장소(Toggle Button 자체 포함)를 클릭하면 팝업이 자동으로 닫히는 것을 제외하고 다음 접근법은 Helge Klein과 동일합니다.

<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);
    }
}

IValue Converter와 Markup Extension을 하나로 결합하는 편리한 기술을 보여줍니다.

이 기술에서 한 가지 문제를 발견했습니다. WPF는 두 개의 팝업이 동시에 화면에 뜨면 버그가 발생합니다.특히 툴바의 "오버플로우 팝업"에 토글버튼이 있는 경우 클릭하면 두 개의 팝업이 열립니다.그런 다음 창의 다른 위치를 클릭하면 두 번째 팝업(팝업)이 열린 상태로 유지될 수 있습니다.이 시점에서 팝업을 닫는 것은 어렵습니다.팝업이 열려 있기 때문에 IsHitTestVisible이 false이기 때문에 사용자가 다시 ToggleButton을 클릭하여 팝업을 닫을 수 없습니다.내 앱에서 나는 이 문제를 완화하기 위해 몇 가지 해크를 사용해야 했다. 예를 들어 (루이스 블랙의 목소리로) "팝업이 열려 있고 사용자가 팝업 밖의 어딘가를 클릭하면, 빌어먹을 팝업을 닫아라.":

PreviewMouseDown += (s, e) =>
{
    // Workaround for popup not closing automatically when 
    // two popups are on-screen at once.
    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;

은 '먹다'를 사용해요.EventTrigger Popup은 우리가 뜻입니다.ToggleButton이치노에서는, 「」를 해 주세요.Click의 of의 Button 하다. 조합해서 할 수 .다른 요소/이벤트 조합을 사용하도록 조정할 수 있습니다.

<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>

★★★★★★★★★에 주의해 주세요.Popup라고 하는 것은, 을 하고 있습니다.Button이름을 붙이고 그 반대도 마찬가지입니다. ★★★★★★★★★★★★★★★★★.x:Name="..."다 입니다.PopupButton.

더 할 수 .Storyboard으로 SetPropertySO 답변에서 설명하는 EventTrigger 액션

마우스 다운 부분에 문제가 있었습니다만, 여기 몇 가지 코드가 있습니다.

<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>

다른 방법:

<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>

언급URL : https://stackoverflow.com/questions/361209/how-to-open-a-wpf-popup-when-another-control-is-clicked-using-xaml-markup-only

반응형