views:

13013

answers:

3

I've got two controls, a TextBlock and a PopUp. When the user clicks (MouseDown) on the textblock, I want to display the popup. I would think that I could do this with an EventTrigger on the Popup, but I can't use setters in an EventTrigger, I can only start storyboards. I want to do this strictly in XAML, because the two controls are in a template and I don't know how I'd find the popup in code.

This is what conceptually I want to do, but can't because you can't put a setter in an EventTrigger (like you can with a 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>
...

What is the best way to show a popup strictly in XAML when an event happens on a different control?

+3  A: 

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>
bendewey
A: 

I had to work around the problem and reuse a single popup that was reference by all of my items. Its pretty much impossible to do this kind of stuff without some codebehind, which is what I was trying to avoid.

I tried going down the route you suggested, but I needed the popup to stay open after I MouseDown on it so the user could interact with controls on the popup. I tried leaving off the storyboard that would set the value back to false, but since the storyboard that opened the popup takes precedence over setting the property explicity in code, you can never "close" the popup until you kill the storyboard.

I wish that the FillBehavior had an additional enumeration called something like "SetPropertiesAndKillAnimation", so after the animation was finished it would explicitly set the properties to their last value in the animation. I know there is the Completed event, but if the storyboard is operating on a control within a template, you can't get access to the object in code because animations use Storyboard.TargetName instead of a binding to the control you want to modify.

viggity
+10  A: 

I did something simple, but it works.

I used a typical ToggleButton, which I restyled as a textblock by changing its control template. Then I just bind the IsChecked property on the ToggleButton to the IsOpen property on the popup. Popup has some properties like StaysOpen (I think) that let you modify the closing behavior.

The following works in 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}">
    <Border Background="LightYellow">
      <TextBlock> I'M the popup </TextBlock>
    </Border>
  </Popup>

John Melville
interesting approach
viggity