2008-12-11 32 views
54

我有兩個控件,一個TextBlock和一個PopUp。當用戶單擊文本塊上的(MouseDown)時,我想顯示彈出窗口。我認爲我可以用PopUp上的EventTrigger來做到這一點,但是我不能在EventTrigger中使用setter,我只能啓動storyboard。我想在XAML中嚴格執行此操作,因爲這兩個控件都在模板中,我不知道如何在代碼中找到彈出窗口。如何在僅使用XAML標記單擊另一個控件時打開WPF彈出窗口?

這是我想做什麼概念,但不能因爲你不能把一個設置在一個EventTrigger(比如你可以用一個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中顯示一個彈出窗口?

回答

77

我做了一些簡單的事,但它的工作原理。

我使用了一個典型的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> 
+0

有趣的方法 – viggity 2009-06-04 15:50:34

+4

也看到@ Qwertie的做法取代了Storyboard東西可以進一步簡化 - 受此啓發更有用的版本,它會自動您何時關閉彈出alt-tab或在彈出框外點擊 – 2012-01-30 02:16:19

8

我對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> 
48

下面的方法是一樣的赫爾格·克萊因的,只是彈出自動關閉,當您單擊彈出(包括切換按鈕本身)以外的任何地方:

<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綁定,這樣當你再次點擊切換按鈕,在彈出的關閉:

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

...其中一個顯示combining IValueConverter and MarkupExtension的方便的技術。

我確實發現了這種技術的一個問題:當兩個彈出窗口同時在屏幕上時,WPF會出現問題。具體來說,如果您的切換按鈕位於工具欄中的「溢出彈出窗口」中,那麼在您單擊它後會打開兩個彈出窗口。然後,您可能會發現,當您點擊窗口的其他任何位置時,第二個彈出窗口(您的彈出窗口)將保持打開狀態。那時,關閉彈出窗口很困難。用戶不能再次單擊ToggleButton來關閉彈出窗口,因爲IsHitTestVisible爲false,因爲彈出窗口已打開!在我的應用程序中,我不得不使用一些黑客來緩解這個問題,比如在主窗口中進行了以下測試,該測試說(在Louis Black的聲音中)「如果彈出窗口是打開的,並且用戶在彈出窗口外點擊某處,關閉受詛咒的彈出「。

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

另一種方式來做到這一點:

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

如何:

<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是referecing的Button按名稱,反之亦然。所以在PopupButton都需要x:Name="..."

實際上,它可以通過自定義SetProperty EventTrigger行動描述in this SO Answer

相關問題