如何在单击另一个控件时仅使用XAML标记打开WPFpopup窗口?
我有两个控件,一个TextBlock和一个PopUp。 当用户单击文本块上的(MouseDown)时,我想显示popup窗口。 我认为我可以用PopUp上的EventTrigger做到这一点,但是我不能在EventTrigger中使用setter,我只能启动storyboard。 我想在XAML中严格执行此操作,因为两个控件都在模板中,我不知道如何在代码中findpopup式窗口。
这就是我想要做的概念,但是不能,因为你不能在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中显示popup窗口的最佳方式是什么?
我做了一些简单的事,但它的工作。
我使用了一个典型的ToggleButton,通过改变它的控制模板,我将其重新设置为一个文本块。 然后,我只是将ToggleButton上的IsChecked属性绑定到popup窗口上的IsOpen属性。 Popup有一些属性,如StaysOpen,可以让你修改closures行为。
以下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相同,不同之处在于当你popupPopup(包括ToggleButton本身)之外的任何地方时,popup窗口会自动closures:
<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>
在“IsHitTestVisible”绑定中使用“BoolInverter”,以便当再次单击ToggleButton时,popup窗口closures:
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结合在一起的方便的技术。
我发现这个技术有一个问题:当两个popup窗口同时在屏幕上时,WPF是有问题的。 具体而言,如果您的切换button位于工具栏中的“溢出popup式窗口”中,则单击它后将popup两个popup窗口。 您可能会发现,当您点击窗口的其他任何位置时,第二个popup窗口(您的popup窗口)将保持打开状态。 此时,closurespopup窗口很困难。 用户不能再次单击ToggleButton来closurespopup框,因为IsHitTestVisible为false,因为popup窗口是打开的! 在我的应用程序中,我不得不使用一些黑客来缓解这个问题,比如在主窗口中的下面的testing(在路易斯·布莱克的声音中)“如果popup窗口是打开的,用户点击popup窗口外的某个地方,closuresfriggin'popup。“:
PreviewMouseDown += (s, e) => { if (Popup.IsOpen) { Point p = e.GetPosition(Popup.Child); if (!IsInRange(pX, 0, ((FrameworkElement)Popup.Child).ActualWidth) || !IsInRange(pY, 0, ((FrameworkElement)Popup.Child).ActualHeight)) Popup.IsOpen = false; } };
我在这个MouseDown部分有一些问题,但是这里有一些代码可能会让你开始。
<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>
怎么样:
<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="..."
在Popup
和Button
都是必需的。
它实际上可以进一步简化,用这个答案中描述的一个自定义的SetProperty
EventTrigger ActionreplaceStoryboard
东西
另一种方式来做到这一点:
<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>